{"version":3,"file":"js/app_javascript_components_sync_recursive_.js","mappings":"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A;AACA;AACA;AACA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AAFA;AAAA;AAAA;AAKA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AAAA;AAAA;AAAA;AAIA;AACA;;AAGA;AACA;AACA;AAFA;AAAA;AAAA;AAKA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;;AAGA;AACA;AACA;AAFA;AAAA;AAAA;AAKA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAKA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAIA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AA7NA;AAgOA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxOA;AACA;AAEA;AAAA;AAIA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAHA;AAAA;AAAA;AAMA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AAGA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAIA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AApHA;AAuHA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/HA;AACA;AAEA;AAAA;AAIA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAGA;AAEA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAMA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAjFA;AAoFA;AACA;AACA;AACA","sources":["webpack:///./app/javascript/components/ sync ^\\.\\/.*$","webpack:///./app/javascript/components/BlockRemove.js","webpack:///./app/javascript/components/CircuitBlock.js","webpack:///./app/javascript/components/CodeBlock.js","webpack:///./app/javascript/components/ContentBlock.js","webpack:///./app/javascript/components/ContentBlockList.js","webpack:///./app/javascript/components/HelloWorld.js","webpack:///./app/javascript/components/MathBlock.js","webpack:///./app/javascript/components/ParagraphBlock.js","webpack:///./app/javascript/components/PhotoBlock.js","webpack:///./app/javascript/components/VideoBlock.js"],"sourcesContent":["var map = {\n\t\"./BlockRemove\": \"./app/javascript/components/BlockRemove.js\",\n\t\"./BlockRemove.js\": \"./app/javascript/components/BlockRemove.js\",\n\t\"./CircuitBlock\": \"./app/javascript/components/CircuitBlock.js\",\n\t\"./CircuitBlock.js\": \"./app/javascript/components/CircuitBlock.js\",\n\t\"./CodeBlock\": \"./app/javascript/components/CodeBlock.js\",\n\t\"./CodeBlock.js\": \"./app/javascript/components/CodeBlock.js\",\n\t\"./ContentBlock\": \"./app/javascript/components/ContentBlock.js\",\n\t\"./ContentBlock.js\": \"./app/javascript/components/ContentBlock.js\",\n\t\"./ContentBlockList\": \"./app/javascript/components/ContentBlockList.js\",\n\t\"./ContentBlockList.js\": \"./app/javascript/components/ContentBlockList.js\",\n\t\"./HelloWorld\": \"./app/javascript/components/HelloWorld.js\",\n\t\"./HelloWorld.js\": \"./app/javascript/components/HelloWorld.js\",\n\t\"./MathBlock\": \"./app/javascript/components/MathBlock.js\",\n\t\"./MathBlock.js\": \"./app/javascript/components/MathBlock.js\",\n\t\"./ParagraphBlock\": \"./app/javascript/components/ParagraphBlock.js\",\n\t\"./ParagraphBlock.js\": \"./app/javascript/components/ParagraphBlock.js\",\n\t\"./PhotoBlock\": \"./app/javascript/components/PhotoBlock.js\",\n\t\"./PhotoBlock.js\": \"./app/javascript/components/PhotoBlock.js\",\n\t\"./VideoBlock\": \"./app/javascript/components/VideoBlock.js\",\n\t\"./VideoBlock.js\": \"./app/javascript/components/VideoBlock.js\"\n};\n\n\nfunction webpackContext(req) {\n\tvar id = webpackContextResolve(req);\n\treturn __webpack_require__(id);\n}\nfunction webpackContextResolve(req) {\n\tif(!__webpack_require__.o(map, req)) {\n\t\tvar e = new Error(\"Cannot find module '\" + req + \"'\");\n\t\te.code = 'MODULE_NOT_FOUND';\n\t\tthrow e;\n\t}\n\treturn map[req];\n}\nwebpackContext.keys = function webpackContextKeys() {\n\treturn Object.keys(map);\n};\nwebpackContext.resolve = webpackContextResolve;\nmodule.exports = webpackContext;\nwebpackContext.id = \"./app/javascript/components sync recursive ^\\\\.\\\\/.*$\";","import React from \"react\"\nimport PropTypes from \"prop-types\"\n\nexport default class BlockRemove extends React.Component {\n\n render () {\n const className = this.props.class + \" block-remove\";\n return (\n x\n );\n }\n}\n\nBlockRemove.propTypes = {\n class: PropTypes.string,\n clickHandler: PropTypes.func,\n}\n","import React from \"react\"\nimport PropTypes from \"prop-types\"\n\nimport BlockRemove from \"./BlockRemove\"\n\nexport default class CircuitBlock extends React.Component {\n\n constructor (props) {\n super(props);\n\n this.state = {\n published: this.props.published || false,\n circuit: \"\",\n label: \"\",\n }\n\n if(typeof this.props.circuit == \"string\" && this.props.circuit.length > 0) {\n this.state.circuit = this.props.circuit;\n }\n\n }\n\n componentDidMount () {\n\n var circuit_json = {\"width\": 600, \"height\": 200};\n var element = $(\"#circuit-simcir_\" + this.props.order);\n\n if (this.state.circuit) {\n circuit_json = JSON.parse(this.state.circuit);\n }\n\n /* Initialize circuits js library */\n simcir.setupSimcir(element, circuit_json);\n\n this.setState({\n element: element,\n circuit: JSON.stringify(circuit_json)\n })\n }\n\n storeCircuit(event) {\n var data = simcir.controller(\n this.state.element.find('.simcir-workspace')\n ).text();\n\n this.setState({circuit: data});\n\n event.stopPropagation();\n event.preventDefault();\n }\n\n onInputChange (event) {\n\n this.setState({\n circuit: event.target.value\n })\n }\n\n updateCircuit (event) {\n /* Update circuit on SimCir */\n simcir.setupSimcir(this.state.element, JSON.parse(this.state.circuit));\n }\n\n render () {\n const circuit = (\n
\n
\n
\n
\n )\n\n const form = (\n

\n

\n \n \n
\n
\n \n \n
\n

\n )\n\n if (this.state.published) {\n return circuit;\n } else {\n return form;\n }\n }\n}\n\nCircuitBlock.propTypes = {\n published: PropTypes.bool,\n circuit: PropTypes.string,\n}\n","import React from \"react\"\nimport PropTypes from \"prop-types\"\nimport ReactDOM from \"react-dom\"\nimport { createRef } from \"react\"\n\nimport BlockRemove from \"./BlockRemove\"\n\nexport default class CodeBlock extends React.Component {\n\n blockRef = createRef(null);\n\n constructor (props) {\n super(props);\n this.state = {\n published: this.props.published || false,\n value: \"\"\n }\n\n this.TAB = 9;\n\n if (typeof this.props.code == \"string\" && this.props.code.length > 0) {\n\n this.state.value = this.props.code;\n }\n }\n\n indent (event) {\n\n const key = event.keyCode;\n\n if(key == this.TAB) {\n\n const value = event.target.value;\n const start = value.substring(0, event.target.selectionStart);\n const end = value.substring(event.target.selectionEnd);\n\n this.setState({value: start + \" \" + end});\n event.target.selectionStart = start + 4;\n event.preventDefault();\n }\n }\n\n change (event) {\n this.setState({value: event.target.value});\n }\n\n pageLoadCallback (event) {\n\n // Highlights current code block\n hljs.highlightBlock(this.blockRef.current);\n }\n\n /**\n * Highlights the code after the component has been mounted\n */\n componentDidMount () {\n\n window.addEventListener('load', this.pageLoadCallback.bind(this));\n window.addEventListener('turbolinks:load', this.pageLoadCallback.bind(this));\n }\n\n render () {\n\n const form = (\n

