<commit_before>'use strict';
import React from 'react';
import { connect } from 'react-redux';
import { _ } from 'lodash';
import { t, getLanguage } from '../utils/i18n';
import { Link } from 'react-router';

import AATable from '../components/aa-table-vpromms';

import { fetchVProMMsids, fetchAdminChildren, fetchFieldVProMMsids, fetchVProMMsidsProperties, setCrossWalk } from '../actions/action-creators';

import config from '../config';

var AnalyticsAA = React.createClass({
  displayName: 'AnalyticsAA',

  propTypes: {
    _fetchVProMMsids: React.PropTypes.func,
    _fetchFieldVProMMsids: React.PropTypes.func,
    _fetchVProMMsidsProperties: React.PropTypes.func,
    _fetchAdminChildren: React.PropTypes.func,
    _setCrossWalk: React.PropTypes.func,
    children: React.PropTypes.object,
    routeParams: React.PropTypes.object,
    crosswalk: React.PropTypes.object,
    params: React.PropTypes.object,
    provinceCrossWalk: React.PropTypes.object,
    VProMMSids: React.PropTypes.object,
    VProMMsProps: React.PropTypes.object,
    fieldIds: React.PropTypes.array,
    fieldFetched: React.PropTypes.bool,
    propsFetched: React.PropTypes.bool,
    adminChildren: React.PropTypes.object,
    adminChildrenFetched: React.PropTypes.bool,
    location: React.PropTypes.object
  },

  renderAdminChildren: function (children) {
    return (

        {children.map((child, i) => {
          return (

<Link onClick={(e) => { this.props._fetchAdminChildren(child.id); } } to={`/${getLanguage()}/analytics/${child.id}`}>{child.name_en}</Link>

          );
        })}

    );
  },

  renderDataDumpLinks: function (provinceId) {
    return (

Admin Chilren

        <a className='bttn bttn-secondary' href={`${config.provinceDumpBaseUrl}${provinceId}.csv`}>Download Roads

    );
  },

  componentWillMount: function () {
    this.props._fetchVProMMsidsProperties();
    this.props._fetchFieldVProMMsids();
    this.props._fetchAdminChildren(this.props.params.aaId);
  },

  handlePop: function () {
    this.props.adminChildren.level === 'district' ? this.props._fetchAdminChildren(this.props.adminChildren.parent) : '';
  },

  renderAnalyticsAdmin: function () {
    this.props.location.action === 'POP' ? this.handlePop() : '';
    const level = this.props.adminChildren.level;
    const provinceId = (level === 'province') ? _.invert(this.props.crosswalk[level])[this.props.params.aaId] : this.props.crosswalk[level][this.props.params.aaId];
    const provinceName = this.props.adminChildren.name;
    const idTest = (level === 'province') ? new RegExp(provinceId) : [new RegExp(provinceId), new RegExp(_.invert(this.props.crosswalk['province'])[this.props.adminChildren.parent])];
    const adminData = (level === 'province') ? Object.keys(this.props.VProMMsProps).filter(id => idTest.test(id.substring(0, 2))) : (Object.keys(this.props.VProMMsProps).filter(
      (id) => {
        id = id.substring(0, 5);
        return idTest[0].test(id) && idTest[1].test(id);
      })
    );
    const propertiesData = _.pickBy(this.props.VProMMsProps, (prop, vpromm) => (adminData.indexOf(vpromm) !== -1));
    const field = (level === 'province') ? this.props.fieldIds.filter(vpromm => idTest.test(vpromm.substring(0, 2))).length : (Object.keys(this.props.VProMMsProps).filter(
      (id) => {
        id = id.substring(0, 5);
        return idTest[0].test(id) && idTest[1].test(id);
      }).length
    );
    const total = adminData.length;
    const completion = total !== 0 ? ((field / total) * 100) : 0;
    let completionMainText;
    let completionTailText = t('Information on VPRoMMS roads is not available');
    if (total !== 0) {
      completionMainText = completion.toFixed(2);
      completionTailText = `% ${t('of VProMMS Ids have field data')} ${field.toLocaleString()} of ${total.toLocaleString()}`;
    }
    // completion text is comprised of a main text component and a tail component, both need to be distinct per the existence of ids for the province.
    return (

{provinceName}

            { completion ? this.renderDataDumpLinks(provinceId) : '' }

          { (level !== 'district') ? this.renderAdminChildren(this.props.adminChildren.children) : '' }

{completionMainText}{completionTailText}

              <div className='meter__internal' style={{width: `${completion}%`}}>

            {total ? <AATable data={adminData} propertiesData={propertiesData} /> : ''}

    );
  },

  render: function () {
    const allFetched = (this.props.propsFetched && this.props.fieldFetched && this.props.adminChildrenFetched);
    return allFetched ? this.renderAnalyticsAdmin() : (
);
  }
});

function selector (state) {
  return {
    fieldIds: state.fieldVProMMsids.ids,
    crosswalk: state.crosswalk,
    propsFetched: state.VProMMsidProperties.fetched,
    fieldFetched: state.fieldVProMMsids.fetched,
    VProMMSids: state.VProMMSidsAnalytics,
    VProMMsProps: state.VProMMsidProperties.properties,
    adminChildren: state.adminChildren.data,
    adminChildrenFetched: state.adminChildren.fetched
  };
}

function dispatcher (dispatch) {
  return {
    _fetchVProMMsids: () => dispatch(fetchVProMMsids()),
    _fetchFieldVProMMsids: () => dispatch(fetchFieldVProMMsids()),
    _fetchVProMMsidsProperties: () => dispatch(fetchVProMMsidsProperties()),
    _fetchAdminChildren: (id) => dispatch(fetchAdminChildren(id)),
    _setCrossWalk: () => dispatch(setCrossWalk())
  };
}

module.exports = connect(selector, dispatcher)(AnalyticsAA);

