<commit_before>//
// Copyright (C) 2013 - present Instructure, Inc.
//
// This file is part of Canvas.
//
// Canvas is free software: you can redistribute it and/or modify it under
// the terms of the GNU Affero General Public License as published by the Free
// Software Foundation, version 3 of the License.
//
// Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.

import React from 'react'
import ReactDOM from 'react-dom'
import $ from 'jquery'
import 'jquery-scroll-to-visible'
import tz from '@canvas/timezone'
import _ from 'underscore'
import Backbone from '@canvas/backbone'
import template from '../../jst/WikiPage.handlebars'
import StickyHeaderMixin from '@canvas/wiki/backbone/views/StickyHeaderMixin.coffee'
import WikiPageDeleteDialog from '@canvas/wiki/backbone/views/WikiPageDeleteDialog'
import WikiPageReloadView from '@canvas/wiki/backbone/views/WikiPageReloadView'
import PublishButtonView from '@canvas/publish-button-view'
import I18n from 'i18n!pages'
import htmlEscape from 'html-escape'
import {publish} from 'jquery-tinypubsub'
import '@canvas/modules/jquery/prerequisites_lookup'
import '../../jquery/content_locks'
import DirectShareUserModal from '@canvas/direct-sharing/react/components/DirectShareUserModal'
import DirectShareCourseTray from '@canvas/direct-sharing/react/components/DirectShareCourseTray'

export default class WikiPageView extends Backbone.View {
  static initClass() {
    this.mixin(StickyHeaderMixin)

    this.prototype.template = template

    this.prototype.els = {
      '.publish-button': '$publishButton',
      '.header-bar-outer-container': '$headerBarOuterContainer',
      '.page-changed-alert': '$pageChangedAlert',
      '.al-trigger': '$gearMenu'
    }

    this.prototype.events = {
      'click .delete_page': 'deleteWikiPage',
      'click .use-as-front-page-menu-item': 'useAsFrontPage',
      'click .unset-as-front-page-menu-item': 'unsetAsFrontPage',
      'click .direct-share-send-to-menu-item': 'openSendTo',
      'click .direct-share-copy-to-menu-item': 'openCopyTo'
    }

    this.optionProperty('modules_path')
    this.optionProperty('wiki_pages_path')
    this.optionProperty('wiki_page_edit_path')
    this.optionProperty('wiki_page_history_path')
    this.optionProperty('WIKI_RIGHTS')
    this.optionProperty('PAGE_RIGHTS')
    this.optionProperty('course_id')
    this.optionProperty('course_home')
    this.optionProperty('course_title')
    this.optionProperty('display_show_all_pages')
  }

  initialize() {
    this.model.on('change', () => this.render())
    super.initialize(...arguments)
    if (!this.WIKI_RIGHTS) this.WIKI_RIGHTS = {}
    return this.PAGE_RIGHTS || (this.PAGE_RIGHTS = {})
  }