\n \n \n \n

\n );\n\n const source = (\n
\n        \n          {this.state.value}\n        \n      
\n );\n\n if(this.state.published) {\n return source;\n } else {\n return form;\n }\n }\n}\n\nCodeBlock.propTypes = {\n code: PropTypes.string,\n};\n","import React from \"react\"\nimport PropTypes from \"prop-types\"\n\nimport ParagraphBlock from \"./ParagraphBlock\"\nimport CodeBlock from \"./CodeBlock\"\nimport PhotoBlock from \"./PhotoBlock\"\nimport VideoBlock from \"./VideoBlock\"\nimport CircuitBlock from \"./CircuitBlock\"\nimport MathBlock from \"./MathBlock\"\nimport ContentBlockList from \"./ContentBlockList\"\nimport BlockRemove from \"./BlockRemove\"\n\n\nexport default class ContentBlock extends React.Component {\n\n constructor (props) {\n\n super(props);\n\n this.state = {\n components: [],\n published: this.props.published || false,\n nextOrder: 0, // Initialize blocks order on form\n };\n\n this.handleClick = this.handleClick.bind(this);\n\n if(this.props.contentBlocks &&\n Object.keys(this.props.contentBlocks).length > 0) {\n this.createComponents();\n }\n }\n\n createComponents () {\n\n const objectKeys = Object.keys(this.props.contentBlocks);\n for (let i=0; i < objectKeys.length; i++) {\n\n const block = this.props.contentBlocks[ objectKeys[i] ];\n const key = Object.keys(block)[0];\n this.addBlock(key, i, block[key]);\n }\n }\n\n addBlock(blockType, index, value) {\n\n let component = undefined;\n switch (blockType) {\n case \"video\":\n component = ;\n break;\n case \"photo\":\n component = ;\n break;\n case \"paragraph\":\n component = ;\n break;\n case \"code\":\n component = ;\n break;\n case \"math\":\n component = ;\n break;\n case \"circuit\":\n component = ;\n break;\n default:\n console.log(\"Unknown block type\");\n }\n\n this.state.components.push(component);\n this.state.nextOrder++;\n }\n\n deleteBlock (index) {\n this.state.components.pop(index);\n this.forceUpdate();\n }\n\n handleClick (event) {\n\n event.preventDefault();\n event.stopPropagation();\n\n const blockType = event.currentTarget.className;\n const nBlocks = this.state.components.length;\n\n this.addBlock(blockType, nBlocks);\n this.setState({});\n }\n\n render () {\n\n const listBlocks = (\n
\n
    \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
