<commit_before>###
#    Copyright 2015-2017 ppy Pty. Ltd.
#
#    This file is part of osu!web. osu!web is distributed with the hope of
#    attracting more community contributions to the core ecosystem of osu!.
#
#    osu!web is free software: you can redistribute it and/or modify
#    it under the terms of the Affero GNU General Public License version 3
#    as published by the Free Software Foundation.
#
#    osu!web is distributed 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 osu!web.  If not, see <http://www.gnu.org/licenses/>.
###

{a, button, div, i, li, span, ul} = ReactDOMFactories
el = React.createElement

pages = document.getElementsByClassName("js-switchable-mode-page--scrollspy")
pagesOffset = document.getElementsByClassName("js-switchable-mode-page--scrollspy-offset")

currentLocation = ->
  "#{document.location.pathname}#{document.location.search}"


class ProfilePage.Main extends React.PureComponent
  constructor: (props) ->
    super props

    @state = JSON.parse(props.container.dataset.profilePageState ? null)
    @restoredState = @state?

    if !@restoredState
      page = location.hash.slice(1)
      @initialPage = page if page?

      @state =
        currentMode: props.currentMode
        user: props.user
        userPage:
          html: props.userPage.html
          initialRaw: props.userPage.raw
          raw: props.userPage.raw
          editing: false
          selection: [0, 0]
        profileOrder: props.user.profile_order[..]
        recentActivity: @props.extras.recentActivity
        scoresBest: @props.extras.scoresBest
        scoresFirsts: @props.extras.scoresFirsts
        scoresRecent: @props.extras.scoresRecent
        beatmapPlaycounts: @props.extras.beatmapPlaycounts
        favouriteBeatmapsets: @props.extras.favouriteBeatmapsets
        rankedAndApprovedBeatmapsets: @props.extras.rankedAndApprovedBeatmapsets
        lovedBeatmapsets: @props.extras.lovedBeatmapsets
        unrankedBeatmapsets: @props.extras.unrankedBeatmapsets
        graveyardBeatmapsets: @props.extras.graveyardBeatmapsets
        recentlyReceivedKudosu: @props.extras.recentlyReceivedKudosu
        showMorePagination: {}

      for own elem, perPage of @props.perPage
        @state.showMorePagination[elem] ?= {}
        @state.showMorePagination[elem].hasMore = @state[elem].length > perPage

        if @state.showMorePagination[elem].hasMore
          @state[elem].pop()


  componentDidMount: =>
    $.subscribe 'user:update.profilePage', @userUpdate
    $.subscribe 'user:page:update.profilePage', @userPageUpdate
    $.subscribe 'profile:showMore.profilePage', @showMore
    $.subscribe 'profile:page:jump.profilePage', @pageJump
    $(window).on 'throttled-scroll.profilePage', @pageScan
    $(document).on 'turbolinks:before-cache.profilePage', @saveStateToContainer

    $(@pages).sortable
      cursor: 'move'
      handle: '.js-profile-page-extra--sortable-handle'
      items: '.js-sortable--page'
      revert: 150
      scrollSpeed: 10
      update: @updateOrder

    $(@tabs).sortable
      containment: 'parent'
      cursor: 'move'
      disabled: !@props.withEdit
      items: '.js-sortable--tab'
      revert: 150
      scrollSpeed: 0
      update: @updateOrder
      start: =>
        # Somehow click event still goes through when dragging.
        # This prevents triggering @tabClick.
        Timeout.clear @draggingTabTimeout
        @draggingTab = true
      stop: =>
        @draggingTabTimeout = Timeout.set 500, => @draggingTab = false

    osu.pageChange()

    @modeScrollUrl = currentLocation()

    if !@restoredState
      Timeout.set 0, => @pageJump null, @initialPage


  componentWillUnmount: =>
    $.unsubscribe '.profilePage'
    $(window).off '.profilePage'

    for sortable in [@pages, @tabs]
      $(sortable).sortable 'destroy'

    $(window).stop()
    Timeout.clear @modeScrollTimeout


  render: =>
    if @props.user.is_bot
      profileOrder = ['me']
    else
      profileOrder = @state.profileOrder.slice()

    profileOrder.push 'account_standing' if !_.isEmpty @state.user.account_history

    if @state.userPage.initialRaw.trim() == '' && !@props.withEdit
      _.pull profileOrder, 'me'

    isBlocked = _.find(currentUser.blocks, target_id: @state.user.id)

    div className: 'osu-layout',
      if isBlocked
        div className: 'osu-page',
          el NotificationBanner,
            type: 'warning'
            title: osu.trans('users.blocks.banner_text')
            message:
              div className: 'notification-banner__button-group',
                div className: 'notification-banner__button',
                  el BlockButton, user_id: @props.user.id
                div className: 'notification-banner__button',
                  button
                    type: 'button'
                    className: 'textual-button'
                    onClick: =>
                      @setState forceShow: !@state.forceShow
                    span {},<commit_msg>conditionally apply class so position: sticky works<commit_after>###