  render() {
    // detach elements to preserve data/events
    if (this.publishButtonView != null) {
      this.publishButtonView.$el.detach()
    }
    if (this.$sequenceFooter != null) {
      this.$sequenceFooter.detach()
    }

    super.render(...arguments)

    if (this.model.get('locked_for_user')) {
      const lock_info = this.model.get('lock_info')
      $('.lock_explanation').html(htmlEscape(INST.lockExplanation(lock_info, 'page')))
      if (lock_info.context_module && lock_info.context_module.id) {
        const prerequisites_lookup = `${ENV.MODULES_PATH}/${
          lock_info.context_module.id
        }/prerequisites/wiki_page_${this.model.get('page_id')}`
        $('<a id="module_prerequisites_lookup_link" style="display: none;">')
          .attr('x-canvaslms-trusted-url', prerequisites_lookup)
          .appendTo($('.lock_explanation'))
        INST.lookupPrerequisites()
      }
    }

    // attach/re-attach the publish button
    if (!this.publishButtonView) {
      this.publishButtonView = new PublishButtonView({model: this.model})
      this.model.view = this
    }
    this.publishButtonView.$el.appendTo(this.$publishButton)
    this.publishButtonView.render()

    // Attach the immersive reader button if enabled
    const immersive_reader_mount_point = document.getElementById('immersive_reader_mount_point')
    const immersive_reader_mobile_mount_point = document.getElementById(
      'immersive_reader_mobile_mount_point'
    )
    if (immersive_reader_mount_point || immersive_reader_mobile_mount_point) {
      import('@canvas/immersive-reader/ImmersiveReader')
        .then(ImmersiveReader => {
          const content = () => document.querySelector('.show-content').innerHTML
          const title = document.querySelector('.page-title').textContent

          if (immersive_reader_mount_point) {
            ImmersiveReader.initializeReaderButton(immersive_reader_mount_point, {content, title})
          }

          if (immersive_reader_mobile_mount_point) {
            ImmersiveReader.initializeReaderButton(immersive_reader_mobile_mount_point, {
              content,
              title
            })
          }
        })
        .catch(e => {
          console.log('Error loading immersive readers.', e) // eslint-disable-line no-console
        })
    }

    // Adds class if a LTI iframe is embed in content
    const ltisEmbedded = $('.show-content iframe.lti-embed')
    if (ltisEmbedded.length > 0) {
      $('.show-content').addClass('lti-content')
      ltisEmbedded.each(function () {
        $(this).closest('p').addClass('lti-embed-container')
      })
    }

    // attach/re-attach the sequence footer (if this is a course, but not the home page)
    if (!this.$sequenceFooter && !this.course_home && !!this.course_id) {
      if (!this.$sequenceFooter) this.$sequenceFooter = $('<div></div>').hide()
      this.$sequenceFooter.moduleSequenceFooter({<commit_msg>Fix linking to an element of different wiki page<commit_after>//
// Copyright (C) 2013 - present Instructure, Inc.
//
// This file is part of Canvas.
//
// Canvas is free software: you can redistribute it and/or modify it under
// the terms of the GNU Affero General Public License as published by the Free
// Software Foundation, version 3 of the License.
//
// Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.

import React from 'react'
import ReactDOM from 'react-dom'
import $ from 'jquery'
import 'jquery-scroll-to-visible'
import tz from '@canvas/timezone'
import _ from 'underscore'
import Backbone from '@canvas/backbone'
import template from '../../jst/WikiPage.handlebars'
import StickyHeaderMixin from '@canvas/wiki/backbone/views/StickyHeaderMixin.coffee'
import WikiPageDeleteDialog from '@canvas/wiki/backbone/views/WikiPageDeleteDialog'
import WikiPageReloadView from '@canvas/wiki/backbone/views/WikiPageReloadView'
import PublishButtonView from '@canvas/publish-button-view'
import I18n from 'i18n!pages'
import htmlEscape from 'html-escape'
import {publish} from 'jquery-tinypubsub'
import '@canvas/modules/jquery/prerequisites_lookup'
import '../../jquery/content_locks'
import DirectShareUserModal from '@canvas/direct-sharing/react/components/DirectShareUserModal'
import DirectShareCourseTray from '@canvas/direct-sharing/react/components/DirectShareCourseTray'

export default class WikiPageView extends Backbone.View {
  static initClass() {
    this.mixin(StickyHeaderMixin)

    this.prototype.template = template

    this.prototype.els = {
      '.publish-button': '$publishButton',
      '.header-bar-outer-container': '$headerBarOuterContainer',
      '.page-changed-alert': '$pageChangedAlert',
      '.al-trigger': '$gearMenu'
    }

    this.prototype.events = {
      'click .delete_page': 'deleteWikiPage',
      'click .use-as-front-page-menu-item': 'useAsFrontPage',
      'click .unset-as-front-page-menu-item': 'unsetAsFrontPage',
      'click .direct-share-send-to-menu-item': 'openSendTo',
      'click .direct-share-copy-to-menu-item': 'openCopyTo'
    }

    this.optionProperty('modules_path')
    this.optionProperty('wiki_pages_path')
    this.optionProperty('wiki_page_edit_path')
    this.optionProperty('wiki_page_history_path')
    this.optionProperty('WIKI_RIGHTS')
    this.optionProperty('PAGE_RIGHTS')
    this.optionProperty('course_id')
    this.optionProperty('course_home')
    this.optionProperty('course_title')
    this.optionProperty('display_show_all_pages')
  }

  initialize() {
    this.model.on('change', () => this.render())
    super.initialize(...arguments)
    if (!this.WIKI_RIGHTS) this.WIKI_RIGHTS = {}
    return this.PAGE_RIGHTS || (this.PAGE_RIGHTS = {})
  }

  render() {
    // detach elements to preserve data/events
    if (this.publishButtonView != null) {
      this.publishButtonView.$el.detach()
    }
    if (this.$sequenceFooter != null) {
      this.$sequenceFooter.detach()
    }

    super.render(...arguments)

    if (this.model.get('locked_for_user')) {
      const lock_info = this.model.get('lock_info')
      $('.lock_explanation').html(htmlEscape(INST.lockExplanation(lock_info, 'page')))
      if (lock_info.context_module && lock_info.context_module.id) {
        const prerequisites_lookup = `${ENV.MODULES_PATH}/${
          lock_info.context_module.id
        }/prerequisites/wiki_page_${this.model.get('page_id')}`
        $('<a id="module_prerequisites_lookup_link" style="display: none;">')
          .attr('x-canvaslms-trusted-url', prerequisites_lookup)
          .appendTo($('.lock_explanation'))
        INST.lookupPrerequisites()
      }
    }

    // attach/re-attach the publish button
    if (!this.publishButtonView) {
      this.publishButtonView = new PublishButtonView({model: this.model})
      this.model.view = this
    }
    this.publishButtonView.$el.appendTo(this.$publishButton)
    this.publishButtonView.render()

    // Attach the immersive reader button if enabled
    const immersive_reader_mount_point = document.getElementById('immersive_reader_mount_point')
    const immersive_reader_mobile_mount_point = document.getElementById(
      'immersive_reader_mobile_mount_point'
    )
    if (immersive_reader_mount_point || immersive_reader_mobile_mount_point) {
      import('@canvas/immersive-reader/ImmersiveReader')
        .then(ImmersiveReader => {
          const content = () => document.querySelector('.show-content').innerHTML
          const title = document.querySelector('.page-title').textContent

          if (immersive_reader_mount_point) {
            ImmersiveReader.initializeReaderButton(immersive_reader_mount_point, {content, title})
          }

          if (immersive_reader_mobile_mount_point) {
            ImmersiveReader.initializeReaderButton(immersive_reader_mobile_mount_point, {
              content,
              title
            })
          }
        })
        .catch(e => {
          console.log('Error loading immersive readers.', e) // eslint-disable-line no-console
        })
    }

    // Fixes issue when using anchors IDs scroll. Sometimes the browsers can't find the element
    // due it is not loaded yet.
    if (window.location?.hash !== '') {
      window.location.href = window.location.hash
    }

    // Adds class if a LTI iframe is embed in content
    const ltisEmbedded = $('.show-content iframe.lti-embed')
    if (ltisEmbedded.length > 0) {
      $('.show-content').addClass('lti-content')
      ltisEmbedded.each(function () {
        $(this).closest('p').addClass('lti-embed-container')
      })
    }

    // attach/re-attach the sequence footer (if this is a course, but not the home page)
    if (!this.$sequenceFooter && !this.course_home && !!this.course_id) {
      if (!this.$sequenceFooter) this.$sequenceFooter = $('<div></div>').hide()
      this.$sequenceFooter.moduleSequenceFooter({
{'fraction_non_alphanumeric': 0.12351543942992874, 'fraction_numerical': 0.0016381358014579408, 'mean_word_length': 3.500552893475857, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6958028', 'n_tokens_mistral': 3702, 'n_tokens_neox': 3586, 'n_words': 765}