\n
\n );\n\n return (\n
\n \n {this.state.published ? null : listBlocks}\n
\n );\n }\n}\n\nContentBlock.propTypes = {\n contentBlocks: PropTypes.object,\n published: PropTypes.bool,\n}\n","import React from \"react\"\nimport PropTypes from \"prop-types\"\n\nimport BlockRemove from \"./BlockRemove\"\n\nexport default class ContentBlockList extends React.Component {\n\n render () {\n\n return (\n
\n {this.props.blocks.map(function (component) {\n return component\n })}\n
\n );\n }\n};\n\nContentBlockList.propTypes = {\n blocks: PropTypes.array,\n}\n","import React from \"react\"\nimport PropTypes from \"prop-types\"\n\nimport BlockRemove from \"./BlockRemove\"\n\nexport default class HelloWorld extends React.Component {\n\n constructor (props) {\n super(props);\n }\n\n render () {\n return (\n \n Greeting: {this.props.greeting}\n \n )\n }\n}\n\nHelloWorld.propTypes = {\n greeting: PropTypes.string\n};\n","import React from \"react\"\nimport PropTypes from \"prop-types\"\n\nimport BlockRemove from \"./BlockRemove\"\n\nexport default class MathBlock extends React.Component {\n\n constructor (props) {\n super(props);\n this.state = {\n published: this.props.published || false,\n value: \"\\\\begin{flalign}\\n & \\\\\\\\ \\n\\\\end{flalign}\"\n }\n\n if (typeof this.props.math == \"string\" && this.props.math.length > 0) {\n\n this.state.value = this.props.math;\n }\n }\n\n genTex () {\n\n var output = document.getElementById(\"math-block-\" + this.props.order);\n output.innerHTML = '';\n\n MathJax.texReset();\n var options = MathJax.getMetricsFor(output);\n\n MathJax.tex2chtmlPromise(this.state.value, options).then(function (node) {\n\n output.appendChild(node);\n MathJax.startup.document.clear();\n MathJax.startup.document.updateDocument();\n\n }).catch(function (err) {\n\n let preElm = document.createElement('pre');\n let txtElm = document.createTextNode(err.message);\n output.appendChild(preElm).appendChild(txtElm);\n })\n }\n\n change (event) {\n this.setState({value: event.target.value});\n }\n\n click (event) {\n\n this.genTex();\n\n event.preventDefault();\n event.stopPropagation();\n }\n\n blur (event) {\n\n this.genTex();\n event.stopPropagation();\n }\n\n pageLoadCallback (event) {\n\n this.genTex();\n }\n\n componentDidMount () {\n\n window.addEventListener('load', this.pageLoadCallback.bind(this));\n window.addEventListener('turbolinks:load', this.pageLoadCallback.bind(this));\n }\n\n render () {\n const form = (\n

