editor-context.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import React, {
  2. createContext,
  3. useCallback,
  4. useContext,
  5. useEffect,
  6. useMemo,
  7. } from 'react'
  8. import PropTypes from 'prop-types'
  9. import useScopeValue from './util/scope-value-hook'
  10. import useBrowserWindow from '../hooks/use-browser-window'
  11. import { useIdeContext } from './ide-context'
  12. export const EditorContext = createContext()
  13. EditorContext.Provider.propTypes = {
  14. value: PropTypes.shape({
  15. cobranding: PropTypes.shape({
  16. logoImgUrl: PropTypes.string.isRequired,
  17. brandVariationName: PropTypes.string.isRequired,
  18. brandVariationId: PropTypes.number.isRequired,
  19. brandId: PropTypes.number.isRequired,
  20. brandVariationHomeUrl: PropTypes.string.isRequired,
  21. publishGuideHtml: PropTypes.string,
  22. partner: PropTypes.string,
  23. brandedMenu: PropTypes.string,
  24. submitBtnHtml: PropTypes.string,
  25. }),
  26. hasPremiumCompile: PropTypes.bool,
  27. loading: PropTypes.bool,
  28. projectRootDocId: PropTypes.string,
  29. projectId: PropTypes.string.isRequired,
  30. projectName: PropTypes.string.isRequired,
  31. renameProject: PropTypes.func.isRequired,
  32. isProjectOwner: PropTypes.bool,
  33. isRestrictedTokenMember: PropTypes.bool,
  34. rootFolder: PropTypes.object,
  35. }),
  36. }
  37. export function EditorProvider({ children, settings }) {
  38. const ide = useIdeContext()
  39. const cobranding = useMemo(
  40. () =>
  41. window.brandVariation
  42. ? {
  43. logoImgUrl: window.brandVariation.logo_url,
  44. brandVariationName: window.brandVariation.name,
  45. brandVariationId: window.brandVariation.id,
  46. brandId: window.brandVariation.brand_id,
  47. brandVariationHomeUrl: window.brandVariation.home_url,
  48. publishGuideHtml: window.brandVariation.publish_guide_html,
  49. partner: window.brandVariation.partner,
  50. brandedMenu: window.brandVariation.branded_menu,
  51. submitBtnHtml: window.brandVariation.submit_button_html,
  52. }
  53. : undefined,
  54. []
  55. )
  56. const [loading] = useScopeValue('state.loading')
  57. const [projectRootDocId] = useScopeValue('project.rootDoc_id')
  58. const [projectName, setProjectName] = useScopeValue('project.name')
  59. const [compileGroup] = useScopeValue('project.features.compileGroup')
  60. const [rootFolder] = useScopeValue('rootFolder')
  61. const [ownerId] = useScopeValue('project.owner._id')
  62. const renameProject = useCallback(
  63. newName => {
  64. setProjectName(oldName => {
  65. if (oldName !== newName) {
  66. settings.saveProjectSettings({ name: newName }).catch(response => {
  67. setProjectName(oldName)
  68. const { data, status } = response
  69. if (status === 400) {
  70. return ide.showGenericMessageModal('Error renaming project', data)
  71. } else {
  72. return ide.showGenericMessageModal(
  73. 'Error renaming project',
  74. 'Please try again in a moment'
  75. )
  76. }
  77. })
  78. }
  79. return newName
  80. })
  81. },
  82. [settings, ide, setProjectName]
  83. )
  84. const { setTitle } = useBrowserWindow()
  85. useEffect(() => {
  86. setTitle(
  87. `${projectName ? projectName + ' - ' : ''}Online LaTeX Editor ${
  88. window.ExposedSettings.appName
  89. }`
  90. )
  91. }, [projectName, setTitle])
  92. const value = useMemo(
  93. () => ({
  94. cobranding,
  95. hasPremiumCompile: compileGroup === 'priority',
  96. loading,
  97. projectId: window.project_id,
  98. projectRootDocId,
  99. projectName: projectName || '', // initially might be empty in Angular
  100. renameProject,
  101. isProjectOwner: ownerId === window.user.id,
  102. isRestrictedTokenMember: window.isRestrictedTokenMember,
  103. rootFolder,
  104. }),
  105. [
  106. cobranding,
  107. compileGroup,
  108. loading,
  109. ownerId,
  110. projectName,
  111. projectRootDocId,
  112. renameProject,
  113. rootFolder,
  114. ]
  115. )
  116. return (
  117. <EditorContext.Provider value={value}>{children}</EditorContext.Provider>
  118. )
  119. }
  120. EditorProvider.propTypes = {
  121. children: PropTypes.any,
  122. settings: PropTypes.any.isRequired,
  123. }
  124. export function useEditorContext(propTypes) {
  125. const context = useContext(EditorContext)
  126. if (!context) {
  127. throw new Error('useEditorContext is only available inside EditorProvider')
  128. }
  129. PropTypes.checkPropTypes(propTypes, context, 'data', 'EditorContext.Provider')
  130. return context
  131. }