#    Copyright 2015-2017 ppy Pty. Ltd.
#
#    This file is part of osu!web. osu!web is distributed with the hope of
#    attracting more community contributions to the core ecosystem of osu!.
#
#    osu!web is free software: you can redistribute it and/or modify
#    it under the terms of the Affero GNU General Public License version 3
#    as published by the Free Software Foundation.
#
#    osu!web is distributed 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 osu!web.  If not, see <http://www.gnu.org/licenses/>.
###

{a, button, div, i, li, span, ul} = ReactDOMFactories
el = React.createElement

pages = document.getElementsByClassName("js-switchable-mode-page--scrollspy")
pagesOffset = document.getElementsByClassName("js-switchable-mode-page--scrollspy-offset")

currentLocation = ->
  "#{document.location.pathname}#{document.location.search}"


class ProfilePage.Main extends React.PureComponent
  constructor: (props) ->
    super props

    @state = JSON.parse(props.container.dataset.profilePageState ? null)
    @restoredState = @state?

    if !@restoredState
      page = location.hash.slice(1)
      @initialPage = page if page?

      @state =
        currentMode: props.currentMode
        user: props.user
        userPage:
          html: props.userPage.html
          initialRaw: props.userPage.raw
          raw: props.userPage.raw
          editing: false
          selection: [0, 0]
        profileOrder: props.user.profile_order[..]
        recentActivity: @props.extras.recentActivity
        scoresBest: @props.extras.scoresBest
        scoresFirsts: @props.extras.scoresFirsts
        scoresRecent: @props.extras.scoresRecent
        beatmapPlaycounts: @props.extras.beatmapPlaycounts
        favouriteBeatmapsets: @props.extras.favouriteBeatmapsets
        rankedAndApprovedBeatmapsets: @props.extras.rankedAndApprovedBeatmapsets
        lovedBeatmapsets: @props.extras.lovedBeatmapsets
        unrankedBeatmapsets: @props.extras.unrankedBeatmapsets
        graveyardBeatmapsets: @props.extras.graveyardBeatmapsets
        recentlyReceivedKudosu: @props.extras.recentlyReceivedKudosu
        showMorePagination: {}

      for own elem, perPage of @props.perPage
        @state.showMorePagination[elem] ?= {}
        @state.showMorePagination[elem].hasMore = @state[elem].length > perPage

        if @state.showMorePagination[elem].hasMore
          @state[elem].pop()


  componentDidMount: =>
    $.subscribe 'user:update.profilePage', @userUpdate
    $.subscribe 'user:page:update.profilePage', @userPageUpdate
    $.subscribe 'profile:showMore.profilePage', @showMore
    $.subscribe 'profile:page:jump.profilePage', @pageJump
    $(window).on 'throttled-scroll.profilePage', @pageScan
    $(document).on 'turbolinks:before-cache.profilePage', @saveStateToContainer

    $(@pages).sortable
      cursor: 'move'
      handle: '.js-profile-page-extra--sortable-handle'
      items: '.js-sortable--page'
      revert: 150
      scrollSpeed: 10
      update: @updateOrder

    $(@tabs).sortable
      containment: 'parent'
      cursor: 'move'
      disabled: !@props.withEdit
      items: '.js-sortable--tab'
      revert: 150
      scrollSpeed: 0
      update: @updateOrder
      start: =>
        # Somehow click event still goes through when dragging.
        # This prevents triggering @tabClick.
        Timeout.clear @draggingTabTimeout
        @draggingTab = true
      stop: =>
        @draggingTabTimeout = Timeout.set 500, => @draggingTab = false

    osu.pageChange()

    @modeScrollUrl = currentLocation()

    if !@restoredState
      Timeout.set 0, => @pageJump null, @initialPage


  componentWillUnmount: =>
    $.unsubscribe '.profilePage'
    $(window).off '.profilePage'

    for sortable in [@pages, @tabs]
      $(sortable).sortable 'destroy'

    $(window).stop()
    Timeout.clear @modeScrollTimeout


  render: =>
    if @props.user.is_bot
      profileOrder = ['me']
    else
      profileOrder = @state.profileOrder.slice()

    profileOrder.push 'account_standing' if !_.isEmpty @state.user.account_history

    if @state.userPage.initialRaw.trim() == '' && !@props.withEdit
      _.pull profileOrder, 'me'

    isBlocked = _.find(currentUser.blocks, target_id: @state.user.id)

    div
      className: 'osu-layout__no-scroll' if isBlocked
      if isBlocked
        div className: 'osu-page',
          el NotificationBanner,
            type: 'warning'
            title: osu.trans('users.blocks.banner_text')
            message:
              div className: 'notification-banner__button-group',
                div className: 'notification-banner__button',
                  el BlockButton, user_id: @props.user.id
                div className: 'notification-banner__button',
                  button
                    type: 'button'
                    className: 'textual-button'
                    onClick: =>
                      @setState forceShow: !@state.forceShow
                    span {},
{'fraction_non_alphanumeric': 0.10352065642591356, 'fraction_numerical': 0.0047705371624844955, 'mean_word_length': 2.756989247311828, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 27, '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': '5040475', 'n_tokens_mistral': 3130, 'n_tokens_neox': 2998, 'n_words': 720}