\n \n \n \n \n\n

\n
\n

\n );\n\n const mathContent = (\n
\n
\n );\n\n if(this.state.published) {\n return mathContent;\n } else {\n return form;\n }\n }\n}\n\nMathBlock.propTypes = {\n math: PropTypes.string,\n}\n","import React from \"react\"\nimport PropTypes from \"prop-types\"\n\nimport BlockRemove from \"./BlockRemove\"\n\nexport default class ParagraphBlock extends React.Component {\n\n constructor (props) {\n super(props);\n\n this.state = {\n published: this.props.published || false,\n ctrlPressed: false,\n anchor: false,\n value: this.props.text || \"\",\n focus: false\n }\n\n this.CTRL = 17;\n this.COMMA = 188;\n this.M = 77;\n this.currentAnchor = undefined;\n }\n\n /**\n * Set the state for CTRL key pressed\n */\n handleKeyDown (event) {\n\n const key = event.keyCode;\n\n if(key == this.CTRL) {\n this.state.ctrlPressed = true;\n }\n }\n\n /**\n * Handle B or I keys pressed. The selection start and end are also read.\n * For each key, bold or italic are used. If the key is CTRL the state is\n * updated.\n */\n handleKeyUp (event) {\n\n event.preventDefault();\n\n const key = event.keyCode;\n const selection = window.getSelection();\n const start = selection.anchorOffset;\n const end = selection.focusOffset;\n\n if(key == this.COMMA && this.state.ctrlPressed) {\n this.insertLinkInput(event);\n } else if (key == this.M && this.state.ctrlPressed) {\n this.insertTitle(event);\n }\n\n this.state.ctrlPressed = false;\n }\n\n\n /**\n * Inserts tag a after paragraph to use as link url\n */\n insertLinkInput (event) {\n\n if (window.getSelection().toString()) {\n\n this.currentAnchor = document.createElement('a');\n this.currentAnchor.target = \"_blank\";\n window.getSelection().getRangeAt(0).surroundContents(this.currentAnchor);\n\n this.setState({\n anchor: true\n });\n }\n\n event.preventDefault();\n }\n\n\n /**\n * Inserts a title using tag bold with styles\n */\n insertTitle (event) {\n\n var titleElm = document.createElement(\"h3\");\n titleElm.className = \"paragraph-title\";\n titleElm.onblur = this.closeEdition;\n titleElm.onclick = this.allowEdition;\n\n window.getSelection().getRangeAt(0).surroundContents(titleElm);\n this.updateState();\n\n event.preventDefault();\n }\n\n /**\n * Update paragraph div state\n */\n updateState () {\n\n\n const div = document.getElementById(\"div-paragraph-\" + this.props.order);\n\n this.setState({\n anchor: false,\n value: div.innerHTML,\n });\n\n div.click();\n div.focus();\n }\n\n /**\n * Sets the current anchor url based on input url\n */\n setLinkUrl (event) {\n\n const url = event.target.value;\n this.currentAnchor.href = url;\n this.currentAnchor = undefined;\n\n this.updateState();\n\n event.stopPropagation();\n }\n\n change (element) {\n\n let input = document.getElementById(\"paragraph-\" + this.props.order);\n input.value = element.innerHTML;\n }\n\n changeCallback (event) {\n\n this.change(event.target);\n }\n\n\n /**\n * Allows paragraph div edition\n */\n allowEdition (event) {\n\n const paragraphDivSelector = \"div-paragraph-\" + this.props.order;\n const paragraphDiv = document.getElementById(paragraphDivSelector);\n\n paragraphDiv.setAttribute(\"contenteditable\", true);\n\n for(var i=0; i < paragraphDiv.childNodes.length; i++) {\n\n const element = paragraphDiv.childNodes[i];\n if(element.nodeType === Node.ELEMENT_NODE) {\n element.setAttribute(\"contenteditable\", true);\n }\n }\n }\n\n\n /**\n * Closes paragraph div edition\n */\n closeEdition (event) {\n\n const paragraphDivSelector = \"div-paragraph-\" + this.props.order;\n const paragraphDiv = document.getElementById(paragraphDivSelector);\n\n paragraphDiv.removeAttribute(\"contenteditable\");\n\n for(var i=0; i < paragraphDiv.childNodes.length; i++) {\n\n const element = paragraphDiv.childNodes[i];\n if(element.nodeType === Node.ELEMENT_NODE) {\n element.removeAttribute(\"contenteditable\");\n }\n }\n\n this.change(paragraphDiv);\n }\n\n\n render () {\n\n let anchor = \"\";\n if(this.state.anchor) {\n anchor = (\n \n );\n }\n\n const form = (\n

