diff --git a/.storybook/helpers/h5p.utils.ts b/.storybook/helpers/h5p.utils.ts index faaae03..3d1119c 100644 --- a/.storybook/helpers/h5p.utils.ts +++ b/.storybook/helpers/h5p.utils.ts @@ -45,43 +45,189 @@ export const semantics: H5PField = { fields: [ { name: "id", type: H5PFieldType.Text, widget: "hidden" }, { - name: "xPercentagePosition", - type: H5PFieldType.Number, - widget: "hidden", + label: "Start Date", + name: "startDate", + type: H5PFieldType.Text, }, { - name: "yPercentagePosition", - type: H5PFieldType.Number, - widget: "hidden", + label: "End Date", + name: "endDate", + type: H5PFieldType.Text, }, { - name: "widthPercentage", - type: H5PFieldType.Number, - widget: "hidden", + label: "Display Date", + name: "displayDate", + type: H5PFieldType.Text, }, { - name: "heightPercentage", - type: H5PFieldType.Number, - widget: "hidden", + label: "Slide Unique Id", + name: "slideUniqueId", + type: H5PFieldType.Text, + widget: "none", }, + { - label: "Label", - description: "The label is shown on top of the background image", - name: "label", - type: H5PFieldType.Text, + label: "Slide Type", + name: "slideType", + type: H5PFieldType.Select, + description: "Select how the slide for this slide will be rendered", + options: [ + { + value: "timelineJS", + label: "TimelineJS", + }, + { + value: "grid", + label: "Grid", + }, + ], + default: "grid", }, { - label: "Background image", - name: "backgroundImage", - type: H5PFieldType.Image, + label: "Timeline Slide Classic", + name: "timelineSlide", + type: H5PFieldType.Group, + widget: "showWhen", + showWhen: { + rules: [ + { + field: "slideType", + equals: "timelineJS", + }, + ], + }, + fields: [ + { + label: "Text", + description: "Text for the event", + name: "text", + type: H5PFieldType.Text, + }, + { + label: "Group", + description: + "Timeline will organize events with the same value for group to be in the same row or adjacent rows,", + name: "group", + type: H5PFieldType.Text, + }, + { + label: "Media", + description: "media", + name: "media", + type: H5PFieldType.Group, + fields: [ + { + label: "Url", + description: "Url", + name: "url", + type: H5PFieldType.Text, + }, + { + label: "Caption", + description: "Caption", + name: "caption", + type: H5PFieldType.Text, + }, + { + label: "credit", + description: "credit", + name: "credit", + type: H5PFieldType.Text, + }, + { + label: "thumbnail", + description: "thumbnail", + name: "thumbnail", + type: H5PFieldType.Text, + }, + { + label: "alt", + description: "alt", + name: "alt", + type: H5PFieldType.Text, + }, + { + label: "title", + description: "title", + name: "title", + type: H5PFieldType.Text, + }, + { + label: "link", + description: "link", + name: "link", + type: H5PFieldType.Text, + }, + { + label: "link_target", + description: "link_target", + name: "linkTarget", + type: H5PFieldType.Text, + }, + ], + }, + ], }, { - label: "Links", - name: "links", - description: - "These links are as auxiliary links for the user in the element's modal window", - type: H5PFieldType.List, - field: { label: "Link", name: "link", type: H5PFieldType.Text }, + label: "Timeline Slide Grid", + name: "timelineGridSlide", + type: H5PFieldType.Group, + widget: "showWhen", + showWhen: { + rules: [ + { + field: "slideType", + equals: "grid", + }, + ], + }, + fields: [ + { + label: "Items", + description: "items", + name: "items", + type: H5PFieldType.List, + field: { + label: "item_spec", + description: "item_spec", + name: "itemSpec", + type: H5PFieldType.Text, + }, + }, + { + label: "Label", + description: + "The label is shown on top of the background image", + name: "label", + type: H5PFieldType.Text, + }, + + { + label: "Background image", + name: "backgroundImage", + type: H5PFieldType.Image, + }, + { + name: "xPercentagePosition", + type: H5PFieldType.Number, + widget: "none", + }, + { + name: "yPercentagePosition", + type: H5PFieldType.Number, + widget: "none", + }, + { + name: "widthPercentage", + type: H5PFieldType.Number, + widget: "none", + }, + { + name: "heightPercentage", + type: H5PFieldType.Number, + widget: "none", + }, + ], }, ], }, diff --git a/H5P.d.ts b/H5P.d.ts index bac59b5..4a517d6 100644 --- a/H5P.d.ts +++ b/H5P.d.ts @@ -9,6 +9,7 @@ export interface H5PObject { export interface H5PEditorObject { H5pEditorTimeline: typeof H5PWrapper; + Timeline: typeof H5PWrapper; widgets: { timeline: typeof H5PWrapper; }; diff --git a/library.json b/library.json index 2c3e7bd..f41d334 100644 --- a/library.json +++ b/library.json @@ -1,13 +1,25 @@ { "title": "h5p-editor-timeline Editor", - "machineName": "H5PEditor.H5pEditorTimeline", - "majorVersion": 1, + "machineName": "H5PEditor.Timeline", + "majorVersion": 2, "minorVersion": 0, "patchVersion": 0, - "runnable": 1, + "runnable": 0, "preloadedJs": [ { - "path": "src/h5p-editor-timeline.js" + "path": "dist/bundle.js" + } + ], + "preloadedCss": [ + { + "path": "dist/main.css" + } + ], + "preloadedDependencies": [ + { + "machineName": "H5P.Timeline", + "majorVersion": 2, + "minorVersion": 0 } ] } diff --git a/src/App.tsx b/src/App.tsx index 604aaa4..59cf55c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,20 +1,45 @@ /* eslint-disable react/prefer-stateless-function */ import * as React from "react"; import { hot } from "react-hot-loader/root"; +import { H5PField } from "./types/h5p/H5PField"; +import { H5PForm } from "./types/h5p/H5PForm"; +import { Params } from "./types/h5p/Params"; +import { + fillInMissingParamsProperties, + getEmptyParams, +} from "./utils/H5P/form.utils"; -type Props = { - adjective: string; +type AppProps = { + setValue: (params: Params) => void; + semantics: H5PField; + initialParams: Partial | undefined; + parent: H5PForm; }; -class App extends React.Component { - render(): JSX.Element { - const { adjective } = this.props; - return ( - <> -

Hi, you're {adjective}

- - ); - } -} +const App: React.FC = ({ + setValue, + semantics, + initialParams, + parent, +}) => { + const [params, setParams] = React.useState( + initialParams + ? fillInMissingParamsProperties(initialParams) + : getEmptyParams() + ); + + return
test
; +}; + +// class App extends React.Component { +// render(): JSX.Element { +// const { adjective } = this.props; +// return ( +// <> +//

Hi, you're {adjective}

+// +// ); +// } +// } export default hot(App); diff --git a/src/components/EventItemForm/EventItemForm.tsx b/src/components/EventItemForm/EventItemForm.tsx index 98d4f31..34b3ddb 100644 --- a/src/components/EventItemForm/EventItemForm.tsx +++ b/src/components/EventItemForm/EventItemForm.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import { H5PField } from "../../types/h5p/H5PField"; import { H5PForm } from "../../types/h5p/H5PForm"; import { Params } from "../../types/h5p/Params"; -import { getTopicMapField } from "../../utils/H5P/form.utils"; +import { getEventsField } from "../../utils/H5P/form.utils"; import { SemanticsForm } from "../SemanticsForm/SemanticsForm"; import "./EventItemForm.scss"; @@ -25,7 +25,7 @@ export const EventItemForm: React.FC = ({ const [formParams, setFormParams] = React.useState(); React.useEffect(() => { - const field = getTopicMapField(semantics); + const field = getEventsField(semantics); setTopicMapField(field); setFormParams({ diff --git a/src/h5p/H5PWrapper.tsx b/src/h5p/H5PWrapper.tsx index 4bd8f99..5138d2f 100644 --- a/src/h5p/H5PWrapper.tsx +++ b/src/h5p/H5PWrapper.tsx @@ -1,24 +1,63 @@ +/* eslint-disable no-console */ import * as React from "react"; import * as ReactDOM from "react-dom"; import App from "../App"; +import { H5PField } from "../types/h5p/H5PField"; +import { H5PForm } from "../types/h5p/H5PForm"; +import { H5PSetValue } from "../types/h5p/H5PSetValue"; +import { Params } from "../types/h5p/Params"; import { H5P } from "./H5P.util"; export class H5PWrapper extends H5P.EventDispatcher { private wrapper: HTMLElement; - constructor(params: unknown, contentId: string, extras?: unknown) { + public field: H5PField; + + constructor( + parent: H5PForm, + semantics: H5PField, + params: Params, + setValue: H5PSetValue + ) { + super(); + this.wrapper = H5PWrapper.createWrapperElement(); + this.field = semantics; super(); + console.log("H5PWrapper.constructor", params); this.wrapper = H5PWrapper.createWrapperElement(); - ReactDOM.render(, this.wrapper); + ReactDOM.render( + setValue(semantics, newParams)} + semantics={semantics} + initialParams={params} + parent={parent} + />, + this.wrapper + ); } attach([containerElement]: JQuery): void { + console.log("H5PWrapper.attach", containerElement); containerElement.appendChild(this.wrapper); containerElement.classList.add("h5p-h5p-editor-timeline"); } + appendTo([containerElement]: JQuery): void { + containerElement.appendChild(this.wrapper); + containerElement.classList.add("h5p-timeline"); + } + + validate(): boolean { + return this.wrapper !== null; + } + + remove(): void { + console.log("H5PWrapper.remove", this); + } + private static createWrapperElement(): HTMLDivElement { + console.log("H5PWrapper.createWrapperElement"); return document.createElement("div"); } } diff --git a/src/index.tsx b/src/index.tsx index 085e7ba..96f31af 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,4 +3,8 @@ import { H5PWrapper } from "./h5p/H5PWrapper"; import "./styles.css"; import "./styles.scss"; -H5PEditor.H5pEditorTimeline = H5PWrapper; +// eslint-disable-next-line no-console +console.log("H5PEditor.init"); + +H5PEditor.widgets.timeline = H5PWrapper; +H5PEditor.Timeline = H5PWrapper; diff --git a/src/utils/H5P/form.utils.ts b/src/utils/H5P/form.utils.ts index e5c0f37..aeaf7cd 100644 --- a/src/utils/H5P/form.utils.ts +++ b/src/utils/H5P/form.utils.ts @@ -5,6 +5,7 @@ import { H5PFieldGroup, } from "../../types/h5p/H5PField"; import { H5PFieldType } from "../../types/h5p/H5PFieldType"; +import { Params } from "../../types/h5p/Params"; const getSubfieldByName = ( name: string, @@ -24,22 +25,42 @@ const getSubfieldByName = ( return null; }; -export const getTopicMapField = (semantics: H5PField): H5PField | null => { +export const getEventsField = (semantics: H5PField): H5PField | null => { if (!H5PEditor.findSemanticsField) { console.error("no H5PEditor.findSemanticsField, finding it manually"); return getSubfieldByName("eventItems", semantics); } - const topicMapField = H5PEditor.findSemanticsField("eventItems", semantics); + const eventsField = H5PEditor.findSemanticsField("eventItems", semantics); - if (!topicMapField) { + if (!eventsField) { throw new Error("Could not find the `eventItems` field"); } - if (Array.isArray(topicMapField)) { - console.error("`topicMapField` is an array", topicMapField); - return topicMapField[0]; + if (Array.isArray(eventsField)) { + console.error("`topicMapField` is an array", eventsField); + return eventsField[0]; } - return topicMapField; + return eventsField; +}; + +export const getEmptyParams = (): Params => { + const params: Params = { + eventItems: [], + draggableItems: [], + }; + + return params; +}; + +export const fillInMissingParamsProperties = ( + partialParams: Partial +): Params => { + const params: Params = { + ...getEmptyParams(), + ...partialParams, + }; + + return params; };