packages/chrome-extension/src/app/components/single/singleEditorEdit.tsx (105 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import * as React from "react"; import { useCallback, useEffect } from "react"; import * as ReactDOM from "react-dom"; import { createAndGetMainContainer, extractOpenFileExtension, extractOpenFilePath, iframeFullscreenContainer, removeAllChildren, runScriptOnPage, waitForElementToBeReady, } from "../../utils"; import { SingleEditorApp } from "./SingleEditorApp"; import { Globals, Main } from "../common/Main"; import { Dependencies } from "../../Dependencies"; import { KOGITO_IFRAME_CONTAINER_CLASS, KOGITO_TOOLBAR_CONTAINER_CLASS } from "../../constants"; import { useGlobals } from "../common/GlobalContext"; import { FileInfo } from "./singleEditorView"; export async function renderSingleEditorApp(args: Globals & { fileInfo: FileInfo }) { // wait for the dom element to be ready before rendering. await waitForElementToBeReady(".cm-content"); // Checking whether this text editor exists is a good way to determine if the page is "ready", // because that would mean that the user could see the default GitHub page. if (!args.dependencies.singleEdit.githubTextEditorToReplaceElement()) { args.logger.log(`Doesn't look like the GitHub page is ready yet.`); return; } const openFileExtension = extractOpenFileExtension(window.location.href); const openFilePath = extractOpenFilePath(window.location.href); if (!openFileExtension) { args.logger.log(`Unable to determine file extension from URL.`); return; } if (!args.editorEnvelopeLocator.hasMappingFor(openFilePath)) { args.logger.log(`No enhanced editor available for "${openFilePath}" format.`); return; } // Necessary because GitHub apparently "caches" DOM structures between changes on History. // Without this method you can observe duplicated elements when using back/forward browser buttons. cleanup(args.id, args.dependencies); ReactDOM.render( <Main id={args.id} editorEnvelopeLocator={args.editorEnvelopeLocator} dependencies={args.dependencies} logger={args.logger} githubAuthTokenCookieName={args.githubAuthTokenCookieName} extensionIconUrl={args.extensionIconUrl} resourceContentServiceFactory={args.resourceContentServiceFactory} externalEditorManager={args.externalEditorManager} customChannelApiImpl={args.customChannelApiImpl} stateControl={args.stateControl} > <SingleEditorEditApp openFileExtension={openFileExtension} fileInfo={args.fileInfo} /> </Main>, createAndGetMainContainer(args.id, args.dependencies.all.body()), () => args.logger.log("Mounted.") ); } function SingleEditorEditApp(props: { openFileExtension: string; fileInfo: FileInfo }) { const globals = useGlobals(); useEffect(() => { runScriptOnPage(chrome.runtime.getURL("scripts/set_content.js")); }, [props.fileInfo]); const getFileName = useCallback(() => { return globals.dependencies.all.edit__githubFileNameInput()!.value; }, [globals.dependencies]); const getFileContents = useCallback(() => { return Promise.resolve(globals.dependencies.all.edit__githubTextAreaWithFileContents()?.textContent ?? ""); }, [globals.dependencies]); return ( <SingleEditorApp readonly={false} openFileExtension={props.openFileExtension} getFileName={getFileName} getFileContents={getFileContents} iframeContainer={iframeContainer(globals.id, globals.dependencies)} toolbarContainer={toolbarContainer(globals.id, globals.dependencies)} githubTextEditorToReplace={globals.dependencies.singleEdit.githubTextEditorToReplaceElement()!} fileInfo={props.fileInfo} /> ); } function cleanup(id: string, dependencies: Dependencies) { removeAllChildren(iframeContainer(id, dependencies)); removeAllChildren(toolbarContainer(id, dependencies)); removeAllChildren(iframeFullscreenContainer(id, dependencies.all.body())); removeAllChildren(createAndGetMainContainer(id, dependencies.all.body())); } function toolbarContainer(id: string, dependencies: Dependencies) { const element = () => document.querySelector(`.${KOGITO_TOOLBAR_CONTAINER_CLASS}.${id}`)!; if (element) { element()?.remove(); } dependencies.singleEdit .toolbarContainerTarget()! .insertAdjacentHTML( "beforebegin", `<div style="width:100%; padding-bottom: 10px;" class="${KOGITO_TOOLBAR_CONTAINER_CLASS} ${id} edit d-flex flex-column flex-items-start flex-md-row"></div>` ); return element() as HTMLElement; } function iframeContainer(id: string, dependencies: Dependencies) { const element = () => document.querySelector(`.${KOGITO_IFRAME_CONTAINER_CLASS}.${id}`)!; if (element) { element()?.remove(); } dependencies.singleEdit .iframeContainerTarget()! .insertAdjacentHTML("afterend", `<div class="${KOGITO_IFRAME_CONTAINER_CLASS} ${id} edit"></div>`); return element() as HTMLElement; }