\n \n \n \n {anchor}\n \n

\n );\n\n const paragraph = (\n

\n );\n\n if(this.state.published) {\n return paragraph;\n } else {\n return form;\n }\n }\n}\n\nParagraphBlock.propTypes = {\n published: PropTypes.bool,\n text: PropTypes.string,\n}\n\n","import React from \"react\"\nimport PropTypes from \"prop-types\"\n\nimport BlockRemove from \"./BlockRemove\"\n\nexport default class PhotoBlock extends React.Component {\n\n constructor (props) {\n super(props);\n\n this.state = {\n visible: false,\n published: this.props.published || false,\n\n file: undefined,\n imageUrl: undefined,\n imagePreviewURL: undefined,\n imageAlt: undefined,\n }\n\n if(this.props.photo) {\n\n if (this.props.photo.path && typeof this.props.photo.path == \"string\") {\n this.state.imageUrl = this.props.photo.path;\n this.state.imagePreviewURL= this.state.imageUrl;\n }\n\n if (this.props.photo.caption && typeof this.props.photo.caption == \"string\") {\n this.state.imageAlt = this.props.photo.caption;\n }\n }\n }\n\n handleFileChoose (event) {\n\n let reader = new FileReader();\n let file = event.target.files[0];\n\n reader.onloadend = () => {\n this.setState({\n file: file,\n imagePreviewURL: reader.result\n });\n }\n\n reader.readAsDataURL(file);\n }\n\n /**\n * The form is correct. Rails does not put alt tag in its class for uploading\n * files\n */\n fillImageAlt(event) {\n\n const alternate = event.target.value;\n\n this.setState({\n imageAlt: alternate\n });\n\n event.stopPropagation();\n }\n\n render () {\n\n let preview = \"\";\n if(this.state.imagePreviewURL) {\n preview = (\n

\n {this.state.imageAlt}\n
\n );\n }\n\n let formFileInput = (\n\n \n );\n\n if(this.state.imageUrl) {\n\n formFileInput = (\n \n );\n }\n\n const form = (\n

\n \n {formFileInput}\n \n {preview}\n \n

\n );\n\n const photo = (\n \n \n {this.state.imageAlt}\n \n );\n\n if(this.state.published) {\n return photo;\n } else {\n return form;\n }\n }\n}\n\nPhotoBlock.propTypes = {\n path: PropTypes.string,\n caption: PropTypes.string,\n};\n","import React from \"react\"\nimport PropTypes from \"prop-types\"\n\nimport BlockRemove from \"./BlockRemove\"\n\nexport default class VideoBlock extends React.Component {\n\n constructor (props) {\n super(props);\n\n this.state = {\n published: this.props.published || false,\n value: \"\",\n videoID: null,\n }\n\n this.youtube = {\n IMG_URL: \"https://img.youtube.com/vi/\",\n IMG_QUALITY: \"/0.jpg\",\n URL_PATTERN: /v=(\\w|-){11}/,\n ID_LENGTH: 11,\n YOUTUBE_EMBED_URL: \"https://www.youtube.com/embed/\",\n }\n\n if(typeof this.props.url == \"string\" && this.props.url.length > 0) {\n\n const videoID = this.getVideoID(this.props.url);\n\n this.state.value = this.props.url;\n this.state.videoID = videoID;\n }\n }\n\n getVideoID (url) {\n\n if(this.youtube.URL_PATTERN.test(url)) {\n return url.split(\"v=\")[1].substring(0, this.youtube.ID_LENGTH);\n }\n return null;\n }\n\n handleKeyUp (event) {\n\n const value = event.target.value;\n const videoID = this.getVideoID(value);\n this.setState({value: value, videoID: videoID});\n }\n\n render () {\n let image = \"\";\n if(this.state.videoID) {\n const videoThumbURL = this.youtube.IMG_URL + this.state.videoID + this.youtube.IMG_QUALITY;\n image = (\n
\n \n
\n );\n }\n\n const form = (\n

\n

\n \n \n \n
\n {image}\n

\n );\n\n const video = (\n
\n