<commit_before>##############################################################################
#
#    CoCalc: Collaborative Calculation in the Cloud
#
#    Copyright (C) 2015 -- 2018, SageMath, Inc.
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program 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 General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################

# global libs
_         = require('underscore')
immutable = require('immutable')
# react elements
{Col, Row, Panel, Button, FormGroup, Checkbox, FormControl, Well, Alert, Modal, Table, Nav, NavItem, ListGroup, ListGroupItem, InputGroup} = require('react-bootstrap')
{React, ReactDOM, redux, Redux, Actions, Store, rtypes, rclass} = require('../smc-react')
{Loading, Icon, Markdown, Space} = require('../r_misc')
# cocalc libs
{defaults, required, optional} = misc = require('smc-util/misc')


exports.ExamplesBody = rclass
    displayName : 'ExamplesBody'

    propTypes:
        actions             : rtypes.object
        data                : rtypes.immutable
        lang                : rtypes.string
        code                : rtypes.string
        descr               : rtypes.string
        setup_code          : rtypes.string
        prepend_setup_code  : rtypes.bool
        category0           : rtypes.number
        category1           : rtypes.number
        category2           : rtypes.number
        category_list0      : rtypes.arrayOf(rtypes.string)
        category_list1      : rtypes.arrayOf(rtypes.string)
        category_list2      : rtypes.arrayOf(rtypes.string)
        search_str          : rtypes.string
        search_sel          : rtypes.number
        hits                : rtypes.arrayOf(rtypes.array)
        unknown_lang        : rtypes.bool   # if true, show info about contributing to the assistant

    getDefaultProps: ->
        search_str : ''

    shouldComponentUpdate: (props, state) ->
        ret = misc.is_different(@props, props, [
            'data', 'lang', 'code', 'descr', 'setup_code', 'prepend_setup_code',
            'category0', 'category1', 'category2', 'search_str', 'search_sel', 'unknown_lang'
        ])
        ret or= misc.is_different_array(props.hits, @props.hits)
        ret or= misc.is_different_array(props.category_list0, @props.category_list0)
        ret or= misc.is_different_array(props.category_list1, @props.category_list1)
        ret or= misc.is_different_array(props.category_list2, @props.category_list2)
        return ret

    componentDidMount: ->
        @scrollTo0 = _.debounce((() -> $(ReactDOM.findDOMNode(@refs.list_0)).find('.active').scrollintoview()), 50)
        @scrollTo1 = _.debounce((() -> $(ReactDOM.findDOMNode(@refs.list_1)).find('.active').scrollintoview()), 50)
        @scrollTo2 = _.debounce((() -> $(ReactDOM.findDOMNode(@refs.list_2)).find('.active').scrollintoview()), 50)
        @scrollToS = _.debounce((() -> $(ReactDOM.findDOMNode(@refs.search_results_list)).find('.active').scrollintoview()), 50)

    componentDidUpdate: (props, state) ->
        @scrollTo0() if props.category0 != @props.category0
        @scrollTo1() if props.category1 != @props.category1
        @scrollTo2() if props.category2 != @props.category2
        @scrollToS() if props.search_sel != @props.search_sel

    category_selection: (level, idx) ->
        @props.actions.set_selected_category(level, idx)

    # level could be 0, 1 or 2
    render_category_list: (level) ->
        cat  = @props["category#{level}"]
        list = @props["category_list#{level}"]
        list ?= []
        # don't use ListGroup & ListGroupItem with onClick, because then there are div/buttons (instead of ul/li) and layout is f'up
        <ul className={'list-group'} ref={"list_#{level}"}>
        {
            list.map (name, idx) =>
                click  = @category_selection.bind(@, level, idx)
                active = if idx == cat then 'active' else ''
                <li className={"list-group-item " + active} onClick={click} key={idx}>
                    <Markdown value={name} />
                </li>
        }
        </ul>

    search_result_selection: (idx) ->
        @props.actions.search_selected(idx)

    render_search_results: ->
        ss = @props.search_str
        <ul className={'list-group'} ref={'search_results_list'}>
        {
            @props.hits.map (hit, idx) =>
                [lvl1, lvl2, lvl3, title, descr, inDescr] = hit
                click = @search_result_selection.bind(@, idx)
                # highlight the match in the title
                title_hl = title.replace(new RegExp(ss, "gi"), "<span class='hl'>#{ss}</span>")
                # if the hit is in the description, highlight it too
                if inDescr != -1
                    i = Math.max(0, inDescr-30)
                    j = Math.min(descr.length, inDescr+30+ss.length)
                    t = descr[inDescr...inDescr+ss.length]<commit_msg>webapp/assistant: be explicit about which property is used<commit_after>##############################################################################
#
#    CoCalc: Collaborative Calculation in the Cloud
#
#    Copyright (C) 2015 -- 2018, SageMath, Inc.
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program 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 General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################

# global libs
_         = require('underscore')
immutable = require('immutable')
# react elements
{Col, Row, Panel, Button, FormGroup, Checkbox, FormControl, Well, Alert, Modal, Table, Nav, NavItem, ListGroup, ListGroupItem, InputGroup} = require('react-bootstrap')
{React, ReactDOM, redux, Redux, Actions, Store, rtypes, rclass} = require('../smc-react')
{Loading, Icon, Markdown, Space} = require('../r_misc')
# cocalc libs
{defaults, required, optional} = misc = require('smc-util/misc')


exports.ExamplesBody = rclass
    displayName : 'ExamplesBody'

    propTypes:
        actions             : rtypes.object
        data                : rtypes.immutable
        lang                : rtypes.string
        code                : rtypes.string
        descr               : rtypes.string
        setup_code          : rtypes.string
        prepend_setup_code  : rtypes.bool
        category0           : rtypes.number
        category1           : rtypes.number
        category2           : rtypes.number
        category_list0      : rtypes.arrayOf(rtypes.string)
        category_list1      : rtypes.arrayOf(rtypes.string)
        category_list2      : rtypes.arrayOf(rtypes.string)
        search_str          : rtypes.string
        search_sel          : rtypes.number
        hits                : rtypes.arrayOf(rtypes.array)
        unknown_lang        : rtypes.bool   # if true, show info about contributing to the assistant

    getDefaultProps: ->
        search_str : ''

    shouldComponentUpdate: (props, state) ->
        ret = misc.is_different(@props, props, [
            'data', 'lang', 'code', 'descr', 'setup_code', 'prepend_setup_code',
            'category0', 'category1', 'category2', 'search_str', 'search_sel', 'unknown_lang'
        ])
        ret or= misc.is_different_array(props.hits, @props.hits)
        ret or= misc.is_different_array(props.category_list0, @props.category_list0)
        ret or= misc.is_different_array(props.category_list1, @props.category_list1)
        ret or= misc.is_different_array(props.category_list2, @props.category_list2)
        return ret

    componentDidMount: ->
        @scrollTo0 = _.debounce((() -> $(ReactDOM.findDOMNode(@refs.list_0)).find('.active').scrollintoview()), 50)
        @scrollTo1 = _.debounce((() -> $(ReactDOM.findDOMNode(@refs.list_1)).find('.active').scrollintoview()), 50)
        @scrollTo2 = _.debounce((() -> $(ReactDOM.findDOMNode(@refs.list_2)).find('.active').scrollintoview()), 50)
        @scrollToS = _.debounce((() -> $(ReactDOM.findDOMNode(@refs.search_results_list)).find('.active').scrollintoview()), 50)

    componentDidUpdate: (props, state) ->
        @scrollTo0() if props.category0 != @props.category0
        @scrollTo1() if props.category1 != @props.category1
        @scrollTo2() if props.category2 != @props.category2
        @scrollToS() if props.search_sel != @props.search_sel

    category_selection: (level, idx) ->
        @props.actions.set_selected_category(level, idx)

    # level could be 0, 1 or 2
    render_category_list: (level) ->
        [category, list] = switch level
            when 0 then [@props.category0, @props.category_list0]
            when 1 then [@props.category1, @props.category_list1]
            when 2 then [@props.category2, @props.category_list2]
        list ?= []
        # don't use ListGroup & ListGroupItem with onClick, because then there are div/buttons (instead of ul/li) and layout is f'up
        <ul className={'list-group'} ref={"list_#{level}"}>
        {
            list.map (name, idx) =>
                click  = @category_selection.bind(@, level, idx)
                active = if idx == category then 'active' else ''
                <li className={"list-group-item " + active} onClick={click} key={idx}>
                    <Markdown value={name} />
                </li>
        }
        </ul>

    search_result_selection: (idx) ->
        @props.actions.search_selected(idx)

    render_search_results: ->
        ss = @props.search_str
        <ul className={'list-group'} ref={'search_results_list'}>
        {
            @props.hits.map (hit, idx) =>
                [lvl1, lvl2, lvl3, title, descr, inDescr] = hit
                click = @search_result_selection.bind(@, idx)
                # highlight the match in the title
                title_hl = title.replace(new RegExp(ss, "gi"), "<span class='hl'>#{ss}</span>")
                # if the hit is in the description, highlight it too
                if inDescr != -1
                    i = Math.max(0, inDescr-30)
                    j = Math.min(descr.length, inDescr+30+ss.length)
                    t = descr[inDescr...inDescr+ss.length]
{'fraction_non_alphanumeric': 0.1455407460416853, 'fraction_numerical': 0.01136058681456302, 'mean_word_length': 2.5113065326633164, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 49, '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': '6940959', 'n_tokens_mistral': 3328, 'n_tokens_neox': 3185, 'n_words': 815}