<commit_msg>Add id on vpromm list (#169)<commit_after>'use strict';
import React from 'react';
import { connect } from 'react-redux';
import { _ } from 'lodash';
import { t, getLanguage } from '../utils/i18n';
import { Link } from 'react-router';

import AATable from '../components/aa-table-vpromms';

import { fetchVProMMsids, fetchAdminChildren, fetchFieldVProMMsids, fetchVProMMsidsProperties, setCrossWalk } from '../actions/action-creators';

import config from '../config';

var AnalyticsAA = React.createClass({
  displayName: 'AnalyticsAA',

  propTypes: {
    _fetchVProMMsids: React.PropTypes.func,
    _fetchFieldVProMMsids: React.PropTypes.func,
    _fetchVProMMsidsProperties: React.PropTypes.func,
    _fetchAdminChildren: React.PropTypes.func,
    _setCrossWalk: React.PropTypes.func,
    children: React.PropTypes.object,
    routeParams: React.PropTypes.object,
    crosswalk: React.PropTypes.object,
    params: React.PropTypes.object,
    provinceCrossWalk: React.PropTypes.object,
    VProMMSids: React.PropTypes.object,
    VProMMsProps: React.PropTypes.object,
    fieldIds: React.PropTypes.array,
    fieldFetched: React.PropTypes.bool,
    propsFetched: React.PropTypes.bool,
    adminChildren: React.PropTypes.object,
    adminChildrenFetched: React.PropTypes.bool,
    location: React.PropTypes.object
  },

  renderAdminChildren: function (children) {
    return (

        {children.map((child, i) => {
          return (

<Link onClick={(e) => { this.props._fetchAdminChildren(child.id); } } to={`/${getLanguage()}/analytics/${child.id}`}>{child.name_en}</Link>

          );
        })}

    );
  },

  renderDataDumpLinks: function (provinceId) {
    return (

Admin Chilren

        <a className='bttn bttn-secondary' href={`${config.provinceDumpBaseUrl}${provinceId}.csv`}>Download Roads

    );
  },

  componentWillMount: function () {
    this.props._fetchVProMMsidsProperties();
    this.props._fetchFieldVProMMsids();
    this.props._fetchAdminChildren(this.props.params.aaId);
  },

  handlePop: function () {
    this.props.adminChildren.level === 'district' ? this.props._fetchAdminChildren(this.props.adminChildren.parent) : '';
  },

  renderAnalyticsAdmin: function () {
    this.props.location.action === 'POP' ? this.handlePop() : '';
    const level = this.props.adminChildren.level;
    const provinceId = (level === 'province') ? _.invert(this.props.crosswalk[level])[this.props.params.aaId] : this.props.crosswalk[level][this.props.params.aaId];
    const provinceName = this.props.adminChildren.name;
    const idTest = (level === 'province') ? new RegExp(provinceId) : [new RegExp(provinceId), new RegExp(_.invert(this.props.crosswalk['province'])[this.props.adminChildren.parent])];
    const adminData = (level === 'province') ? Object.keys(this.props.VProMMsProps).filter(id => idTest.test(id.substring(0, 2))) : (Object.keys(this.props.VProMMsProps).filter(
      (id) => {
        id = id.substring(0, 5);
        return idTest[0].test(id) && idTest[1].test(id);
      })
    );
    const propertiesData = _.pickBy(this.props.VProMMsProps, (prop, vpromm) => (adminData.indexOf(vpromm) !== -1));
    const field = (level === 'province') ? this.props.fieldIds.filter(vpromm => idTest.test(vpromm.substring(0, 2))).length : (Object.keys(this.props.VProMMsProps).filter(
      (id) => {
        id = id.substring(0, 5);
        return idTest[0].test(id) && idTest[1].test(id);
      }).length
    );
    const total = adminData.length;
    const completion = total !== 0 ? ((field / total) * 100) : 0;
    let completionMainText;
    let completionTailText = t('Information on VPRoMMS roads is not available');
    if (total !== 0) {
      completionMainText = completion.toFixed(2);
      completionTailText = `% ${t('of VProMMS Ids have field data')} ${field.toLocaleString()} of ${total.toLocaleString()}`;
    }
    // completion text is comprised of a main text component and a tail component, both need to be distinct per the existence of ids for the province.
    return (

{provinceName}

            { completion ? this.renderDataDumpLinks(provinceId) : '' }

          { (level !== 'district') ? this.renderAdminChildren(this.props.adminChildren.children) : '' }

{completionMainText}{completionTailText}

              <div className='meter__internal' style={{width: `${completion}%`}}>

            {total ? <AATable data={adminData} propertiesData={propertiesData} /> : ''}

    );
  },

  render: function () {
    const allFetched = (this.props.propsFetched && this.props.fieldFetched && this.props.adminChildrenFetched);
    return allFetched ? this.renderAnalyticsAdmin() : (
);
  }
});

function selector (state) {
  return {
    fieldIds: state.fieldVProMMsids.ids,
    crosswalk: state.crosswalk,
    propsFetched: state.VProMMsidProperties.fetched,
    fieldFetched: state.fieldVProMMsids.fetched,
    VProMMSids: state.VProMMSidsAnalytics,
    VProMMsProps: state.VProMMsidProperties.properties,
    adminChildren: state.adminChildren.data,
    adminChildrenFetched: state.adminChildren.fetched
  };
}

function dispatcher (dispatch) {
  return {
    _fetchVProMMsids: () => dispatch(fetchVProMMsids()),
    _fetchFieldVProMMsids: () => dispatch(fetchFieldVProMMsids()),
    _fetchVProMMsidsProperties: () => dispatch(fetchVProMMsidsProperties()),
    _fetchAdminChildren: (id) => dispatch(fetchAdminChildren(id)),
    _setCrossWalk: () => dispatch(setCrossWalk())
  };
}

module.exports = connect(selector, dispatcher)(AnalyticsAA);

<|endoftext|>


<commit_before>import fastdom from "fastdom"
import diffDOM from "diff-dom"

import {findTarget} from "../../common"
import {marginBoxesTemplate, marginboxFilterTemplate} from "./templates"
import {getCommentDuringCreationDecoration, getSelectedChanges, getFootnoteMarkers} from "../state_plugins"

/* Functions related to layouting of comments */
export class ModMarginboxes {
    constructor(editor) {
        editor.mod.marginboxes = this
        this.editor = editor
        this.activeCommentStyle = ''
        this.filterOptions = {
            track: true,
            comments: true,
            help: true,
            commentsResolved: false,
            author: 0,
            assigned: 0
        }
        this.commentColors = {
            isMajor: '#f4c9d9',
            marker: '#f9f9f9',
            active: '#fffacf'
        }
        this.dd = new diffDOM({
            valueDiffing: false
        })
    }

    init() {
        // Add two elements to hold dynamic CSS info about comments.
        document.body.insertAdjacentHTML(
            'beforeend',
            '<style type="text/css" id="active-comment-style"></style><style type="text/css" id="margin-box-placement-style"></style>'
        )
        this.marginBoxesContainer = document.getElementById('margin-box-container')
        this.activeCommentStyleElement = document.getElementById('active-comment-style')
        this.bindEvents()
    }

    bindEvents() {
        // Bind all the click events related to the margin box filter
        document.body.addEventListener('click', event => {
            const el = {}
            switch (true) {
                case findTarget(event, '#margin-box-filter-comments-resolved', el):
                    this.filterOptions.commentsResolved = !this.filterOptions.commentsResolved
                    this.view(this.editor.currentView)
                    break
                case findTarget(event, '.margin-box-filter-comments-author', el):
                    this.filterOptions.author = parseInt(el.target.dataset.id)
                    this.view(this.editor.currentView)
                    break
                case findTarget(event, '.margin-box-filter-comments-assigned', el):
                    this.filterOptions.assigned = parseInt(el.target.dataset.id)
                    this.view(this.editor.currentView)
                    break
                case findTarget(event, '.show-marginbox-options-submenu', el):
                    this.closeAllMenus('.marginbox-options-submenu.fw-open')
                    Array.from(el.target.parentElement.children).find(node => node.matches('.marginbox-options-submenu')).classList.add('fw-open')
                    break
                case findTarget(event, '.show-marginbox-options', el):
                    this.closeAllMenus()
                    Array.from(el.target.parentElement.children).find(node => node.matches('.marginbox-options')).classList.add('fw-open')
                    break
                case findTarget(event, '#margin-box-filter-track', el):
                    this.filterOptions.track = !this.filterOptions.track
                    this.view(this.editor.currentView)
                    break
                case findTarget(event, '#margin-box-filter-comments', el):
                    this.filterOptions.comments = !this.filterOptions.comments
                    this.view(this.editor.currentView)
                    break
                case findTarget(event, '#margin-box-filter-help', el):
                    this.filterOptions.help = !this.filterOptions.help
                    this.view(this.editor.currentView)
                    break
                case findTarget(event, '.margin-box.comment.inactive', el):
                    this.editor.mod.comments.interactions.deactivateSelectedChanges()
                    this.editor.mod.comments.interactions.activateComment(el.target.dataset.id)
                    break
                case findTarget(event, '.margin-box.track.inactive', el):
                    this.editor.mod.track.activateTrack(
                        el.target.dataset.view,
                        el.target.dataset.type,
                        parseInt(el.target.dataset.pos)
                    )
                    break
                default:
                    this.closeAllMenus()
                    break
            }
        })
    }

    closeAllMenus(selector='.marginbox-options-submenu.fw-open, .marginbox-options.fw-open') {
        document.querySelectorAll(selector).forEach(
            el => el.classList.remove('fw-open')
        )
    }

    view(view) {
        // Give up if the user is currently editing a comment.
        if (this.editor.mod.comments.interactions.isCurrentlyEditing()) {
            return false
        }
        this.editor.mod.comments.interactions.activateSelectedComment(view)
    }

    updateDOM() {
        // Handle the layout of the comments on the screen.
        // DOM write phase

        const marginBoxes = [],
            referrers = [],
            selectedChanges = getSelectedChanges(this.editor.currentView.state)
        let fnIndex = 0,
            fnPosCount = 0,
            lastNodeTracks = [],
            lastNode = this.editor.view.state.doc

        this.activeCommentStyle = ''

        this.editor.view.state.doc.descendants(
            (node, pos) => {
                if (node.attrs.hidden) {
                    return false
                }
                lastNodeTracks = this.getMarginBoxes(
                    node,
                    pos,
                    pos,
                    lastNode,
                    lastNodeTracks,
                    'main',
                    marginBoxes,
                    referrers,
                    selectedChanges,
                    this.editor.view.state.selection
                )
                lastNode = node

                if (node.type.name==='footnote') {
                    let lastFnNode = this.editor.mod.footnotes.fnEditor.view.state.doc,
                        lastFnNodeTracks = []
                    const footnote = lastFnNode.childCount > fnIndex ? lastFnNode.child(fnIndex) : false
                    if (!footnote) {
                        return
                    }
                    this.editor.mod.footnotes.fnEditor.view.state.doc.nodesBetween(
                        fnPosCount,
                        fnPosCount+footnote.nodeSize,
                        (fnNode, fnPos) => {
                            if (fnPos < fnPosCount) {
                                return false
                            }
                            lastFnNodeTracks = this.getMarginBoxes(
                                fnNode,
                                fnPos,
                                pos,
                                lastFnNode,
                                lastFnNodeTracks,
                                'footnote',
                                marginBoxes,
                                referrers,
                                selectedChanges,
                                this.editor.view.state.selection
                            )
                            lastFnNode = fnNode
                        }
                    )
                    fnIndex++
                    fnPosCount += footnote.nodeSize
                }
            }
        )

        // Add a comment that is currently under construction to the list.
        if (this.editor.mod.comments.store.commentDuringCreation) {
            const deco = getCommentDuringCreationDecoration(this.editor.view.state)
            let pos, view
            if (deco) {
                pos = deco.from
                view = 'main'
            } else {
                const fnDeco = getCommentDuringCreationDecoration(this.editor.mod.footnotes.fnEditor.view.state)
                if (fnDeco) {
                    pos = this.fnPosToPos(fnDeco.from)
                    view = 'footnote'
                }
            }
            if (pos) {
                const comment = this.editor.mod.comments.store.commentDuringCreation.comment
                let index = 0
                // // We need the position of the new comment in relation to the other
                // // comments in order to insert it in the right place
                while (referrers.length > index && referrers[index] < pos) {
                    index++
                }
                marginBoxes.splice(index, 0, {type: 'comment', data: comment, view, pos, active: true})
                referrers.splice(index, 0, pos)
                this.activeCommentStyle += '.active-comment, .active-comment .comment {background-color: #fffacf !important;}'
            }
        }

        const marginBoxesHTML = marginBoxesTemplate({
            marginBoxes,
            user: this.editor.user,
            docInfo: this.editor.docInfo,
            editComment: this.editor.mod.comments.interactions.editComment,
            activeCommentAnswerId: this.editor.mod.comments.interactions.activeCommentAnswerId,
            filterOptions: this.filterOptions,
            staticUrl: this.editor.staticUrl
        })
        if (this.marginBoxesContainer.innerHTML !== marginBoxesHTML) {
            const tempEl = document.createElement('div')
            tempEl.id = 'margin-box-container'
            tempEl.innerHTML = marginBoxesHTML
            const diff = this.dd.diff(this.marginBoxesContainer, tempEl)
            this.dd.apply(this.marginBoxesContainer, diff)
        }

        if (this.activeCommentStyleElement.innerHTML != this.activeCommentStyle) {
            this.activeCommentStyleElement.innerHTML = this.activeCommentStyle
        }

        const marginBoxFilterHTML = marginboxFilterTemplate({
            marginBoxes,
            filterOptions: this.filterOptions,
            docInfo: this.editor.docInfo
        })

        if (document.getElementById('margin-box-filter').innerHTML != marginBoxFilterHTML) {
            document.getElementById('margin-box-filter').innerHTML = marginBoxFilterHTML
        }

        return new Promise(resolve => {

            fastdom.measure(() => {
                // DOM read phase
                const marginBoxesDOM = document.querySelectorAll('#margin-box-container .margin-box')
                if (marginBoxesDOM.length !== referrers.length || !marginBoxesDOM.length) {
                    // Number of comment boxes and referrers differ.
                    // This isn't right. Abort.
                    resolve()
                    return
                }
                const bodyTop = document.body.getBoundingClientRect().top,
                    marginBoxPlacements = Array.from(marginBoxesDOM).map((mboxDOM, index) => {
                        const mboxDOMRect = mboxDOM.getBoundingClientRect()
                        return {
                            height: mboxDOMRect.height,
                            refPos: this.editor.view.coordsAtPos(referrers[index]).top - bodyTop
                        }
                    }),
                    firstActiveIndex = marginBoxes.findIndex(mBox => mBox.active),
                    firstActiveMboxPlacement = marginBoxPlacements[firstActiveIndex]

                let activeIndex = firstActiveIndex,
                    currentPos = 0
                while (activeIndex > -1) {
                    const mboxPlacement = marginBoxPlacements[activeIndex]
                    if (mboxPlacement.height === 0) {
                        mboxPlacement.pos = currentPos
                    } else if (mboxPlacement===firstActiveMboxPlacement) {
                        mboxPlacement.pos = mboxPlacement.refPos
                    } else {
                        mboxPlacement.pos = Math.min(
                            currentPos - 2 - mboxPlacement.height,
                            mboxPlacement.refPos
                    )
                    }
                    currentPos = mboxPlacement.pos
                    activeIndex--
                }
                if (firstActiveIndex > -1) {
                    currentPos = firstActiveMboxPlacement.pos + firstActiveMboxPlacement.height
                    activeIndex = firstActiveIndex + 1
                } else {
                    activeIndex = 0
                }

                while (activeIndex < marginBoxPlacements.length) {
                    const mboxPlacement = marginBoxPlacements[activeIndex]
                    mboxPlacement.pos = Math.max(currentPos + 2, mboxPlacement.refPos)
                    currentPos = mboxPlacement.pos + mboxPlacement.height
                    activeIndex++
                }

                const initialOffset = document.body.classList.contains('header-closed') ? 91 + 60 : 200 + 60
                let totalOffset = 0

                const marginBoxesPlacementStyle = marginBoxPlacements.map((mboxPlacement, index) => {
                    if (mboxPlacement.height === 0) {
                        return ''
                    }
                    const pos = mboxPlacement.pos - initialOffset
                    let css = ''
                    if (pos !== totalOffset) {
                        const topMargin = parseInt(pos - totalOffset)
                        css += `.margin-box:nth-of-type(${(index+1)}) {margin-top: ${topMargin}px;}\n`
                        totalOffset += topMargin
                    }
                    totalOffset += mboxPlacement.height + 2
                    return css
                }).join('')

                fastdom.mutate(() => {
                    //DOM write phase
                    if (document.getElementById('margin-box-placement-style').innerHTML != marginBoxesPlacementStyle) {
                        document.getElementById('margin-box-placement-style').innerHTML = marginBoxesPlacementStyle
                    }
                    if (this.editor.mod.comments.store.commentDuringCreation) {
                        this.editor.mod.comments.store.commentDuringCreation.inDOM = true
                    }
                    resolve()
                })
            })

        })

    }

    fnPosToPos(fnPos) {
        const fnIndex = this.editor.mod.footnotes.fnEditor.view.state.doc.resolve(fnPos).index(0),
            fnMarker = getFootnoteMarkers(this.editor.view.state)[fnIndex]

        return fnMarker.from
    }

    getMarginBoxes(
        node,
        pos,
        refPos,
        lastNode,
        lastNodeTracks,
        view,
        marginBoxes,
        referrers,
        selectedChanges,
        selection // Selection in main editor
    ) {

        if (node.attrs.help) { // Help/instruction margin boxes
            const helpBox = {
                type: 'help',
                data: {
                    active: selection.$anchor.node(2) === node ? true : false,
                    help: node.attrs.help
                }
            }
            marginBoxes.push(helpBox)
            referrers.push(refPos)
        }

        const commentIds = node.isInline || node.isLeaf ? this.editor.mod.comments.interactions.findCommentIds(node) : []

        const nodeTracks = node.attrs.track ?
            node.attrs.track.map(track => {
                const nodeTrack = {type: track.type, data: {user: track.user, username: track.username, date: track.date}}
                if (track.type==='block_change') {
                    nodeTrack.data.before = track.before
                }
                return nodeTrack
            }) :
            node.marks.filter(mark =>
                ['deletion', 'format_change'].includes(mark.type.name) ||
                (mark.type.name==='insertion' && !mark.attrs.approved)
            ).map(mark => ({type: mark.type.name, data: mark.attrs}))

        // Filter out trackmarks already present in the last node (if it's an inline node).
        const tracks = node.isInline === lastNode.isInline ?
            nodeTracks.filter(track =>
                !lastNodeTracks.find(
                    lastTrack =>
                        track.type===lastTrack.type &&
                        track.data.user===lastTrack.data.user &&
                        track.data.date===lastTrack.data.date &&
                        (
                            node.isInline || // block level changes almost always need new boxes
                            (node.type.name === 'paragraph' && lastNode.type.name === 'list_item' && lastTrack.type === 'insertion') // Don't show first paragraphs in list items.
                        ) &&
                        (
                            ['insertion', 'deletion'].includes(track.type) ||
                            (
                                track.type === 'format_change' &&
                                track.data.before.length===lastTrack.data.before.length &&
                                track.data.after.length===lastTrack.data.after.length &&
                                track.data.before.every(markName => lastTrack.data.before.includes(markName)) &&
                                track.data.after.every(markName => lastTrack.data.after.includes(markName))
                            ) ||
                            (
                                track.type === 'block_change' &&
                                track.data.before.type===lastTrack.data.before.type &&
                                track.data.before.attrs.level===lastTrack.data.before.attrs.level
                            )
                        )
                )
            ) :
            nodeTracks
        tracks.forEach(track => {
            marginBoxes.push(Object.assign({
                node,
                pos,
                view,
                active: selectedChanges[track.type] && selectedChanges[track.type].from === pos
            }, track))
            referrers.push(refPos)
        })

        if (!commentIds.length && !tracks.length) {
            return nodeTracks
        }
        commentIds.forEach(commentId => {
            const comment = this.editor.mod.comments.store.findComment(commentId)
            if (!comment || (!this.filterOptions.commentsResolved && comment.resolved)) {
                // We have no comment with this ID. Ignore the referrer.
                return
            }
            if (marginBoxes.find(marginBox => marginBox.data===comment)) {
                // comment already placed
                return
            }
            const active = comment.id === this.editor.mod.comments.interactions.activeCommentId
            if (this.filterOptions.comments) {
                if (active) {
                    this.activeCommentStyle +=
                        `.comment[data-id="${comment.id}"], .comment[data-id="${comment.id}"] .comment {background-color: ${this.commentColors.active} !important;}`
                } else if (comment.isMajor) {
                    this.activeCommentStyle +=
                        `#paper-editable .comment[data-id="${comment.id}"] {background-color: ${this.commentColors.isMajor};}`
                } else {
                    this.activeCommentStyle +=
                        `#paper-editable .comment[data-id="${comment.id}"] {background-color: ${this.commentColors.marker};}`
                }
            }
            marginBoxes.push({type: 'comment', data: comment, pos, view, active})
            referrers.push(refPos)
        })

        return nodeTracks
    }

}
<commit_msg>Using Redom updating the dom<commit_after>import fastdom from "fastdom"
import diffDOM from "diff-dom"

import {findTarget} from "../../common"
import {marginBoxesTemplate, marginboxFilterTemplate} from "./templates"
import {getCommentDuringCreationDecoration, getSelectedChanges, getFootnoteMarkers} from "../state_plugins"
import {setChildren} from 'redom'
/* Functions related to layouting of comments */
export class ModMarginboxes {
    constructor(editor) {
        editor.mod.marginboxes = this
        this.editor = editor
        this.activeCommentStyle = ''
        this.filterOptions = {
            track: true,
            comments: true,
            help: true,
            commentsResolved: false,
            author: 0,
            assigned: 0
        }
        this.commentColors = {
            isMajor: '#f4c9d9',
            marker: '#f9f9f9',
            active: '#fffacf'
        }
        this.dd = new diffDOM({
            valueDiffing: false
        })
    }

    init() {
        // Add two elements to hold dynamic CSS info about comments.
        document.body.insertAdjacentHTML(
            'beforeend',
            '<style type="text/css" id="active-comment-style"></style><style type="text/css" id="margin-box-placement-style"></style>'
        )
        this.marginBoxesContainer = document.getElementById('margin-box-container')
        this.activeCommentStyleElement = document.getElementById('active-comment-style')
        this.bindEvents()
    }

    bindEvents() {
        // Bind all the click events related to the margin box filter
        document.body.addEventListener('click', event => {
            const el = {}
            switch (true) {
                case findTarget(event, '#margin-box-filter-comments-resolved', el):
                    this.filterOptions.commentsResolved = !this.filterOptions.commentsResolved
                    this.view(this.editor.currentView)
                    break
                case findTarget(event, '.margin-box-filter-comments-author', el):
                    this.filterOptions.author = parseInt(el.target.dataset.id)
                    this.view(this.editor.currentView)
                    break
                case findTarget(event, '.margin-box-filter-comments-assigned', el):
                    this.filterOptions.assigned = parseInt(el.target.dataset.id)
                    this.view(this.editor.currentView)
                    break
                case findTarget(event, '.show-marginbox-options-submenu', el):
                    this.closeAllMenus('.marginbox-options-submenu.fw-open')
                    Array.from(el.target.parentElement.children).find(node => node.matches('.marginbox-options-submenu')).classList.add('fw-open')
                    break
                case findTarget(event, '.show-marginbox-options', el):
                    this.closeAllMenus()
                    Array.from(el.target.parentElement.children).find(node => node.matches('.marginbox-options')).classList.add('fw-open')
                    break
                case findTarget(event, '#margin-box-filter-track', el):
                    this.filterOptions.track = !this.filterOptions.track
                    this.view(this.editor.currentView)
                    break
                case findTarget(event, '#margin-box-filter-comments', el):
                    this.filterOptions.comments = !this.filterOptions.comments
                    this.view(this.editor.currentView)
                    break
                case findTarget(event, '#margin-box-filter-help', el):
                    this.filterOptions.help = !this.filterOptions.help
                    this.view(this.editor.currentView)
                    break
                case findTarget(event, '.margin-box.comment.inactive', el):
                    this.editor.mod.comments.interactions.deactivateSelectedChanges()
                    this.editor.mod.comments.interactions.activateComment(el.target.dataset.id)
                    break
                case findTarget(event, '.margin-box.track.inactive', el):
                    this.editor.mod.track.activateTrack(
                        el.target.dataset.view,
                        el.target.dataset.type,
                        parseInt(el.target.dataset.pos)
                    )
                    break
                default:
                    this.closeAllMenus()
                    break
            }
        })
    }

    closeAllMenus(selector='.marginbox-options-submenu.fw-open, .marginbox-options.fw-open') {
        document.querySelectorAll(selector).forEach(
            el => el.classList.remove('fw-open')
        )
    }

    view(view) {
        // Give up if the user is currently editing a comment.
        if (this.editor.mod.comments.interactions.isCurrentlyEditing()) {
            return false
        }
        this.editor.mod.comments.interactions.activateSelectedComment(view)
    }

    updateDOM() {
        // Handle the layout of the comments on the screen.
        // DOM write phase

        const marginBoxes = [],
            referrers = [],
            selectedChanges = getSelectedChanges(this.editor.currentView.state)
        let fnIndex = 0,
            fnPosCount = 0,
            lastNodeTracks = [],
            lastNode = this.editor.view.state.doc

        this.activeCommentStyle = ''

        this.editor.view.state.doc.descendants(
            (node, pos) => {
                if (node.attrs.hidden) {
                    return false
                }
                lastNodeTracks = this.getMarginBoxes(
                    node,
                    pos,
                    pos,
                    lastNode,
                    lastNodeTracks,
                    'main',
                    marginBoxes,
                    referrers,
                    selectedChanges,
                    this.editor.view.state.selection
                )
                lastNode = node

                if (node.type.name==='footnote') {
                    let lastFnNode = this.editor.mod.footnotes.fnEditor.view.state.doc,
                        lastFnNodeTracks = []
                    const footnote = lastFnNode.childCount > fnIndex ? lastFnNode.child(fnIndex) : false
                    if (!footnote) {
                        return
                    }
                    this.editor.mod.footnotes.fnEditor.view.state.doc.nodesBetween(
                        fnPosCount,
                        fnPosCount+footnote.nodeSize,
                        (fnNode, fnPos) => {
                            if (fnPos < fnPosCount) {
                                return false
                            }
                            lastFnNodeTracks = this.getMarginBoxes(
                                fnNode,
                                fnPos,
                                pos,
                                lastFnNode,
                                lastFnNodeTracks,
                                'footnote',
                                marginBoxes,
                                referrers,
                                selectedChanges,
                                this.editor.view.state.selection
                            )
                            lastFnNode = fnNode
                        }
                    )
                    fnIndex++
                    fnPosCount += footnote.nodeSize
                }
            }
        )

        // Add a comment that is currently under construction to the list.
        if (this.editor.mod.comments.store.commentDuringCreation) {
            const deco = getCommentDuringCreationDecoration(this.editor.view.state)
            let pos, view
            if (deco) {
                pos = deco.from
                view = 'main'
            } else {
                const fnDeco = getCommentDuringCreationDecoration(this.editor.mod.footnotes.fnEditor.view.state)
                if (fnDeco) {
                    pos = this.fnPosToPos(fnDeco.from)
                    view = 'footnote'
                }
            }
            if (pos) {
                const comment = this.editor.mod.comments.store.commentDuringCreation.comment
                let index = 0
                // // We need the position of the new comment in relation to the other
                // // comments in order to insert it in the right place
                while (referrers.length > index && referrers[index] < pos) {
                    index++
                }
                marginBoxes.splice(index, 0, {type: 'comment', data: comment, view, pos, active: true})
                referrers.splice(index, 0, pos)
                this.activeCommentStyle += '.active-comment, .active-comment .comment {background-color: #fffacf !important;}'
            }
        }

        const marginBoxesHTML = marginBoxesTemplate({
            marginBoxes,
            user: this.editor.user,
            docInfo: this.editor.docInfo,
            editComment: this.editor.mod.comments.interactions.editComment,
            activeCommentAnswerId: this.editor.mod.comments.interactions.activeCommentAnswerId,
            filterOptions: this.filterOptions,
            staticUrl: this.editor.staticUrl
        })
        if (this.marginBoxesContainer.innerHTML !== marginBoxesHTML) {
            // const hello = el('h1', 'Hello RE:DOM!');
            // mount(document.querySelector('#margin-box-column'), hello);
            // console.log(hello)
            const tempEl = document.createElement('div')
            tempEl.id = 'margin-box-container'
            tempEl.innerHTML = marginBoxesHTML

            setChildren(document.querySelector('#margin-box-container'), [tempEl])

            //const diff = this.dd.diff(this.marginBoxesContainer, tempEl)
            //this.dd.apply(this.marginBoxesContainer, diff)
        }

        if (this.activeCommentStyleElement.innerHTML != this.activeCommentStyle) {
            this.activeCommentStyleElement.innerHTML = this.activeCommentStyle
        }

        const marginBoxFilterHTML = marginboxFilterTemplate({
            marginBoxes,
            filterOptions: this.filterOptions,
            docInfo: this.editor.docInfo
        })

        if (document.getElementById('margin-box-filter').innerHTML != marginBoxFilterHTML) {
            document.getElementById('margin-box-filter').innerHTML = marginBoxFilterHTML
        }

        return new Promise(resolve => {

            fastdom.measure(() => {
                // DOM read phase
                const marginBoxesDOM = document.querySelectorAll('#margin-box-container .margin-box')
                if (marginBoxesDOM.length !== referrers.length || !marginBoxesDOM.length) {
                    // Number of comment boxes and referrers differ.
                    // This isn't right. Abort.
                    resolve()
                    return
                }
                const bodyTop = document.body.getBoundingClientRect().top,
                    marginBoxPlacements = Array.from(marginBoxesDOM).map((mboxDOM, index) => {
                        const mboxDOMRect = mboxDOM.getBoundingClientRect()
                        return {
                            height: mboxDOMRect.height,
                            refPos: this.editor.view.coordsAtPos(referrers[index]).top - bodyTop
                        }
                    }),
                    firstActiveIndex = marginBoxes.findIndex(mBox => mBox.active),
                    firstActiveMboxPlacement = marginBoxPlacements[firstActiveIndex]

                let activeIndex = firstActiveIndex,
                    currentPos = 0
                while (activeIndex > -1) {
                    const mboxPlacement = marginBoxPlacements[activeIndex]
                    if (mboxPlacement.height === 0) {
                        mboxPlacement.pos = currentPos
                    } else if (mboxPlacement===firstActiveMboxPlacement) {
                        mboxPlacement.pos = mboxPlacement.refPos
                    } else {
                        mboxPlacement.pos = Math.min(
                            currentPos - 2 - mboxPlacement.height,
                            mboxPlacement.refPos
                    )
                    }
                    currentPos = mboxPlacement.pos
                    activeIndex--
                }
                if (firstActiveIndex > -1) {
                    currentPos = firstActiveMboxPlacement.pos + firstActiveMboxPlacement.height
                    activeIndex = firstActiveIndex + 1
                } else {
                    activeIndex = 0
                }

                while (activeIndex < marginBoxPlacements.length) {
                    const mboxPlacement = marginBoxPlacements[activeIndex]
                    mboxPlacement.pos = Math.max(currentPos + 2, mboxPlacement.refPos)
                    currentPos = mboxPlacement.pos + mboxPlacement.height
                    activeIndex++
                }

                const initialOffset = document.body.classList.contains('header-closed') ? 91 + 60 : 200 + 60
                let totalOffset = 0

                const marginBoxesPlacementStyle = marginBoxPlacements.map((mboxPlacement, index) => {
                    if (mboxPlacement.height === 0) {
                        return ''
                    }
                    const pos = mboxPlacement.pos - initialOffset
                    let css = ''
                    if (pos !== totalOffset) {
                        const topMargin = parseInt(pos - totalOffset)
                        css += `.margin-box:nth-of-type(${(index+1)}) {margin-top: ${topMargin}px;}\n`
                        totalOffset += topMargin
                    }
                    totalOffset += mboxPlacement.height + 2
                    return css
                }).join('')

                fastdom.mutate(() => {
                    //DOM write phase
                    if (document.getElementById('margin-box-placement-style').innerHTML != marginBoxesPlacementStyle) {
                        document.getElementById('margin-box-placement-style').innerHTML = marginBoxesPlacementStyle
                    }
                    if (this.editor.mod.comments.store.commentDuringCreation) {
                        this.editor.mod.comments.store.commentDuringCreation.inDOM = true
                    }
                    resolve()
                })
            })

        })

    }

    fnPosToPos(fnPos) {
        const fnIndex = this.editor.mod.footnotes.fnEditor.view.state.doc.resolve(fnPos).index(0),
            fnMarker = getFootnoteMarkers(this.editor.view.state)[fnIndex]

        return fnMarker.from
    }

    getMarginBoxes(
        node,
        pos,
        refPos,
        lastNode,
        lastNodeTracks,
        view,
        marginBoxes,
        referrers,
        selectedChanges,
        selection // Selection in main editor
    ) {

        if (node.attrs.help) { // Help/instruction margin boxes
            const helpBox = {
                type: 'help',
                data: {
                    active: selection.$anchor.node(2) === node ? true : false,
                    help: node.attrs.help
                }
            }
            marginBoxes.push(helpBox)
            referrers.push(refPos)
        }

        const commentIds = node.isInline || node.isLeaf ? this.editor.mod.comments.interactions.findCommentIds(node) : []

        const nodeTracks = node.attrs.track ?
            node.attrs.track.map(track => {
                const nodeTrack = {type: track.type, data: {user: track.user, username: track.username, date: track.date}}
                if (track.type==='block_change') {
                    nodeTrack.data.before = track.before
                }
                return nodeTrack
            }) :
            node.marks.filter(mark =>
                ['deletion', 'format_change'].includes(mark.type.name) ||
                (mark.type.name==='insertion' && !mark.attrs.approved)
            ).map(mark => ({type: mark.type.name, data: mark.attrs}))

        // Filter out trackmarks already present in the last node (if it's an inline node).
        const tracks = node.isInline === lastNode.isInline ?
            nodeTracks.filter(track =>
                !lastNodeTracks.find(
                    lastTrack =>
                        track.type===lastTrack.type &&
                        track.data.user===lastTrack.data.user &&
                        track.data.date===lastTrack.data.date &&
                        (
                            node.isInline || // block level changes almost always need new boxes
                            (node.type.name === 'paragraph' && lastNode.type.name === 'list_item' && lastTrack.type === 'insertion') // Don't show first paragraphs in list items.
                        ) &&
                        (
                            ['insertion', 'deletion'].includes(track.type) ||
                            (
                                track.type === 'format_change' &&
                                track.data.before.length===lastTrack.data.before.length &&
                                track.data.after.length===lastTrack.data.after.length &&
                                track.data.before.every(markName => lastTrack.data.before.includes(markName)) &&
                                track.data.after.every(markName => lastTrack.data.after.includes(markName))
                            ) ||
                            (
                                track.type === 'block_change' &&
                                track.data.before.type===lastTrack.data.before.type &&
                                track.data.before.attrs.level===lastTrack.data.before.attrs.level
                            )
                        )
                )
            ) :
            nodeTracks
        tracks.forEach(track => {
            marginBoxes.push(Object.assign({
                node,
                pos,
                view,
                active: selectedChanges[track.type] && selectedChanges[track.type].from === pos
            }, track))
            referrers.push(refPos)
        })

        if (!commentIds.length && !tracks.length) {
            return nodeTracks
        }
        commentIds.forEach(commentId => {
            const comment = this.editor.mod.comments.store.findComment(commentId)
            if (!comment || (!this.filterOptions.commentsResolved && comment.resolved)) {
                // We have no comment with this ID. Ignore the referrer.
                return
            }
            if (marginBoxes.find(marginBox => marginBox.data===comment)) {
                // comment already placed
                return
            }
            const active = comment.id === this.editor.mod.comments.interactions.activeCommentId
            if (this.filterOptions.comments) {
                if (active) {
                    this.activeCommentStyle +=
                        `.comment[data-id="${comment.id}"], .comment[data-id="${comment.id}"] .comment {background-color: ${this.commentColors.active} !important;}`
                } else if (comment.isMajor) {
                    this.activeCommentStyle +=
                        `#paper-editable .comment[data-id="${comment.id}"] {background-color: ${this.commentColors.isMajor};}`
                } else {
                    this.activeCommentStyle +=
                        `#paper-editable .comment[data-id="${comment.id}"] {background-color: ${this.commentColors.marker};}`
                }
            }
            marginBoxes.push({type: 'comment', data: comment, pos, view, active})
            referrers.push(refPos)
        })

        return nodeTracks
    }

}
<|endoftext|>


<commit_before>import React, {PropTypes} from 'react';
import Draggable from 'react-draggable';
import classNames from 'classnames';

import ButtonControls from '@ciscospark/react-component-button-controls';
import {ICON_TYPE_VIDEO_CROSS_OUTLINE, ICON_TYPE_MUTE_OUTLINE, ICON_TYPE_EXIT} from '@ciscospark/react-component-icon';
import Video from '@ciscospark/react-component-video';
import Avatar from '@ciscospark/react-component-avatar';

import styles from './styles.css';

// eslint-disable-next-line complexity
export default function ActiveCall({
  callState,
  localVideoPosition,
  onHangupClick,
  onLocalVideoDragStop,
  onStartSendingAudio,
  onStartSendingVideo,
  onStopSendingAudio,
  onStopSendingVideo,
  localMediaStream,
  remoteMediaStream,
  toPersonAvatar,
  toPersonName
}) {
  const connectedClass = remoteMediaStream && remoteMediaStream.active && styles.callConnected;
  const {
    sendingAudio,
    sendingVideo
  } = callState;

  const buttons = [
    {
      accessibilityLabel: `mute audio`,
      iconType: ICON_TYPE_MUTE_OUTLINE,
      buttonClassName: classNames(styles.audioButton, sendingAudio ? styles.audioStopSending : styles.audioStartSending),
      onClick: sendingAudio ? onStopSendingAudio : onStartSendingAudio
    },
    {
      accessibilityLabel: `mute video`,
      iconType: ICON_TYPE_VIDEO_CROSS_OUTLINE,
      buttonClassName: classNames(styles.videoButton, sendingVideo ? styles.videoStopSending : styles.videoStartSending),
      onClick: sendingVideo ? onStopSendingVideo : onStartSendingVideo
    },
    {
      accessibilityLabel: `hangup`,
      iconType: ICON_TYPE_EXIT,
      buttonClassName: styles.hangupButton,
      onClick: onHangupClick
    }
  ];

  let remoteView = ( // eslint-disable-line no-extra-parens
    <div className={classNames(styles.avatarView, `remote-avatar-view`)}>
      <Avatar image={toPersonAvatar} name={toPersonName} />

  );

  if (remoteMediaStream && remoteMediaStream.active && !callState.remoteVideoMuted) {
    remoteView = <Video srcObject={remoteMediaStream} />;
  }

  return (
    <div className={classNames(styles.callContainer, connectedClass, `call-container`)}>
      <div className={classNames(styles.remoteVideo, `remote-video`)}>
        { remoteView }

      {
        localMediaStream && localMediaStream.active && sendingVideo &&
        <Draggable
          bounds="parent"
          defaultClassNameDragging={styles.reactDraggableDragging}
          onStop={onLocalVideoDragStop}
          position={localVideoPosition}
        >
          <div className={classNames(styles.localVideo, `local-video`)}>
            <Video audioMuted srcObject={localMediaStream} />

        </Draggable>
      }
      {
        localMediaStream && localMediaStream.active &&
        <div className={classNames(styles.callControls, `call-controls`)}>
          <ButtonControls buttons={buttons} showLabels={false} />

      }

  );
}

ActiveCall.propTypes = {
  callState: PropTypes.object,
  localMediaStream: PropTypes.object,
  localVideoPosition: PropTypes.object,
  onHangupClick: PropTypes.func.isRequired,
  onLocalVideoDragStop: PropTypes.func,
  onStartSendingAudio: PropTypes.func.isRequired,
  onStartSendingVideo: PropTypes.func.isRequired,
  onStopSendingAudio: PropTypes.func.isRequired,
  onStopSendingVideo: PropTypes.func.isRequired,
  remoteMediaStream: PropTypes.object,
  toPersonAvatar: PropTypes.string,
  toPersonName: PropTypes.string
};
<commit_msg>fix(widget-meet): capitalize accessibility labels for control buttons<commit_after>import React, {PropTypes} from 'react';
import Draggable from 'react-draggable';
import classNames from 'classnames';

import ButtonControls from '@ciscospark/react-component-button-controls';
import {ICON_TYPE_VIDEO_CROSS_OUTLINE, ICON_TYPE_MUTE_OUTLINE, ICON_TYPE_EXIT} from '@ciscospark/react-component-icon';
import Video from '@ciscospark/react-component-video';
import Avatar from '@ciscospark/react-component-avatar';

import styles from './styles.css';

// eslint-disable-next-line complexity
export default function ActiveCall({
  callState,
  localVideoPosition,
  onHangupClick,
  onLocalVideoDragStop,
  onStartSendingAudio,
  onStartSendingVideo,
  onStopSendingAudio,
  onStopSendingVideo,
  localMediaStream,
  remoteMediaStream,
  toPersonAvatar,
  toPersonName
}) {
  const connectedClass = remoteMediaStream && remoteMediaStream.active && styles.callConnected;
  const {
    sendingAudio,
    sendingVideo
  } = callState;

  const buttons = [
    {
      accessibilityLabel: `Mute Audio`,
      iconType: ICON_TYPE_MUTE_OUTLINE,
      buttonClassName: classNames(styles.audioButton, sendingAudio ? styles.audioStopSending : styles.audioStartSending),
      onClick: sendingAudio ? onStopSendingAudio : onStartSendingAudio
    },
    {
      accessibilityLabel: `Mute Video`,
      iconType: ICON_TYPE_VIDEO_CROSS_OUTLINE,
      buttonClassName: classNames(styles.videoButton, sendingVideo ? styles.videoStopSending : styles.videoStartSending),
      onClick: sendingVideo ? onStopSendingVideo : onStartSendingVideo
    },
    {
      accessibilityLabel: `Hangup`,
      iconType: ICON_TYPE_EXIT,
      buttonClassName: styles.hangupButton,
      onClick: onHangupClick
    }
  ];

  let remoteView = ( // eslint-disable-line no-extra-parens
    <div className={classNames(styles.avatarView, `remote-avatar-view`)}>
      <Avatar image={toPersonAvatar} name={toPersonName} />

  );

  if (remoteMediaStream && remoteMediaStream.active && !callState.remoteVideoMuted) {
    remoteView = <Video srcObject={remoteMediaStream} />;
  }

  return (
    <div className={classNames(styles.callContainer, connectedClass, `call-container`)}>
      <div className={classNames(styles.remoteVideo, `remote-video`)}>
        { remoteView }

      {
        localMediaStream && localMediaStream.active && sendingVideo &&
        <Draggable
          bounds="parent"
          defaultClassNameDragging={styles.reactDraggableDragging}
          onStop={onLocalVideoDragStop}
          position={localVideoPosition}
        >
          <div className={classNames(styles.localVideo, `local-video`)}>
            <Video audioMuted srcObject={localMediaStream} />

        </Draggable>
      }
      {
        localMediaStream && localMediaStream.active &&
        <div className={classNames(styles.callControls, `call-controls`)}>
          <ButtonControls buttons={buttons} showLabels={false} />

      }

  );
}

ActiveCall.propTypes = {
  callState: PropTypes.object,
  localMediaStream: PropTypes.object,
  localVideoPosition: PropTypes.object,
  onHangupClick: PropTypes.func.isRequired,
  onLocalVideoDragStop: PropTypes.func,
  onStartSendingAudio: PropTypes.func.isRequired,
  onStartSendingVideo: PropTypes.func.isRequired,
  onStopSendingAudio: PropTypes.func.isRequired,
  onStopSendingVideo: PropTypes.func.isRequired,
  remoteMediaStream: PropTypes.object,
  toPersonAvatar: PropTypes.string,
  toPersonName: PropTypes.string
};
<|endoftext|>


<commit_before>// document.addEventListener( 'turbolinks:load', function() {
//     flexdatalistInit();
// });
//
//
//
// function flexdatalistInit(el = $('body')) {
//
//     el.find('input.flexdatalist').flexdatalist();
//
//     el.find('input.flexdatalist[data-units]').on( 'change:flexdatalist', function(event, set, options) {
//         $($(this).data('units')).data( 'data', ( 'app/quantities/' + set.value + '/units_of_measurement.json?locale=' + $('p#lang').text() ) ).flexdatalist().attr('disabled', 'false');
//     });
//
// };
<commit_msg>testing<commit_after>document.addEventListener( 'turbolinks:load', function() {
    flexdatalistInit();
});

function flexdatalistInit(el = $('body')) {

    el.find('input.flexdatalist').flexdatalist();

    el.find('input.flexdatalist[data-units]').on( 'change:flexdatalist', function(event, set, options) {
        $($(this).data('units')).data( 'data', ( 'app/quantities/' + set.value + '/units_of_measurement.json?locale=' + $('p#lang').text() ) ).flexdatalist().attr('disabled', 'false');
    });

};
<|endoftext|>


<commit_before>/**
  If a row begins with HTML tags, don't parse it.
**/
var blockTags = ['address', 'article', 'aside', 'audio', 'blockquote', 'canvas', 'dd', 'div',
                 'dl', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3',
                 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'iframe', 'noscript', 'ol', 'output',
                 'p', 'pre', 'section', 'table', 'tfoot', 'ul', 'video'],

    splitAtLast = function(tag, block, next, first) {
      var endTag = "</" + tag + ">",
          endTagIndex = first ? block.indexOf(endTag) : block.lastIndexOf(endTag);

      if (endTagIndex !== -1) {
        endTagIndex += endTag.length;

        var leading = block.substr(0, endTagIndex),
            trailing = block.substr(endTagIndex).replace(/^\s+/, '');

        if (trailing.length) {
          next.unshift(trailing);
        }

        return [ leading ];
      }
    };

Discourse.Dialect.registerBlock('html', function(block, next) {
  var split;

  // Fix manual blockquote paragraphing even though it's not strictly correct
  if (block.search(/[^\s]+<blockquote/) === 0) {
    console.log(/[^\s]+<blockquote/.exec(block));
    split = splitAtLast('blockquote', block, next, true);
    if (split) { return this.processInline(split[0]); }
  }

  var m = /^<([^>]+)\>/.exec(block);
  if (m && m[1]) {
    var tag = m[1].split(/\s/);
    if (tag && tag[0] && blockTags.indexOf(tag[0]) !== -1) {
      split = splitAtLast(tag[0], block, next);
      if (split) { return split; }
      return [ block.toString() ];
    }
  }
});
<commit_msg>FIX: Removes `console.log`<commit_after>/**
  If a row begins with HTML tags, don't parse it.
**/
var blockTags = ['address', 'article', 'aside', 'audio', 'blockquote', 'canvas', 'dd', 'div',
                 'dl', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3',
                 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'iframe', 'noscript', 'ol', 'output',
                 'p', 'pre', 'section', 'table', 'tfoot', 'ul', 'video'],

    splitAtLast = function(tag, block, next, first) {
      var endTag = "</" + tag + ">",
          endTagIndex = first ? block.indexOf(endTag) : block.lastIndexOf(endTag);

      if (endTagIndex !== -1) {
        endTagIndex += endTag.length;

        var leading = block.substr(0, endTagIndex),
            trailing = block.substr(endTagIndex).replace(/^\s+/, '');

        if (trailing.length) {
          next.unshift(trailing);
        }

        return [ leading ];
      }
    };

Discourse.Dialect.registerBlock('html', function(block, next) {
  var split;

  // Fix manual blockquote paragraphing even though it's not strictly correct
  if (block.search(/[^\s]+<blockquote/) === 0) {
    split = splitAtLast('blockquote', block, next, true);
    if (split) { return this.processInline(split[0]); }
  }

  var m = /^<([^>]+)\>/.exec(block);
  if (m && m[1]) {
    var tag = m[1].split(/\s/);
    if (tag && tag[0] && blockTags.indexOf(tag[0]) !== -1) {
      split = splitAtLast(tag[0], block, next);
      if (split) { return split; }
      return [ block.toString() ];
    }
  }
});
<|endoftext|>


<commit_before>/**
 * The Slide view.
 */
define([
  'jquery',
  'backbone',
  'underscore',
  'mps',
  'handlebars',
  'text!landing/templates/paginationSlider.handlebars',
], function($,Backbone, _,mps, Handlebars, tpl) {

  'use strict';
  Handlebars.registerHelper('for', function(from, to, incr, block) {
    var accum = '';
    for(var i = from; i < to; i += incr)
      accum += block.fn(i);
    return accum;
  });

  // PAGINATION
  var PaginationView = Backbone.View.extend({

    el: '#paginationView',

    template: Handlebars.compile(tpl),

    events: {
      'click li' : '_navigateTo'
    },

    initialize: function(model){
      this.len = model.len;
      this.render();
      this._setListeners()
    },

    _setListeners: function(){
      mps.subscribe('slider:index', _.bind(function(index){
        this._changeCurrent(index);
      },this));
    },

    render: function(){
      this.$el.html(this.template({len: this.len}));
      this.$pages = this.$el.find('li');
      this._changeCurrent(0);
    },

    _changeCurrent: function(index){
      this.$pages.eq(index).addClass('current').siblings().removeClass('current');
    },

    _navigateTo: function(e){
      var index = $(e.currentTarget).index();
      mps.publish('slider:change',[index]);
    }
  })

  // SLIDER
  var SlideView = Backbone.View.extend({

    el: '#main-slider',

    events: {
      'click #get-started' : 'getStarted',
      'click #go-to-apps' : 'goToApps',
      'click .gotomap' : 'gotoMap'
    },

    initialize: function() {
      //Init
      this.$slides = $('.slide');
      this.$getStarted = $('#get-started');
      this.len = this.$slides.length;
      this.position = 0;
      this.interval;
      this.timeTimeout = 1001; // Remember change this value when you change time in landing scss

      //Init Pagination
      this.pagination = new PaginationView({ len: this.len });

      //Inits
      this._setListeners();
      this._autoSlider();
    },

    _setListeners: function(){
      $('html').on('click',_.bind(this._onHtmlClick,this));
      mps.subscribe('slider:change', _.bind(function(index){
        this.stopAutoSlider();
        this.changePosition(index);
        this.slide();
      },this));
    },

    _autoSlider: function() {
      this.interval = setInterval(_.bind(function(){
        this.changePosition('next');
        this.slide();
      },this),5000)
    },

    stopAutoSlider: function() {
      clearInterval(this.interval);
    },

    changePosition: function(dir) {
      this.positionOld = this.position;
      switch(dir){
        case 'prev':
          (this.position === 0) ? this.position = this.len - 1 : this.position--;
        break;
        case 'next':
          (this.position === this.len - 1) ? this.position = 0 : this.position++;
        break;
        default:
          this.position = dir
        break;
      }
      mps.publish('slider:index',[this.position]);
    },

    slide: function() {
      this.$slides.eq(this.position).addClass('current');
      this.$slides.eq(this.positionOld).addClass('leave').removeClass('current')
      setTimeout(_.bind(function(){
        this.$slides.eq(this.position).siblings().removeClass('leave');
      },this),this.timeTimeout)
    },

    getStarted: function(e){
      e.stopPropagation();
      $(e.currentTarget).toggleClass('active');
    },

    /**
     * Closes submenu tooltip
     * Check the click target is not the dialog itself.
     *
     * @param  {Object} e Event
     */
    _onHtmlClick: function(e) {
      if (!$(e.target).hasClass('submenu-tooltip') && this.$getStarted.hasClass('active')) {
        this.$getStarted.removeClass('active');
      }
    },

    goToApps: function(e){
      e.preventDefault();
      var posY = $($(e.currentTarget).attr('href')).offset().top;
      $('html,body').animate({scrollTop: posY},500);
    },

    gotoMap: function(e) {
      e.preventDefault();
      e.stopPropagation();

      var $target = $(e.target);

      if (!$(e.target).hasClass('gotomap')) {
        $target = $(e.target).parent();
      }

      if ($target.data('dialog') === true) {
        var dialog = JSON.stringify(
        {
          "display": true,
          "type" : $target.data('dialog')
        });

        sessionStorage.setItem('DIALOG', dialog);
      }
      console.log($target.data('ga'))
      ga('send', 'event', 'Home', 'Click', $target.data('ga'))
      location.assign($target.attr('href'));
    }

  });

  return SlideView;

});
<commit_msg>Cleaning<commit_after>/**
 * The Slide view.
 */
define([
  'jquery',
  'backbone',
  'underscore',
  'mps',
  'handlebars',
  'text!landing/templates/paginationSlider.handlebars',
], function($,Backbone, _,mps, Handlebars, tpl) {

  'use strict';
  Handlebars.registerHelper('for', function(from, to, incr, block) {
    var accum = '';
    for(var i = from; i < to; i += incr)
      accum += block.fn(i);
    return accum;
  });

  // PAGINATION
  var PaginationView = Backbone.View.extend({

    el: '#paginationView',

    template: Handlebars.compile(tpl),

    events: {
      'click li' : '_navigateTo'
    },

    initialize: function(model){
      this.len = model.len;
      this.render();
      this._setListeners()
    },

    _setListeners: function(){
      mps.subscribe('slider:index', _.bind(function(index){
        this._changeCurrent(index);
      },this));
    },

    render: function(){
      this.$el.html(this.template({len: this.len}));
      this.$pages = this.$el.find('li');
      this._changeCurrent(0);
    },

    _changeCurrent: function(index){
      this.$pages.eq(index).addClass('current').siblings().removeClass('current');
    },

    _navigateTo: function(e){
      var index = $(e.currentTarget).index();
      mps.publish('slider:change',[index]);
    }
  })

  // SLIDER
  var SlideView = Backbone.View.extend({

    el: '#main-slider',

    events: {
      'click #get-started' : 'getStarted',
      'click #go-to-apps' : 'goToApps',
      'click .gotomap' : 'gotoMap'
    },

    initialize: function() {
      //Init
      this.$slides = $('.slide');
      this.$getStarted = $('#get-started');
      this.len = this.$slides.length;
      this.position = 0;
      this.interval;
      this.timeTimeout = 1001; // Remember change this value when you change time in landing scss

      //Init Pagination
      this.pagination = new PaginationView({ len: this.len });

      //Inits
      this._setListeners();
      this._autoSlider();
    },

    _setListeners: function(){
      $('html').on('click',_.bind(this._onHtmlClick,this));
      mps.subscribe('slider:change', _.bind(function(index){
        this.stopAutoSlider();
        this.changePosition(index);
        this.slide();
      },this));
    },

    _autoSlider: function() {
      this.interval = setInterval(_.bind(function(){
        this.changePosition('next');
        this.slide();
      },this),5000)
    },

    stopAutoSlider: function() {
      clearInterval(this.interval);
    },

    changePosition: function(dir) {
      this.positionOld = this.position;
      switch(dir){
        case 'prev':
          (this.position === 0) ? this.position = this.len - 1 : this.position--;
        break;
        case 'next':
          (this.position === this.len - 1) ? this.position = 0 : this.position++;
        break;
        default:
          this.position = dir
        break;
      }
      mps.publish('slider:index',[this.position]);
    },

    slide: function() {
      this.$slides.eq(this.position).addClass('current');
      this.$slides.eq(this.positionOld).addClass('leave').removeClass('current')
      setTimeout(_.bind(function(){
        this.$slides.eq(this.position).siblings().removeClass('leave');
      },this),this.timeTimeout)
    },

    getStarted: function(e){
      e.stopPropagation();
      $(e.currentTarget).toggleClass('active');
    },

    /**
     * Closes submenu tooltip
     * Check the click target is not the dialog itself.
     *
     * @param  {Object} e Event
     */
    _onHtmlClick: function(e) {
      if (!$(e.target).hasClass('submenu-tooltip') && this.$getStarted.hasClass('active')) {
        this.$getStarted.removeClass('active');
      }
    },

    goToApps: function(e){
      e.preventDefault();
      var posY = $($(e.currentTarget).attr('href')).offset().top;
      $('html,body').animate({scrollTop: posY},500);
    },

    gotoMap: function(e) {
      e.preventDefault();
      e.stopPropagation();

      var $target = $(e.target);

      if (!$(e.target).hasClass('gotomap')) {
        $target = $(e.target).parent();
      }

      if ($target.data('dialog') === true) {
        var dialog = JSON.stringify(
        {
          "display": true,
          "type" : $target.data('dialog')
        });

        sessionStorage.setItem('DIALOG', dialog);
      }
      ga('send', 'event', 'Home', 'Click', $target.data('ga'))
      location.assign($target.attr('href'));
    }

  });

  return SlideView;

});
<|endoftext|>


<commit_before>
define(['log', 'jquery'], function (Global, $) {
  'use strict';

  var defaults = {
    // Setup
    triggerEl: '.collapsible',
    targetEl: '.collapsible-section',
    targetType: 'class', // class / href / data-attr
    activeClass: 'is-on',
    inactiveClass: 'is-off',
    closeOffFocus: false,
    parentWrapper: false,
    accordion: false,
    showOnlyFirst: false,

    // Display options
    showIcon: false,
    headingIcon: '{{txt}}',
    useButton: false,

    // Localised text strings
    textString: {
      showThisSection: 'Show this section',
      hideThisSection: 'Hide this section'
    }
  };

  $.fn.swapClass = function(from, to){
    this.removeClass(from).addClass(to);
  };

  var Collapsible = function(opts){
    this.o = $.extend({}, defaults, opts);
    this.sections = [];
    this.selected = false;

    var _this = this,
        triggers = $(this.o.triggerEl),
        l = triggers.length,
        i = 0;

    if(l === 0){
      return Global.warn('mas_collapsible => no trigger elements in page: ' + this.o.triggerEl);
    }

    for(i; i<l; i++){
      this._setupEach.call(this, i, triggers[i]);
    }

    if(this.o.closeOffFocus){
      this.$parent = $(this.o.parentWrapper);

      if(!this.o.parentWrapper || !this.$parent.length) {
        Global.warn('options.parentWrapper should be set & valid for closeOffFocus to work properly');
        return;
      }

      this.$parent.on('focusout', function(){
        setTimeout(function(){
          if( _this.$parent.find(document.activeElement).length === 0 && _this.selected !== false){
            _this.hide(_this.selected);
          }
        },300);
      });
    }
  };

  Collapsible.prototype._modifyButtonHTML = function(i){
    var trigger = this.sections[i].trigger,
        icon = (this.o.showIcon)? trigger.prepend(this.o.headingIcon.replace('{{txt}}', this.o.textString.showThisSection)): '';

    if(this.o.useButton){
      var buttonTitle = trigger.text();

      if(trigger[0].nodeName === 'A'){
        // Anchor => replace elemnt
        var newEl = $('' + icon + buttonTitle + '');
        // add new
        trigger.after(newEl);
        // remove old
        trigger.remove();
        trigger = newEl;
      }else{
        // Anything else => insert button inside
        trigger.html('<button class="button--unstyled">' + icon + buttonTitle  + '</button>');
      }
    }else{
      // Use aria-role
      trigger.attr('aria-role','button');
      trigger.attr('tabindex', '0');
      trigger.prepend(icon);
    }

    if(this.o.showIcon){
      this.sections[i].icon = trigger.find('.visually-hidden');
    }
  };

  Collapsible.prototype.getTarget = function($el){
    switch(this.o.targetType){
    case 'class':
      return $el.next(this.o.targetEl);
    case 'href':
      var href = $el.attr('href'),
        $t = $(href);
      return ($t.length)? $t : false;
    default:
      return false;
    }
  };

  Collapsible.prototype._setupEach = function(i,el){
    var $el = $(el);
    var _this = this;

    this.sections[i] = {
      index: i,
      trigger: $el,
      target: this.getTarget($el),
      hidden: !$el.hasClass(this.o.activeClass)
    };
    // Dont modify or bind events if no target element
    if(!this.sections[i].target.length) return;

    // Set show / hide states based on options
    if(this.o.showOnlyFirst){
      this.sections[i].hidden = (i === 0)? false : true;
    }

    if(this.o.accordion){
      if(this.selected === false && !this.sections[i].hidden){
      }else{
        this.sections[i].hidden = true;
      }
    }

    // Update Button HTML to make accessible
    this._modifyButtonHTML(i);

    // Set initial state
    this.toggle(!this.sections[i].hidden,i);

    // Bind events
    this.sections[i].trigger.on('click', i, function(e){
      e.preventDefault();
      _this.toggle(_this.sections[i].hidden, i);
    });

    // Accessibility support for spacebar
    this.sections[i].trigger.on('keypress', function(e){
      if(e.which === 32 && _this.sections[i].trigger[0].nodeName !== 'BUTTON') {
        e.preventDefault();
        _this.sections[i].trigger.trigger('click');
      }
    });
  };

  Collapsible.prototype.toggle = function(show,i){
    if(show){
      this.show(i);
    }else{
      this.hide(i);
    }
  };

  Collapsible.prototype.show = function(i){
    var item = this.sections[i];
    if(this.o.showIcon) item.icon.text(this.o.textString.hideThisSection);
    item.trigger.swapClass(this.o.inactiveClass, this.o.activeClass);
    item.target.swapClass(this.o.inactiveClass, this.o.activeClass);
    item.target.attr('aria-hidden', 'false');
    item.hidden = false;

    if (this.o.accordion && (this.selected !== false && this.selected !== i)){
      this.hide(this.selected);
    }
    this.selected = i;
  };

  Collapsible.prototype.hide = function(i){
    var item = this.sections[i];
    if(this.o.showIcon) item.icon.text(this.o.textString.showThisSection);
    item.trigger.swapClass(this.o.activeClass, this.o.inactiveClass);
    item.target.swapClass(this.o.activeClass, this.o.inactiveClass);
    item.target.attr('aria-hidden', 'true');
    item.hidden = true;
  };

  return Collapsible;
});
<commit_msg>fix aria-hidden on primary nav<commit_after>
define(['log', 'jquery'], function (Global, $) {
  'use strict';

  var defaults = {
    // Setup
    triggerEl: '.collapsible',
    targetEl: '.collapsible-section',
    targetType: 'class', // class / href / data-attr
    activeClass: 'is-on',
    inactiveClass: 'is-off',
    closeOffFocus: false,
    parentWrapper: false,
    accordion: false,
    showOnlyFirst: false,

    // Display options
    showIcon: false,
    headingIcon: '{{txt}}',
    useButton: false,

    // Localised text strings
    textString: {
      showThisSection: 'Show this section',
      hideThisSection: 'Hide this section'
    }
  };

  $.fn.swapClass = function(from, to){
    this.removeClass(from).addClass(to);
  };

  var Collapsible = function(opts){
    this.o = $.extend({}, defaults, opts);
    this.sections = [];
    this.selected = false;

    var _this = this,
        triggers = $(this.o.triggerEl),
        l = triggers.length,
        i = 0;

    if(l === 0){
      return Global.warn('mas_collapsible => no trigger elements in page: ' + this.o.triggerEl);
    }

    for(i; i<l; i++){
      this._setupEach.call(this, i, triggers[i]);
    }

    if(this.o.closeOffFocus){
      this.$parent = $(this.o.parentWrapper);

      if(!this.o.parentWrapper || !this.$parent.length) {
        Global.warn('options.parentWrapper should be set & valid for closeOffFocus to work properly');
        return;
      }

      this.$parent.on('focusout', function(){
        setTimeout(function(){
          if( _this.$parent.find(document.activeElement).length === 0 && _this.selected !== false){
            _this.hide(_this.selected);
          }
        },300);
      });
    }
  };

  Collapsible.prototype._modifyButtonHTML = function(i){
    var trigger = this.sections[i].trigger,
        icon = (this.o.showIcon)? trigger.prepend(this.o.headingIcon.replace('{{txt}}', this.o.textString.showThisSection)): '';

    if(this.o.useButton){
      var buttonTitle = trigger.text();

      if(trigger[0].nodeName === 'A'){
        // Anchor => replace elemnt
        var newEl = $('' + icon + buttonTitle + '');
        // add new
        trigger.after(newEl);
        // remove old
        trigger.remove();
        trigger = newEl;
      }else{
        // Anything else => insert button inside
        trigger.html('<button class="button--unstyled">' + icon + buttonTitle  + '</button>');
      }
    }else{
      // Use aria-role
      trigger.attr('aria-role','button');
      trigger.attr('tabindex', '0');
      trigger.prepend(icon);
    }

    if(this.o.showIcon){
      this.sections[i].icon = trigger.find('.visually-hidden');
    }
  };

  Collapsible.prototype.getTarget = function($el){
    switch(this.o.targetType){
    case 'class':
      return $el.next(this.o.targetEl);
    case 'href':
      var href = $el.attr('href'),
        $t = $(href);
      return ($t.length)? $t : false;
    default:
      return false;
    }
  };

  Collapsible.prototype._testHidden = function(target){
    return !(target.hasClass(this.o.activeClass) || target.is(':visible'));
  };

  Collapsible.prototype._setupEach = function(i,el){
    var $el = $(el),
      _this = this,
      _target = this.getTarget($el);

    this.sections[i] = {
      index: i,
      trigger: $el,
      target: _target,
      hidden: this._testHidden(_target)
    };
    // Dont modify or bind events if no target element
    if(!this.sections[i].target.length) return;

    // Set show / hide states based on options
    if(this.o.showOnlyFirst){
      this.sections[i].hidden = (i === 0)? false : true;
    }

    if(this.o.accordion){
      if(this.selected === false && !this.sections[i].hidden){
      }else{
        this.sections[i].hidden = true;
      }
    }

    // Update Button HTML to make accessible
    this._modifyButtonHTML(i);

    // Set initial state
    this.toggle(!this.sections[i].hidden,i);

    // Bind events
    this.sections[i].trigger.on('click', i, function(e){
      e.preventDefault();
      _this.toggle(_this.sections[i].hidden, i);
    });

    // Accessibility support for spacebar
    this.sections[i].trigger.on('keypress', function(e){
      if(e.which === 32 && _this.sections[i].trigger[0].nodeName !== 'BUTTON') {
        e.preventDefault();
        _this.sections[i].trigger.trigger('click');
      }
    });
  };

  Collapsible.prototype.toggle = function(show,i){
    if(show){
      this.show(i);
    }else{
      this.hide(i);
    }
  };

  Collapsible.prototype.show = function(i){
    var item = this.sections[i];
    if(this.o.showIcon) item.icon.text(this.o.textString.hideThisSection);
    item.trigger.swapClass(this.o.inactiveClass, this.o.activeClass);
    item.target.swapClass(this.o.inactiveClass, this.o.activeClass);
    item.target.attr('aria-hidden', 'false');
    item.hidden = false;

    if (this.o.accordion && (this.selected !== false && this.selected !== i)){
      this.hide(this.selected);
    }
    this.selected = i;
  };

  Collapsible.prototype.hide = function(i){
    var item = this.sections[i];
    if(this.o.showIcon) item.icon.text(this.o.textString.showThisSection);
    item.trigger.swapClass(this.o.activeClass, this.o.inactiveClass);
    item.target.swapClass(this.o.activeClass, this.o.inactiveClass);
    item.target.attr('aria-hidden', 'true');
    item.hidden = true;
  };

  return Collapsible;
});
<|endoftext|>


<commit_before>import Component from 'framework/component';
import Decorator from 'framework/decorator';

import FeedStore from 'shreds/stores/feed';
import ShredsDispatcher from 'shreds/dispatcher';
import FeedActions from 'shreds/actions/feed';
import NavigationActions from 'shreds/actions/navigation';

const FeedComponent = Component.extend({
  template: Component.template('feed'),

  data() { return FeedStore.getData(); },

  partials: {
    newsitems: Component.template('feeds/_newsitems')
  },

  oninit() {
    FeedStore.addChangeListener((ev, payload) => {
      this.assign(payload.data);
      Decorator.do('setTitle', this.get('title'));
    });

    this.on('mark-as-read', (ev, fid, nid) => {
      FeedActions.markAsRead(fid, nid);
      return false;
    });

    this.on('navigate', (ev, path, cid, fid) => {
      NavigationActions.navigate(path, cid, fid);
    });

    Decorator.do('setTitle', this.get('title'));
  }
});

export default FeedComponent;
<commit_msg>Remove unused import<commit_after>import Component from 'framework/component';
import Decorator from 'framework/decorator';

import FeedStore from 'shreds/stores/feed';
import FeedActions from 'shreds/actions/feed';
import NavigationActions from 'shreds/actions/navigation';

const FeedComponent = Component.extend({
  template: Component.template('feed'),

  data() { return FeedStore.getData(); },

  partials: {
    newsitems: Component.template('feeds/_newsitems')
  },

  oninit() {
    FeedStore.addChangeListener((ev, payload) => {
      this.assign(payload.data);
      Decorator.do('setTitle', this.get('title'));
    });

    this.on('mark-as-read', (ev, fid, nid) => {
      FeedActions.markAsRead(fid, nid);
      return false;
    });

    this.on('navigate', (ev, path, cid, fid) => {
      NavigationActions.navigate(path, cid, fid);
    });

    Decorator.do('setTitle', this.get('title'));
  }
});

export default FeedComponent;
<|endoftext|>


<commit_before>import Ember from 'ember';
import { v4 } from 'ember-uuid';

const { Component, computed, run: { debounce }, testing } = Ember;

export default Component.extend({

  editor: null,

  // Ensure any changes to the parser rules are set in the sanitizer @ services/sanitizer.js
  standardParserRules: {
    tags: {
      'p'      : 1,
      'b'      : { 'rename_tag': 'string' },
      'strong' : 1,
      'i'      : { 'rename_tag': 'em' },
      'em'     : 1,
      'u'      : 1,
      'ol'     : 1,
      'li'     : 1,
      'ul'     : 1,
      'a'      : {
        'check_attributes': {
          'href': 'url'
        },
        'set_attributes': {
          'rel'    : 'nofollow',
          'target' : '_blank'
        }
      }
    }
  },

  textareaIdGenerated: computed('textareaId', function() {
    return this.get('textareaId') ? this.get('textareaId') : v4();
  }),

  didInsertElement() {
    this._super(...arguments);
    this.$('.button')
      .popup({
        inline    : true,
        variation : 'tiny'
      });

    // Don't initialize wysihtml5 when app is in testing mode
    if (!testing) {
      this.editor = new wysihtml5.Editor(this.$(`#${this.get('textareaIdGenerated')}`)[0], {
        toolbar     : this.$(`#${this.get('textareaIdGenerated')}-toolbar`)[0],
        parserRules : this.get('standardParserRules')
      });

      const updateValue = () => {
        debounce(this, () => {
          this.set('value', this.editor.getValue());
        }, 400);
      };

      this.editor.on('interaction', updateValue);
      this.editor.on('aftercommand:composer', updateValue);
    }
  },

  willDestroyElement() {
    this._super(...arguments);
    if (this.editor) {
      this.editor.destroy();
    }
    this.$('.button').popup('destroy');
  }
});
<commit_msg>Implement two-way binding for rich-text-editor value<commit_after>import Ember from 'ember';
import { v4 } from 'ember-uuid';

const { Component, computed, run: { debounce }, testing, observer } = Ember;

export default Component.extend({

  editor: null,

  // Ensure any changes to the parser rules are set in the sanitizer @ services/sanitizer.js
  standardParserRules: {
    tags: {
      'p'      : 1,
      'b'      : { 'rename_tag': 'string' },
      'strong' : 1,
      'i'      : { 'rename_tag': 'em' },
      'em'     : 1,
      'u'      : 1,
      'ol'     : 1,
      'li'     : 1,
      'ul'     : 1,
      'a'      : {
        'check_attributes': {
          'href': 'url'
        },
        'set_attributes': {
          'rel'    : 'nofollow',
          'target' : '_blank'
        }
      }
    }
  },

  valueObserver: observer('value', function() {
    if (this.get('editor') && this.get('value') !== this.get('_value')) {
      this.get('editor').setValue(this.get('value'));
    }
  }),

  textareaIdGenerated: computed('textareaId', function() {
    return this.get('textareaId') ? this.get('textareaId') : v4();
  }),

  didInsertElement() {
    this._super(...arguments);
    this.set('_value', this.get('value'));
    this.$('.button')
      .popup({
        inline    : true,
        variation : 'tiny'
      });

    // Don't initialize wysihtml5 when app is in testing mode
    if (!testing) {
      this.editor = new wysihtml5.Editor(this.$(`#${this.get('textareaIdGenerated')}`)[0], {
        toolbar     : this.$(`#${this.get('textareaIdGenerated')}-toolbar`)[0],
        parserRules : this.get('standardParserRules')
      });

      const updateValue = () => {
        debounce(this, () => {
          const value = this.editor.getValue();
          this.setProperties({ _value: value, value });
        }, 200);
      };

      this.editor.on('interaction', updateValue);
      this.editor.on('aftercommand:composer', updateValue);
    }
  },

  willDestroyElement() {
    this._super(...arguments);
    if (this.editor) {
      this.editor.destroy();
    }
    this.$('.button').popup('destroy');
  }
});
<|endoftext|>


<commit_before>import React, { Component } from 'react';

import Sessions from './Sessions';
import Empty from './Empty';
import Create from './Create';

class Index extends Component {
  state = {
    page: 0
  };

  switchPage(page) {
    this.setState({ page });
  }

  render() {
    const { page } = this.state;

    switch (page) {
      case 0:
        return <Sessions />;
      case 1:
        return <Empty />;
      case 2:
        return <Create />;
      default:
        break;
    }
  }
}

export default Index;
<commit_msg>Add prop types + fixes<commit_after>import React, { Component } from 'react';
import { array } from 'prop-types';

import Sessions from './Sessions';
import Empty from './Empty';
import Create from './Create';

class Index extends Component {
  state = {
    page: this.props.sessions.length > 0 ? 0 : 1
  };

  switchPage(page) {
    this.setState({ page });
  }

  render() {
    const { page } = this.state;

    switch (page) {
      case 0:
        return <Sessions />;
      case 1:
        return <Empty />;
      case 2:
        return <Create />;
      default:
        break;
    }
  }
}

Index.propTypes = {
  sessions: array
};

Index.defaultProps = {
  sessions: []
};

export default Index;
<|endoftext|>


<commit_before>import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { isPresent } from '@ember/utils';
import { dropTask, restartableTask } from 'ember-concurrency-decorators';

export default class LearnergroupInstructorManager extends Component {
  @tracked availableInstructorGroups = [];
  @tracked instructors = [];
  @tracked instructorGroups = [];

  @restartableTask
  *load(element, [learnerGroup]) {
    if (isPresent(learnerGroup)) {
      const instructors = yield learnerGroup.get('instructors');
      const instructorGroups = yield learnerGroup.get('instructorGroups');
      const cohort = yield learnerGroup.get('cohort');
      const programYear = yield cohort.get('programYear');
      const program = yield programYear.get('program');
      const school = yield program.get('school');
      const availableInstructorGroups = yield school.get('instructorGroups');

      this.instructors = instructors.toArray();
      this.instructorGroups = instructorGroups.toArray();
      this.availableInstructorGroups = availableInstructorGroups.toArray();
    }
  }

  @action
  addInstructor(user) {
    this.instructors = [...this.instructors, user];
  }

  @action
  addInstructorGroup(instructorGroup) {
    this.instructorGroups = [...this.instructorGroups, instructorGroup];
  }

  @action
  removeInstructor(user) {
    this.instructors = this.instructors.filter(instructor => instructor !== user);
  }

  @action
  removeInstructorGroup(instructorGroup) {
    this.instructorGroups = this.instructorGroups.filter(group => group !== instructorGroup);
  }

  @dropTask
  *saveChanges() {
    yield this.args.save(this.instructors, this.instructorGroups);
  }
}
<commit_msg>rm reduntant blank line.<commit_after>import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { isPresent } from '@ember/utils';
import { dropTask, restartableTask } from 'ember-concurrency-decorators';

export default class LearnergroupInstructorManager extends Component {
  @tracked availableInstructorGroups = [];
  @tracked instructors = [];
  @tracked instructorGroups = [];

  @restartableTask
  *load(element, [learnerGroup]) {
    if (isPresent(learnerGroup)) {
      const instructors = yield learnerGroup.get('instructors');
      const instructorGroups = yield learnerGroup.get('instructorGroups');
      const cohort = yield learnerGroup.get('cohort');
      const programYear = yield cohort.get('programYear');
      const program = yield programYear.get('program');
      const school = yield program.get('school');
      const availableInstructorGroups = yield school.get('instructorGroups');

      this.instructors = instructors.toArray();
      this.instructorGroups = instructorGroups.toArray();
      this.availableInstructorGroups = availableInstructorGroups.toArray();
    }
  }

  @action
  addInstructor(user) {
    this.instructors = [...this.instructors, user];
  }

  @action
  addInstructorGroup(instructorGroup) {
    this.instructorGroups = [...this.instructorGroups, instructorGroup];
  }

  @action
  removeInstructor(user) {
    this.instructors = this.instructors.filter(instructor => instructor !== user);
  }

  @action
  removeInstructorGroup(instructorGroup) {
    this.instructorGroups = this.instructorGroups.filter(group => group !== instructorGroup);
  }

  @dropTask
  *saveChanges() {
    yield this.args.save(this.instructors, this.instructorGroups);
  }
}
<|endoftext|>


<commit_before>'use strict';
var isInit = true,
    helpers = require('../../utils/widgets/helper'),
    navigationProperty = require('../../utils/widgets/navigation-property'),
    // additional requires
    viewModel = require('./offlinePageView-view-model'),
	modOfflinePage = require('../../lib/modOfflinePage/modOfflinePage.js'),
	modBrowser = require('../../lib/modBrowser/modBrowser.js'),
	actionBarModule = require("ui/action-bar"),
	buttonModule = require("ui/button"),
	util = require('../../utils/MyUtil')
	;

// additional functions
function pageLoaded(args) {
    var page = args.object;

    helpers.platformInit(page);
    page.bindingContext = viewModel;
    // additional pageLoaded

    if (isInit) {
        isInit = false;

        // additional pageInit
    }
	loadItems();

	// NAVBUTTON - start
	var navButton = new actionBarModule.NavigationButton();
	navButton.text = 'Edit'
	navButton.height = 44;
	navButton.on(buttonModule.Button.tapEvent, function() {
		if(!editMode)
			navButton.text = 'Done';
		else
			navButton.text = 'Edit';

		editMode = !editMode;
	})
	util.setRightNavButton(page, navButton);
	// NAVBUTTON - end

}
function loadItems() {
    modOfflinePage.getList(function(items) {
        var menuItems = [];
        for(var i = 0; i < items.length; i++) {
            var item = items[i];
            menuItems.push({
                "title": "[" + item.title + "]",
                "item" : item,
                "icon": "\ue903"
            },);
        }
        viewModel.set('menuItems', menuItems);
    });
}

// START_CUSTOM_CODE_homeView
// Add custom code here. For more information about custom code, see http://docs.telerik.com/platform/screenbuilder/troubleshooting/how-to-keep-custom-code-changes
var view = require("ui/core/view");
function menuItemTap(args) {
    var sender = args.object;
    var parent = sender.parent;
    var menuItems = viewModel.get('menuItems');
    var menuItem = menuItems[args.index];
    var item = menuItem.item;
	if(item.type == 'cat') {
		var browser = modBrowser.createBrowser();
		browser.open(item.cat);
	}
	else if(item.type == 'item') {
		var browser = modBrowser.createBrowser();
		browser.open(item.item);
	}
}

// END_CUSTOM_CODE_homeView

var editMode = false;

exports.pageLoaded = pageLoaded;<commit_msg>exports.menuItemTap = menuItemTap;<commit_after>'use strict';
var isInit = true,
    helpers = require('../../utils/widgets/helper'),
    navigationProperty = require('../../utils/widgets/navigation-property'),
    // additional requires
    viewModel = require('./offlinePageView-view-model'),
	modOfflinePage = require('../../lib/modOfflinePage/modOfflinePage.js'),
	modBrowser = require('../../lib/modBrowser/modBrowser.js'),
	actionBarModule = require("ui/action-bar"),
	buttonModule = require("ui/button"),
	util = require('../../utils/MyUtil')
	;

// additional functions
function pageLoaded(args) {
    var page = args.object;

    helpers.platformInit(page);
    page.bindingContext = viewModel;
    // additional pageLoaded

    if (isInit) {
        isInit = false;

        // additional pageInit
    }
	loadItems();

	// NAVBUTTON - start
	var navButton = new actionBarModule.NavigationButton();
	navButton.text = 'Edit'
	navButton.height = 44;
	navButton.on(buttonModule.Button.tapEvent, function() {
		if(!editMode)
			navButton.text = 'Done';
		else
			navButton.text = 'Edit';

		editMode = !editMode;
	})
	util.setRightNavButton(page, navButton);
	// NAVBUTTON - end

}
function loadItems() {
    modOfflinePage.getList(function(items) {
        var menuItems = [];
        for(var i = 0; i < items.length; i++) {
            var item = items[i];
            menuItems.push({
                "title": "[" + item.title + "]",
                "item" : item,
                "icon": "\ue903"
            },);
        }
        viewModel.set('menuItems', menuItems);
    });
}

// START_CUSTOM_CODE_homeView
// Add custom code here. For more information about custom code, see http://docs.telerik.com/platform/screenbuilder/troubleshooting/how-to-keep-custom-code-changes
var view = require("ui/core/view");
function menuItemTap(args) {
    var sender = args.object;
    var parent = sender.parent;
    var menuItems = viewModel.get('menuItems');
    var menuItem = menuItems[args.index];
    var item = menuItem.item;
	if(item.type == 'cat') {
		var browser = modBrowser.createBrowser();
		browser.open(item.cat);
	}
	else if(item.type == 'item') {
		var browser = modBrowser.createBrowser();
		browser.open(item.item);
	}
}

// END_CUSTOM_CODE_homeView

var editMode = false;

exports.menuItemTap = menuItemTap;
exports.pageLoaded = pageLoaded;<|endoftext|>