<commit_before>/**
 * Conditional sub fields
 *
 * Supports the ability to conditionally show and hide content based on the
 * value of a field.
 *
 * The element to be shown requires 2 attributes:
 * [data-controlled-by] - this is the name of the field which controls it
 * [data-control-value] - the value by which this element should be displayed
 *
 * It also requires a basic bit of style to work:
 *
 * [data-controlled-by] {
 *   display: none;
 * }
 * [data-controlled-by].is-active {
 *   display: block;
 * }
 *
 * Note: it is recommend to only apply this if javascript is enabled
 *
 * @example
 *
 *
 *   <input name="control-field" value="yes" type="radio">Yes
 *
 *
 *   <input name="control-field" value="no" type="radio">No
 *
 *
 *

 *   Visible when `control-field` equals `yes`
 *

 *
 */

const uniq = require('lodash/uniq')
const includes = require('lodash/includes')

const { addClass, removeClass } = require('../_deprecated/lib/element-stuff.js')

const ConditionalSubfields = {
  selector: 'js-ConditionalSubfield',
  activeClass: 'is-active',
  onChangeHandler: null,
  controllers: [],
  wrapper: null,

  init (wrapper = document) {
    this.wrapper = wrapper

    this.cacheEls()

    if (this.controllers.length) {
      this.bindEvents()
      this.render()
    }
  },

  cacheEls () {
    const conditionalSubFields = this.wrapper.getElementsByClassName(this.selector)

    this.onChangeHandler = this.onChange.bind(this)
    this.controllers = uniq([...conditionalSubFields].map((controller, i) => {
      return controller.getAttribute('data-controlled-by')
    }))
  },

  bindEvents () {
    this.wrapper.addEventListener('change', this.onChangeHandler)
  },

  render () {
    this.controllers.forEach((controller) => {
      const field = this.wrapper.querySelector(`[name="${controller}"]`)

      this._handleField(field)
    })
  },

  destroy () {
    this.wrapper.removeEventListener('change', this.onChangeHandler)
  },

  onChange (evt) {
    const field = evt.target

    if (includes(this.controllers, field.name)) {
      this._handleField(field)
    }
  },

  _handleField (controlInput) {
    if (!controlInput) {
      return
    }
    const subFields = this.wrapper.querySelectorAll(`[data-controlled-by="${controlInput.name}"]`)
    const tagName = controlInput.tagName
    let controlInputValue

    if (tagName === 'SELECT') {
      controlInputValue = controlInput.value
    } else if (tagName === 'INPUT') {
      const type = controlInput.type

      if (type === 'radio' || type === 'checkbox') {
        const checked = this.wrapper.querySelector(`[name="${controlInput.name}"]:checked`)

        controlInputValue = checked ? checked.value : null
      } else {
        controlInputValue = controlInput.value
      }
    }

    Array.from(subFields).forEach((subField) => {
      const value = subField.getAttribute('data-control-value') + ''
      let isVisible

      isVisible = controlInputValue === value

      this._toggleSubField(subField, isVisible)
    })
  },

  _toggleSubField (subField, isVisible) {
    if (isVisible) {
      addClass(subField, this.activeClass)
    } else {
      removeClass(subField, this.activeClass)
    }

    subField.setAttribute('aria-expanded', isVisible)
    subField.setAttribute('aria-hidden', !isVisible)

    if (!isVisible && !subField.getAttribute('data-persist-values')) {
      const children = subField.querySelectorAll('input, select, checkbox, textarea')

      Array.from(children).forEach((field) => {
        if (!field.getAttribute('data-persist-values')) {
          field.value = ''
          field.checked = false
        }

        const event = this.wrapper.createEvent('HTMLEvents')
        event.initEvent('change', true, false)
        field.dispatchEvent(event)
      })
    }
  },
}

module.exports = ConditionalSubfields
<commit_msg>Allow conditional subfields to be controlled by multiple values<commit_after>/**
 * Conditional sub fields
 *
 * Supports the ability to conditionally show and hide content based on the
 * value of a field.
 *
 * The element to be shown requires 2 attributes:
 * [data-controlled-by] - this is the name of the field which controls it
 * [data-control-value] - the value by which this element should be displayed
 *                        Can include multiple control values using `||` to
 *                        separate each value
 *
 * It also requires a basic bit of style to work:
 *
 * [data-controlled-by] {
 *   display: none;
 * }
 * [data-controlled-by].is-active {
 *   display: block;
 * }
 *
 * Note: it is recommend to only apply this if javascript is enabled
 *
 * @example
 *
 *
 *   <input name="control-field" value="yes" type="radio">Yes
 *
 *
 *   <input name="control-field" value="no" type="radio">No
 *
 *
 *

 *   Visible when `control-field` equals `yes`
 *

 *
 */

const uniq = require('lodash/uniq')
const includes = require('lodash/includes')

const { addClass, removeClass } = require('../_deprecated/lib/element-stuff.js')

const ConditionalSubfields = {
  selector: 'js-ConditionalSubfield',
  activeClass: 'is-active',
  onChangeHandler: null,
  controllers: [],
  wrapper: null,

  init (wrapper = document) {
    this.wrapper = wrapper

    this.cacheEls()

    if (this.controllers.length) {
      this.bindEvents()
      this.render()
    }
  },

  cacheEls () {
    const conditionalSubFields = this.wrapper.getElementsByClassName(this.selector)

    this.onChangeHandler = this.onChange.bind(this)
    this.controllers = uniq([...conditionalSubFields].map((controller, i) => {
      return controller.getAttribute('data-controlled-by')
    }))
  },

  bindEvents () {
    this.wrapper.addEventListener('change', this.onChangeHandler)
  },

  render () {
    this.controllers.forEach((controller) => {
      const field = this.wrapper.querySelector(`[name="${controller}"]`)

      this._handleField(field)
    })
  },

  destroy () {
    this.wrapper.removeEventListener('change', this.onChangeHandler)
  },

  onChange (evt) {
    const field = evt.target

    if (includes(this.controllers, field.name)) {
      this._handleField(field)
    }
  },

  _handleField (controlInput) {
    if (!controlInput) {
      return
    }
    const subFields = this.wrapper.querySelectorAll(`[data-controlled-by="${controlInput.name}"]`)
    const tagName = controlInput.tagName
    let controlInputValue

    if (tagName === 'SELECT') {
      controlInputValue = controlInput.value
    } else if (tagName === 'INPUT') {
      const type = controlInput.type

      if (type === 'radio' || type === 'checkbox') {
        const checked = this.wrapper.querySelector(`[name="${controlInput.name}"]:checked`)

        controlInputValue = checked ? checked.value : null
      } else {
        controlInputValue = controlInput.value
      }
    }

    Array.from(subFields).forEach((subField) => {
      const values = (subField.getAttribute('data-control-value') + '').split('||')
      let isVisible

      isVisible = includes(values, controlInputValue)

      this._toggleSubField(subField, isVisible)
    })
  },

  _toggleSubField (subField, isVisible) {
    if (isVisible) {
      addClass(subField, this.activeClass)
    } else {
      removeClass(subField, this.activeClass)
    }

    subField.setAttribute('aria-expanded', isVisible)
    subField.setAttribute('aria-hidden', !isVisible)

    if (!isVisible && !subField.getAttribute('data-persist-values')) {
      const children = subField.querySelectorAll('input, select, checkbox, textarea')

      Array.from(children).forEach((field) => {
        if (!field.getAttribute('data-persist-values')) {
          field.value = ''
          field.checked = false
        }

        const event = this.wrapper.createEvent('HTMLEvents')
        event.initEvent('change', true, false)
        field.dispatchEvent(event)
      })
    }
  },
}

module.exports = ConditionalSubfields
<|endoftext|>


<commit_before>var TENDER_VIEW_URL = "/tenderView";
var FORMAT_DATE = 'yyyy/mm/dd';
var locs = '';

$(document).ready(function () {
    $('#endDate').datepicker({
        format: FORMAT_DATE,
        startDate: '-3d'
    });
    showUnit();
    showProposals();
    showInfo();
    $("#status, #date_to, #description").change(function() {
        enableSaveTenderButton();
    });
    $("[rel='tooltip']").tooltip();
    $("#locations").hover(
        function() {
            if (locs.toString().split(',').length>2) {
                var html = '';
                html += '
' +
                    '

' +
                    '
' + locs + '
' +
                    '
'
                $(this).append($(html));
            }
        }, function() {
            $( this ).find( $('#hover_locations') ).remove();
        }
    );
});
function showProposals() {
    var URL = location.href;
    var tenderURI = URL.split(TENDER_VIEW_URL);
    var tenderId = tenderURI[tenderURI.length - 1];
    $.getJSON('/tenders/'+tenderId+'/proposals', function (data) {
        var html;
        var len = data.length;
        if(len > 0) {
            document.getElementById("no_proposals_message").setAttribute('hidden','true');
            for (var i = 0; i < len; i++) {
                html += '
' +
                    '' + data[i].fullName + '	' +
                    '' + data[i].numberOfBids + '	' +
                    '' + data[i].totalBidsPrice + '	' +
                    '<button type="submit" class="btn btn-default" disabled>Deal</button>	' +
                    '
';
            }
            $('#proposals').html(html);
        } else {
            document.getElementById("head_proposals").setAttribute('hidden','true');
        }
    });
}
function showUnit() {
    var str = location.href;
    var tender1 = str.split(TENDER_VIEW_URL);
    var tender = tender1[tender1.length - 1];
    $.getJSON('/tenders/' + tender + '/units', function (data) {
        var html = '';
        var len = data.length;
        for (var i = 0; i < len; i++) {
            if (data[i].itemType == 'P')
                var itemTypes = 'Product'
            else if (data[i].itemType == 'S')
                var itemTypes = 'Service'
            html += '
' + ' <input type="checkbox">' + '	' +
                '' + data[i].unitName + '	' +
                '' + itemTypes + '	' +
                '' + data[i].categoryName + '	' +
                '' + data[i].quantity + ' ' + data[i].measurementName + '	' +
                '' + data[i].numberOfBids + '	' +
                '' + data[i].price + '	' +
                '' + '<button type="submit" class="btn btn-default" disabled>Deal</button>' + '
';
        }
        $('#unitsTable').html(html);
    });
}

function showInfo(){
    var str = location.href;
    var tender1 = str.split(TENDER_VIEW_URL);
    var tender = tender1[tender1.length - 1];
    $.getJSON(TENDERS_URL+tender.substring(1), function(data){
        var statusHtml = '';
        statusHtml += '<option value="'+ data.status + '">' + data.status + '</option>';
        statusHtml += '<option value="Close">Close</option>';
        $('#status').html(statusHtml);
        document.getElementById('date_to').value = dateConverter(data.endDate);
        var priceHtml ='';
        priceHtml+= '
' + data.suitablePrice + '
';
        $('#suitablePrice').html(priceHtml);
        if (data.description!=null){
            document.getElementById('description').value = data.description;
        }else{
            document.getElementById('description').value = "";
        }
        var loc =new Array();
        var len = data.locations.toString().split(',').length;
        loc =data.locations.toString().split(',');
        var locations = '';
        if (len>2){
            for (var i=0;i<2;i++){
                locations += loc[i]+','
            }
            locations = locations.substring(0,locations.lastIndexOf(','))+ '...';
        }else{
            locations = data.locations.toString();
        }
        var locationsHtml ='';
        locationsHtml += '
' + locations + '
';
        $('#locations').html(locationsHtml);
        locs = data.locations;
    });
}

function dateConverter(timestamp){
    var date = new Date(timestamp);
    var year = date.getFullYear();
    var month = date.getMonth()+1;
    var day = date.getDate();

    if(day <= 9) day = "0" + day;
    if(month <= 9) month = "0" + month;

    return year + "/" + month + "/" + day;
}

function saveTenderAfterUpdate(){
    var srt = location.href;
    var tender1 = srt.split(TENDER_VIEW_URL);
    var tender = tender1[tender1.length - 1];
    var str = '';
    str += "statusName=" + $('#status').val()+"&endDate="+$('#date_to').val();
    if ($('#description').val()!=""){
        str +="&description="+$('#description').val();
    }
    $.ajax({
        url: TENDERS_URL + tender.substring(1) + "?"  + str,
        type: "PUT",
        success: function(data){
            alert("Success")
        },
        error: function(){
            alert("Something wrong")
        }
    })
}

function enableSaveTenderButton(){
    $("#save_tender_button").removeAttr("disabled");
}

<commit_msg>set to checkbox<commit_after>var TENDER_VIEW_URL = "/tenderView";
var FORMAT_DATE = 'yyyy/mm/dd';
var locs = '';
var Units = new Array();
var Proposals = new Array();

$(document).ready(function () {
    $('#endDate').datepicker({
        format: FORMAT_DATE,
        startDate: '-3d'
    });
    showUnit();
    showProposals();
    showInfo();
    $("#status, #date_to, #description").change(function() {
        enableSaveTenderButton();
    });
    $("[rel='tooltip']").tooltip();
    $("#locations").hover(
        function() {
            if (locs.toString().split(',').length>2) {
                var html = '';
                html += '
' +
                    '

' +
                    '
' + locs + '
' +
                    '
'
                $(this).append($(html));
            }
        }, function() {
            $( this ).find( $('#hover_locations') ).remove();
        }
    );
});
function showProposals() {
    var URL = location.href;
    var tenderURI = URL.split(TENDER_VIEW_URL);
    var tenderId = tenderURI[tenderURI.length - 1];
    $.getJSON('/tenders/'+tenderId+'/proposals', function (data) {
        var html;
        var len = data.length;
        Proposals = data;
        if(len > 0) {
            document.getElementById("no_proposals_message").setAttribute('hidden','true');
            for (var i = 0; i < len; i++) {
                html += '
' +
                    '' + data[i].fullName + '	' +
                    '' + data[i].numberOfBids + '	' +
                    '' + data[i].totalBidsPrice + '	' +
                    '<button type="submit" class="btn btn-default" disabled>Deal</button>	' +
                    '
';
            }
            $('#proposals').html(html);
        } else {
            document.getElementById("head_proposals").setAttribute('hidden','true');
        }
    });
}
function showUnit() {
    var str = location.href;
    var tender1 = str.split(TENDER_VIEW_URL);
    var tender = tender1[tender1.length - 1];
    $.getJSON('/tenders/' + tender + '/units', function (data) {
        var html = '';
        var len = data.length;
        Units = data;
        for (var i = 0; i < len; i++) {
            if (data[i].itemType == 'P')
                var itemTypes = 'Product'
            else if (data[i].itemType == 'S')
                var itemTypes = 'Service'
            html += '
' + '<input type="checkbox" onchange="" id="' + i + '">	' +
                '' + data[i].unitName + '	' +
                '' + itemTypes + '	' +
                '' + data[i].categoryName + '	' +
                '' + data[i].quantity + ' ' + data[i].measurementName + '	' +
                '' + data[i].numberOfBids + '	' +
                '' + data[i].price + '	' +
                '' + '<button type="submit" class="btn btn-default" disabled>Deal</button>' + '
';
        }
        $('#unitsTable').html(html);
    });
}

function showInfo(){
    var str = location.href;
    var tender1 = str.split(TENDER_VIEW_URL);
    var tender = tender1[tender1.length - 1];
    $.getJSON(TENDERS_URL+tender.substring(1), function(data){
        var statusHtml = '';
        statusHtml += '<option value="'+ data.status + '">' + data.status + '</option>';
        statusHtml += '<option value="Close">Close</option>';
        $('#status').html(statusHtml);
        document.getElementById('date_to').value = dateConverter(data.endDate);
        var priceHtml ='';
        priceHtml+= '
' + data.suitablePrice + '
';
        $('#suitablePrice').html(priceHtml);
        if (data.description!=null){
            document.getElementById('description').value = data.description;
        }else{
            document.getElementById('description').value = "";
        }
        var loc =new Array();
        var len = data.locations.toString().split(',').length;
        loc =data.locations.toString().split(',');
        var locations = '';
        if (len>2){
            for (var i=0;i<2;i++){
                locations += loc[i]+','
            }
            locations = locations.substring(0,locations.lastIndexOf(','))+ '...';
        }else{
            locations = data.locations.toString();
        }
        var locationsHtml ='';
        locationsHtml += '
' + locations + '
';
        $('#locations').html(locationsHtml);
        locs = data.locations;
    });
}

function dateConverter(timestamp){
    var date = new Date(timestamp);
    var year = date.getFullYear();
    var month = date.getMonth()+1;
    var day = date.getDate();

    if(day <= 9) day = "0" + day;
    if(month <= 9) month = "0" + month;

    return year + "/" + month + "/" + day;
}

function saveTenderAfterUpdate(){
    var srt = location.href;
    var tender1 = srt.split(TENDER_VIEW_URL);
    var tender = tender1[tender1.length - 1];
    var str = '';
    str += "statusName=" + $('#status').val()+"&endDate="+$('#date_to').val();
    if ($('#description').val()!=""){
        str +="&description="+$('#description').val();
    }
    $.ajax({
        url: TENDERS_URL + tender.substring(1) + "?"  + str,
        type: "PUT",
        success: function(data){
            alert("Success")
        },
        error: function(){
            alert("Something wrong")
        }
    })
}

function enableSaveTenderButton(){
    $("#save_tender_button").removeAttr("disabled");
}

function showSpecificProposals() {

}

<|endoftext|>


<commit_before>/*
Copyright 2015 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

var React = require('react');
var sdk = require('matrix-react-sdk')

var MatrixChatController = require('matrix-react-sdk/lib/controllers/pages/MatrixChat')

// should be atomised
var Loader = require("react-loader");

var dis = require('matrix-react-sdk/lib/dispatcher');

module.exports = React.createClass({
    displayName: 'MatrixChat',
    mixins: [MatrixChatController],

    getInitialState: function() {
        return {
            width: 10000,
        }
    },

    componentDidMount: function() {
        window.addEventListener('resize', this.handleResize);
        this.handleResize();
    },

    componentWillUnmount: function() {
        window.removeEventListener('resize', this.handleResize);
    },

    handleResize: function(e) {
        var hideLhsThreshold = 1000;
        var showLhsThreshold = 1000;
        var hideRhsThreshold = 820;
        var showRhsThreshold = 820;

        if (this.state.width > hideLhsThreshold && window.innerWidth <= hideLhsThreshold) {
            dis.dispatch({ action: 'hide_left_panel' });
        }
        if (this.state.width <= showLhsThreshold && window.innerWidth > showLhsThreshold) {
            dis.dispatch({ action: 'show_left_panel' });
        }
        if (this.state.width > hideRhsThreshold && window.innerWidth <= hideRhsThreshold) {
            dis.dispatch({ action: 'hide_right_panel' });
        }
        if (this.state.width <= showRhsThreshold && window.innerWidth > showRhsThreshold) {
            dis.dispatch({ action: 'show_right_panel' });
        }

        this.setState({width: window.innerWidth});
    },

    onRoomCreated: function(room_id) {
        dis.dispatch({
            action: "view_room",
            room_id: room_id,
        });
    },

    render: function() {
        var LeftPanel = sdk.getComponent('organisms.LeftPanel');
        var RoomView = sdk.getComponent('organisms.RoomView');
        var RightPanel = sdk.getComponent('organisms.RightPanel');
        var Login = sdk.getComponent('templates.Login');
        var UserSettings = sdk.getComponent('organisms.UserSettings');
        var Register = sdk.getComponent('templates.Register');
        var CreateRoom = sdk.getComponent('organisms.CreateRoom');
        var RoomDirectory = sdk.getComponent('organisms.RoomDirectory');
        var MatrixToolbar = sdk.getComponent('molecules.MatrixToolbar');
        var Notifier = sdk.getComponent('organisms.Notifier');

        if (this.state.logged_in && this.state.ready) {
            var page_element;
            var right_panel = "";

            switch (this.state.page_type) {
                case this.PageTypes.RoomView:
                    page_element = <RoomView roomId={this.state.currentRoom} key={this.state.currentRoom} />
                    right_panel = <RightPanel roomId={this.state.currentRoom} collapsed={this.state.collapse_rhs} />
                    break;
                case this.PageTypes.UserSettings:
                    page_element = <UserSettings />
                    right_panel = <RightPanel collapsed={this.state.collapse_rhs}/>
                    break;
                case this.PageTypes.CreateRoom:
                    page_element = <CreateRoom onRoomCreated={this.onRoomCreated}/>
                    right_panel = <RightPanel collapsed={this.state.collapse_rhs}/>
                    break;
                case this.PageTypes.RoomDirectory:
                    page_element = <RoomDirectory />
                    right_panel = <RightPanel collapsed={this.state.collapse_rhs}/>
                    break;
            }

            // TODO: Fix duplication here and do conditionals like we do above
            if (Notifier.supportsDesktopNotifications() && !Notifier.isEnabled() && !Notifier.isToolbarHidden()) {
                return (

                            <MatrixToolbar />

                                <LeftPanel selectedRoom={this.state.currentRoom} collapsed={this.state.collapse_lhs} />

                                    {page_element}

                                {right_panel}

                );
            }
            else {
                return (

                            <LeftPanel selectedRoom={this.state.currentRoom} collapsed={this.state.collapse_lhs} />

                                {page_element}

                            {right_panel}

                );
            }
        } else if (this.state.logged_in) {
            return (
                <Loader />
            );
        } else if (this.state.screen == 'register') {
            return (
                <Register onLoggedIn={this.onLoggedIn} clientSecret={this.state.register_client_secret}
                    sessionId={this.state.register_session_id} idSid={this.state.register_id_sid}
                    hsUrl={this.state.register_hs_url} isUrl={this.state.register_is_url}
                    registrationUrl={this.props.registrationUrl}
                />
            );
        } else {
            return (
                <Login onLoggedIn={this.onLoggedIn} />
            );
        }
    }
});
<commit_msg>Add linkify handlers<commit_after>/*
Copyright 2015 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

var React = require('react');
var sdk = require('matrix-react-sdk')

var MatrixChatController = require('matrix-react-sdk/lib/controllers/pages/MatrixChat')

// should be atomised
var Loader = require("react-loader");

var dis = require('matrix-react-sdk/lib/dispatcher');
var Matrix = require("matrix-js-sdk");
var ContextualMenu = require("../../../../ContextualMenu");

module.exports = React.createClass({
    displayName: 'MatrixChat',
    mixins: [MatrixChatController],

    getInitialState: function() {
        return {
            width: 10000,
        }
    },

    componentDidMount: function() {
        window.addEventListener('resize', this.handleResize);
        this.handleResize();
    },

    componentWillUnmount: function() {
        window.removeEventListener('resize', this.handleResize);
    },

    onAliasClick: function(event, alias) {
        event.preventDefault();
        dis.dispatch({action: 'view_room_alias', room_alias: alias});
    },

    onUserClick: function(event, userId) {
        event.preventDefault();
        var MemberInfo = sdk.getComponent('molecules.MemberInfo');
        var member = new Matrix.RoomMember(null, userId);
        ContextualMenu.createMenu(MemberInfo, {
            member: member,
            right: window.innerWidth - event.pageX,
            top: event.pageY
        });
    },

    handleResize: function(e) {
        var hideLhsThreshold = 1000;
        var showLhsThreshold = 1000;
        var hideRhsThreshold = 820;
        var showRhsThreshold = 820;

        if (this.state.width > hideLhsThreshold && window.innerWidth <= hideLhsThreshold) {
            dis.dispatch({ action: 'hide_left_panel' });
        }
        if (this.state.width <= showLhsThreshold && window.innerWidth > showLhsThreshold) {
            dis.dispatch({ action: 'show_left_panel' });
        }
        if (this.state.width > hideRhsThreshold && window.innerWidth <= hideRhsThreshold) {
            dis.dispatch({ action: 'hide_right_panel' });
        }
        if (this.state.width <= showRhsThreshold && window.innerWidth > showRhsThreshold) {
            dis.dispatch({ action: 'show_right_panel' });
        }

        this.setState({width: window.innerWidth});
    },

    onRoomCreated: function(room_id) {
        dis.dispatch({
            action: "view_room",
            room_id: room_id,
        });
    },

    render: function() {
        var LeftPanel = sdk.getComponent('organisms.LeftPanel');
        var RoomView = sdk.getComponent('organisms.RoomView');
        var RightPanel = sdk.getComponent('organisms.RightPanel');
        var Login = sdk.getComponent('templates.Login');
        var UserSettings = sdk.getComponent('organisms.UserSettings');
        var Register = sdk.getComponent('templates.Register');
        var CreateRoom = sdk.getComponent('organisms.CreateRoom');
        var RoomDirectory = sdk.getComponent('organisms.RoomDirectory');
        var MatrixToolbar = sdk.getComponent('molecules.MatrixToolbar');
        var Notifier = sdk.getComponent('organisms.Notifier');

        if (this.state.logged_in && this.state.ready) {
            var page_element;
            var right_panel = "";

            switch (this.state.page_type) {
                case this.PageTypes.RoomView:
                    page_element = <RoomView roomId={this.state.currentRoom} key={this.state.currentRoom} />
                    right_panel = <RightPanel roomId={this.state.currentRoom} collapsed={this.state.collapse_rhs} />
                    break;
                case this.PageTypes.UserSettings:
                    page_element = <UserSettings />
                    right_panel = <RightPanel collapsed={this.state.collapse_rhs}/>
                    break;
                case this.PageTypes.CreateRoom:
                    page_element = <CreateRoom onRoomCreated={this.onRoomCreated}/>
                    right_panel = <RightPanel collapsed={this.state.collapse_rhs}/>
                    break;
                case this.PageTypes.RoomDirectory:
                    page_element = <RoomDirectory />
                    right_panel = <RightPanel collapsed={this.state.collapse_rhs}/>
                    break;
            }

            // TODO: Fix duplication here and do conditionals like we do above
            if (Notifier.supportsDesktopNotifications() && !Notifier.isEnabled() && !Notifier.isToolbarHidden()) {
                return (

                            <MatrixToolbar />

                                <LeftPanel selectedRoom={this.state.currentRoom} collapsed={this.state.collapse_lhs} />

                                    {page_element}

                                {right_panel}

                );
            }
            else {
                return (

                            <LeftPanel selectedRoom={this.state.currentRoom} collapsed={this.state.collapse_lhs} />

                                {page_element}

                            {right_panel}

                );
            }
        } else if (this.state.logged_in) {
            return (
                <Loader />
            );
        } else if (this.state.screen == 'register') {
            return (
                <Register onLoggedIn={this.onLoggedIn} clientSecret={this.state.register_client_secret}
                    sessionId={this.state.register_session_id} idSid={this.state.register_id_sid}
                    hsUrl={this.state.register_hs_url} isUrl={this.state.register_is_url}
                    registrationUrl={this.props.registrationUrl}
                />
            );
        } else {
            return (
                <Login onLoggedIn={this.onLoggedIn} />
            );
        }
    }
});
<|endoftext|>


<commit_before>/**
 * @module Q
 */

var Q = require('../Q');
var fs = require('fs');

/**
 * Creates a Q.Tree object
 * @class Tree
 * @namespace Q
 * @constructor
 * @param {object} [linked={}] If supplied, then this object is
 *  used as the internal tree that Tree operates on.
 */
module.exports = function (linked) {

	if (linked === undefined) {
		linked = {};
	}

	if (Q.typeOf(linked) === 'Q.Tree') {
		linked = linked.getAll();
	}

	this.typename = "Q.Tree";

	/**
	 * Loads data into a tree from a file.
	 * @method load
	 * @param {string} filename The filename of the file to load.
	 * @param {function} [callback=null] Function to call back, with params (err, data)
	 * @throws {Q.Exception} if filename is not string or array of strings
	 */
	this.load = function (filename, callback) {
		var that = this;
		var filenames;
		switch (Q.typeOf(filename)) {
			case 'string':
				filenames = [filename];
				break;
			case 'array':
				filenames = filename;
				break;
			default:
				throw new Q.Exception("Q.Tree.load: filename has to be a string or array");
		}
		var p = new Q.Pipe(filenames, function (params) {
			// All the files were loaded, time to merge them in the right order
			for (var i=0; i<filenames.length; ++i) {
				var k = filenames[i];
				if (params[k][0]) {
					that.merge(params[k][0]);
				}
			}
			this.filename = filename;
			callback && callback.call(that, null, that.getAll());
		});
		for (var i=0; i<filenames.length; ++i) {
			(function (i) {
				var isPHP = (filenames[i].substr(-4).toLowerCase() === '.php');
				fs.readFile(filenames[i].replace('/', Q.DS), 'utf-8', function (err, data) {
					if (err) {
						if (err.code == 'ENOENT') {
							p.fill(filenames[i])(null); // just keep going
						} else {
							callback && callback.call(that, err);
						}
					} else {
						try {
							if (isPHP) {
								data = data.substring(
									data.indexOf("\n") + 1,
									data.lastIndexOf("\n")
								);
							}
							data = data.replace(/\s*(?!<")\/\*[^\*]+\*\/(?!")\s*/gi, '');
							data = JSON.parse(data);
						} catch (e) {
							callback && callback.call(that, e);
						}
						p.fill(filenames[i])(data);
					}
				});
			})(i);
		}
	};

	/**
	 * Saves a (sub)tree of parameters to a file
	 * @method save
	 * @param {string} filename The filename to save into.
	 *   If tree was loaded from a single file, you can leave this blank to update that file.
	 * @param {array} [arrayPath=[]] Array of keys identifying the path of the subtree to save
	 * @param {array} [prefixPath=[]] Array of keys identifying the prefix path of the subtree to save
	 * @param {function} [callback=null] Function to call back, with params (err)
	 */
	this.save = function (filename, arrayPath, prefixPath, callback) {
		if (!filename && (typeof this.filename === 'string')) {
			filename = this.filename;
		}
		if (typeof arrayPath === 'function' || typeof arrayPath === 'undefined') {
			callback = arrayPath;
			arrayPath = prefixPath = [];
		} else if (typeof prefixPath === 'function' || typeof prefixPath === 'undefined') {
			callback = prefixPath;
			prefixPath = [];
		}

		var d, data = this.get.apply(this, [arrayPath]), that = this;

		if(Q.typeOf(prefixPath) !== 'array') prefixPath = prefixPath ? [prefixPath] : [];

		for (var i=prefixPath.length-1; i>=0; i--) {
			d = {};
			d[prefixPath[i]] = data;
			data = d;
		}

		to_save = JSON.stringify(data, null, '\t');
		var mask = process.umask(parseInt(Q.Config.get(['Q', 'internal', 'umask'], "0000"), 8));
		fs.writeFile(filename.replace('/', Q.DS), to_save, function (err) {
			process.umask(mask);
			callback && callback.call(that, err);
		});
	};

	/**
	 * Gets the entire tree of parameters
	 * @method getAll
	 * @return {object}
	 */
	this.getAll = function () {
		return linked;
	};

	/**
	 * Gets the value of a field in the tree
	 * @method get
	 * @param {string|array} [keys=[]] A key or an array of keys for traversing the tree.
	 * @param {mixed} [def=undefined] The value to return if the field is not found. Defaults to undefined.
	 * @return {mixed} The field if it is found, otherwise def or undefined.
	 * @throws {Q.Exception} if subtree is not an object
	 */
	this.get = function (keys, def) {
		if (typeof keys === 'undefined') keys = [];
		if (typeof keys === 'string') {
			var arr = [];
			for (var j=0; j<arguments.length-1; ++j) {
				arr.push(arguments[j]);
			}
			keys = arr;
			def = arguments[arguments.length-1];
		}
		var result = linked, key, sawKeys = [];
		for (var i=0, len = keys.length; i<len; ++i) {
			key = keys[i];
			if (typeof result !== 'object') {
				return def; // silently ignore the rest of the path
				// var sawString = '["' + sawKeys.join('"]["') + '"]';
				// throw new Q.Exception(
				// 	"Q.Tree: subtree at '"+sawString+"' is not an object",
				// 	{keys: keys, key: key}
				// );
			}
			if (!result || key == null || !(key in result)) {
				return def;
			}
			result = result[key];
			sawKeys.push(key);
		}
		return result;
	};

	/**
	 * Sets the value of a field in the tree. If only one argument is given,
	 * it is assigned as tree value
	 * @method set
	 * @param {string|array} keys A key or an array of keys for traversing the tree.
	 * @param {mixed} value The value to set for that field.
	 * @return {Q.Tree} Returns itself for chaining
	 * @chainable
	 */
	this.set = function (keys, value) {
		var k;
		if (arguments.length === 1) {
			linked = (typeof keys === "object") ? keys : [keys];
		} else {
			if (Q.typeOf(keys) === 'object') {
				for (k in keys) {
					linked[k] = keys[k];
				}
			} else {
				if (typeof keys === 'string') {
					var arr = [];
					for (var j=0; j<arguments.length-1; ++j) {
						arr.push(arguments[j]);
					}
					keys = arr;
					value = arguments[arguments.length-1];
				}
				var result = linked, key;
				for (var i=0, len = keys.length; i<len-1; ++i) {
					key = keys[i];
					if (!(key in result) || Q.typeOf(result[key]) !== 'object') {
						result[key] = {}; // overwrite with an object
					}
					result = result[key];
				}
				if (key = keys[len-1]) {
					result[key] = value;
				}
			}
		}
		return this;
	};

	/**
	 * Clears the value of a field, removing that key from the tree
	 * @method clear
	 * @param {string|array} [keys=null] A key or an array of keys for traversing the tree. If null, clears entire tree.
	 * @return {boolean} Returns whether the field to be cleared was found
	 */
	this.clear = function (keys) {
		if (!keys) {
			linked = {};
			return;
		}
		if (typeof keys === 'string') {
			keys = [keys];
		}
		var result = linked, key;
		for (var i=0, len = keys.length; i<len; ++i) {
			key = keys[i];
			if (typeof result !== 'object') {
				return false;
			}
			if (!(key in result)) {
				return false;
			}
			if (i === len - 1) {
				// return the final value
				delete result[key];
				return true;
			}
			result = result[key];
		}
		return false;
	};

	/**
	 * Traverse the tree depth-first and call the callback
	 * @method depthFirst
	 * @param {Function} callback Will receive (path, value, tree, context)
	 * @param {mixed} [context=null] To propagate some context to the callback
	 */
	this.depthFirst = function(callback, context) {
		_depthFirst.call(this, [], linked, callback, context);
	};

	/**
	 * Traverse the tree breadth-first and call the callback
	 * @method breadthFirst
	 * @param {Function} callback Will receive (path, value, tree, context)
	 * @param {mixed} [context=null] To propagate some context to the callback
	 */
	this.breadthFirst = function(callback, context) {
		callback.call(this, [], linked, linked, context);
		_breadthFirst.call(this, [], linked, callback, context);
	};

	/**
	 * Calculates a diff between this tree and another tree
	 * @method diff
	 * @param {Q.Tree} tree
	 * @return {Q.Tree} This tree holds the results of the diff
	 */
	this.diff = function(tree) {
		var context = {
			from: this,
			to: tree,
			diff: new Q.Tree()
		};
		this.depthFirst(_diffTo, context);
		tree.depthFirst(_diffFrom, context);
		return context.diff;
	};

	function _diffTo (path, value, arr, context) {
		var valueTo = context.to.get(path, null);
		if ((!Q.isPlainObject(value) || !Q.isPlainObject(valueTo))
		&& valueTo !== value) {
			if (Q.isArrayLike(value) && Q.isArrayLike(valueTo)) {
				valueTo = {replace: valueTo};
			}
			context.diff.set(path, valueTo);
		}
		if (valueTo == null) {
			return false;
		}
	}

	function _diffFrom (path, value, arr, context) {
		var valueFrom = context.from.get(path, undefined);
		if (valueFrom === undefined) {
			context.diff.set(path, value);
			return false;
		}
	}

	/**
	 * Merges a tree over the top of an existing tree
	 * @method merge
	 * @param {Q.Tree|Object} second The Object or Q.Tree to merge over the existing tree.
	 * @param {boolean} [under=false] If true, merges the second under this tree, instead of over it.
	 *  By default, second is merged on top of this tree.
	 * @return {object} Returns the resulting tree, modified by the merge.
	 **/
	this.merge = function(second, under) {
		if (Q.typeOf(second) === 'Q.Tree') {
			this.merge(second.getAll(), under);
		} else if (typeof second === 'object') {
			if (under === true) {
				linked = _merge(second, linked);
			} else {
				linked = _merge(linked, second);
			}
		} else {
			return false;
		}
		return this;
	};

	function _merge(first, second) {
		var result = (Q.typeOf(second) === 'object' ? {} : []);
		var k;
		// copy first to the result
		if (Q.typeOf(first) === 'array' && second.replace) {
			return second.replace;
		}
		for (k in first) {
			result[k] = first[k];
		}
		switch (Q.typeOf(second)) {
			case 'array':
				// merge in values if they are not in array yet
				// if array contains scalar values only unique values are kept
				for (k=0; k<second.length; k++) {
					if (result.indexOf(second[k]) < 0) {
						result.push(second[k]);
					}
				}
				break;
			case 'object':
				for (k in second) {
					if (!(k in result)) {
						// key is not in result so just add it
						result[k] = second[k];
					} else if (typeof result[k] !== 'object' || result[k] === null) {
						// result[k] is scalar type
						result[k] = second[k];
					} else if (typeof second[k] !== 'object' || second[k] === null) {
						// key already in result but second[k] is scalar
						result[k] = second[k];
					} else {
						// otherwise second[k] is an object so merge it in
						result[k] = _merge(result[k], second[k]);
					}
				}
				break;
			case 'null':
				break;
			default:
				throw new Q.Exception("Cannot merge scalar '"+second+"' into Q.Tree");
		}
		return result;
	}
};

function _depthFirst(subpath, obj, callback, context)  {
	var k, v, path;
	for (k in obj) {
		v = obj[k];
		path = subpath.concat([k]);
		if (false === callback.call(this, path, v, obj, context)) {
			continue;
		}
		if (Q.isPlainObject(v)) {
			_depthFirst.call(this, path, v, callback, context);
		}
	}
}

function _breadthFirst(subpath, obj, callback, context) {
	var k, v, path;
	for (k in obj) {
		v = obj[k];
		path = subpath.concat([k]);
		if (false === callback.call(this, path, v, obj, context)) {
			break;
		}
	}
	for (k in obj) {
		if (Q.isPlainObject(v)) {
			path = subpath.concat([k]);
			_breadthFirst.call(this, path, v, callback);
		}
	}
}<commit_msg>Improved Q.Tree in Node to be like Q_Tree in PHP<commit_after>/**
 * @module Q
 */

var Q = require('../Q');
var fs = require('fs');

/**
 * Creates a Q.Tree object
 * @class Tree
 * @namespace Q
 * @constructor
 * @param {object} [linked={}] If supplied, then this object is
 *  used as the internal tree that Tree operates on.
 */
module.exports = function (linked) {

	if (linked === undefined) {
		linked = {};
	}

	if (Q.typeOf(linked) === 'Q.Tree') {
		linked = linked.getAll();
	}

	this.typename = "Q.Tree";

	/**
	 * Loads data into a tree from a file.
	 * @method load
	 * @param {string} filename The filename of the file to load.
	 * @param {function} [callback=null] Function to call back, with params (err, data)
	 * @throws {Q.Exception} if filename is not string or array of strings
	 */
	this.load = function (filename, callback) {
		var that = this;
		var filenames;
		switch (Q.typeOf(filename)) {
			case 'string':
				filenames = [filename];
				break;
			case 'array':
				filenames = filename;
				break;
			default:
				throw new Q.Exception("Q.Tree.load: filename has to be a string or array");
		}
		var p = new Q.Pipe(filenames, function (params) {
			// All the files were requested, time to merge them in the right order
			for (var i=0; i<filenames.length; ++i) {
				var k = filenames[i];
				// if (params[k][0] && params[k][0].code === 'ENOENT') {
				// 	// file doesn't exist, it's OK, keep going
				// }
				if (params[k][1]) {
					that.merge(params[k][1]);
				}
			}
			this.filename = filename;
			callback && callback.call(that, null, that.getAll());
		});
		for (var i=0; i<filenames.length; ++i) {
			(function (i) {
				var isPHP = (filenames[i].substr(-4).toLowerCase() === '.php');
				fs.readFile(filenames[i].replace('/', Q.DS), 'utf-8', function (err, data) {
					if (err) {
						p.fill(filenames[i])(err, null);
						return;
					}
					try {
						if (isPHP) {
							data = data.substring(
								data.indexOf("\n") + 1,
								data.lastIndexOf("\n")
							);
						}
						data = data.replace(/\s*(?!<")\/\*[^\*]+\*\/(?!")\s*/gi, '');
						data = data.replace(/\,\s*\}/, '}');
						data = JSON.parse(data);
					} catch (e) {
						p.fill(filenames[i])(e, null);
					}
					p.fill(filenames[i])(null, data);
				});
			})(i);
		}
	};

	/**
	 * Saves a (sub)tree of parameters to a file
	 * @method save
	 * @param {string} filename The filename to save into.
	 *   If tree was loaded from a single file, you can leave this blank to update that file.
	 * @param {array} [arrayPath=[]] Array of keys identifying the path of the subtree to save
	 * @param {array} [prefixPath=[]] Array of keys identifying the prefix path of the subtree to save
	 * @param {function} [callback=null] Function to call back, with params (err)
	 */
	this.save = function (filename, arrayPath, prefixPath, callback) {
		if (!filename && (typeof this.filename === 'string')) {
			filename = this.filename;
		}
		if (typeof arrayPath === 'function' || typeof arrayPath === 'undefined') {
			callback = arrayPath;
			arrayPath = prefixPath = [];
		} else if (typeof prefixPath === 'function' || typeof prefixPath === 'undefined') {
			callback = prefixPath;
			prefixPath = [];
		}

		var d, data = this.get.apply(this, [arrayPath]), that = this;

		if(Q.typeOf(prefixPath) !== 'array') prefixPath = prefixPath ? [prefixPath] : [];

		for (var i=prefixPath.length-1; i>=0; i--) {
			d = {};
			d[prefixPath[i]] = data;
			data = d;
		}

		to_save = JSON.stringify(data, null, '\t');
		var mask = process.umask(parseInt(Q.Config.get(['Q', 'internal', 'umask'], "0000"), 8));
		fs.writeFile(filename.replace('/', Q.DS), to_save, function (err) {
			process.umask(mask);
			callback && callback.call(that, err);
		});
	};

	/**
	 * Gets the entire tree of parameters
	 * @method getAll
	 * @return {object}
	 */
	this.getAll = function () {
		return linked;
	};

	/**
	 * Gets the value of a field in the tree
	 * @method get
	 * @param {string|array} [keys=[]] A key or an array of keys for traversing the tree.
	 * @param {mixed} [def=undefined] The value to return if the field is not found. Defaults to undefined.
	 * @return {mixed} The field if it is found, otherwise def or undefined.
	 * @throws {Q.Exception} if subtree is not an object
	 */
	this.get = function (keys, def) {
		if (typeof keys === 'undefined') keys = [];
		if (typeof keys === 'string') {
			var arr = [];
			for (var j=0; j<arguments.length-1; ++j) {
				arr.push(arguments[j]);
			}
			keys = arr;
			def = arguments[arguments.length-1];
		}
		var result = linked, key, sawKeys = [];
		for (var i=0, len = keys.length; i<len; ++i) {
			key = keys[i];
			if (typeof result !== 'object') {
				return def; // silently ignore the rest of the path
				// var sawString = '["' + sawKeys.join('"]["') + '"]';
				// throw new Q.Exception(
				// 	"Q.Tree: subtree at '"+sawString+"' is not an object",
				// 	{keys: keys, key: key}
				// );
			}
			if (!result || key == null || !(key in result)) {
				return def;
			}
			result = result[key];
			sawKeys.push(key);
		}
		return result;
	};

	/**
	 * Sets the value of a field in the tree. If only one argument is given,
	 * it is assigned as tree value
	 * @method set
	 * @param {string|array} keys A key or an array of keys for traversing the tree.
	 * @param {mixed} value The value to set for that field.
	 * @return {Q.Tree} Returns itself for chaining
	 * @chainable
	 */
	this.set = function (keys, value) {
		var k;
		if (arguments.length === 1) {
			linked = (typeof keys === "object") ? keys : [keys];
		} else {
			if (Q.typeOf(keys) === 'object') {
				for (k in keys) {
					linked[k] = keys[k];
				}
			} else {
				if (typeof keys === 'string') {
					var arr = [];
					for (var j=0; j<arguments.length-1; ++j) {
						arr.push(arguments[j]);
					}
					keys = arr;
					value = arguments[arguments.length-1];
				}
				var result = linked, key;
				for (var i=0, len = keys.length; i<len-1; ++i) {
					key = keys[i];
					if (!(key in result) || Q.typeOf(result[key]) !== 'object') {
						result[key] = {}; // overwrite with an object
					}
					result = result[key];
				}
				if (key = keys[len-1]) {
					result[key] = value;
				}
			}
		}
		return this;
	};

	/**
	 * Clears the value of a field, removing that key from the tree
	 * @method clear
	 * @param {string|array} [keys=null] A key or an array of keys for traversing the tree. If null, clears entire tree.
	 * @return {boolean} Returns whether the field to be cleared was found
	 */
	this.clear = function (keys) {
		if (!keys) {
			linked = {};
			return;
		}
		if (typeof keys === 'string') {
			keys = [keys];
		}
		var result = linked, key;
		for (var i=0, len = keys.length; i<len; ++i) {
			key = keys[i];
			if (typeof result !== 'object') {
				return false;
			}
			if (!(key in result)) {
				return false;
			}
			if (i === len - 1) {
				// return the final value
				delete result[key];
				return true;
			}
			result = result[key];
		}
		return false;
	};

	/**
	 * Traverse the tree depth-first and call the callback
	 * @method depthFirst
	 * @param {Function} callback Will receive (path, value, tree, context)
	 * @param {mixed} [context=null] To propagate some context to the callback
	 */
	this.depthFirst = function(callback, context) {
		_depthFirst.call(this, [], linked, callback, context);
	};

	/**
	 * Traverse the tree breadth-first and call the callback
	 * @method breadthFirst
	 * @param {Function} callback Will receive (path, value, tree, context)
	 * @param {mixed} [context=null] To propagate some context to the callback
	 */
	this.breadthFirst = function(callback, context) {
		callback.call(this, [], linked, linked, context);
		_breadthFirst.call(this, [], linked, callback, context);
	};

	/**
	 * Calculates a diff between this tree and another tree
	 * @method diff
	 * @param {Q.Tree} tree
	 * @return {Q.Tree} This tree holds the results of the diff
	 */
	this.diff = function(tree) {
		var context = {
			from: this,
			to: tree,
			diff: new Q.Tree()
		};
		this.depthFirst(_diffTo, context);
		tree.depthFirst(_diffFrom, context);
		return context.diff;
	};

	function _diffTo (path, value, arr, context) {
		var valueTo = context.to.get(path, null);
		if ((!Q.isPlainObject(value) || !Q.isPlainObject(valueTo))
		&& valueTo !== value) {
			if (Q.isArrayLike(value) && Q.isArrayLike(valueTo)) {
				valueTo = {replace: valueTo};
			}
			context.diff.set(path, valueTo);
		}
		if (valueTo == null) {
			return false;
		}
	}

	function _diffFrom (path, value, arr, context) {
		var valueFrom = context.from.get(path, undefined);
		if (valueFrom === undefined) {
			context.diff.set(path, value);
			return false;
		}
	}

	/**
	 * Merges a tree over the top of an existing tree
	 * @method merge
	 * @param {Q.Tree|Object} second The Object or Q.Tree to merge over the existing tree.
	 * @param {boolean} [under=false] If true, merges the second under this tree, instead of over it.
	 *  By default, second is merged on top of this tree.
	 * @return {object} Returns the resulting tree, modified by the merge.
	 **/
	this.merge = function(second, under) {
		if (Q.typeOf(second) === 'Q.Tree') {
			this.merge(second.getAll(), under);
		} else if (typeof second === 'object') {
			if (under === true) {
				linked = _merge(second, linked);
			} else {
				linked = _merge(linked, second);
			}
		} else {
			return false;
		}
		return this;
	};

	function _merge(first, second) {
		var result = (Q.typeOf(second) === 'object' ? {} : []);
		var k;
		// copy first to the result
		if (Q.typeOf(first) === 'array' && second.replace) {
			return second.replace;
		}
		for (k in first) {
			result[k] = first[k];
		}
		switch (Q.typeOf(second)) {
			case 'array':
				// merge in values if they are not in array yet
				// if array contains scalar values only unique values are kept
				for (k=0; k<second.length; k++) {
					if (result.indexOf(second[k]) < 0) {
						result.push(second[k]);
					}
				}
				break;
			case 'object':
				for (k in second) {
					if (!(k in result)) {
						// key is not in result so just add it
						result[k] = second[k];
					} else if (typeof result[k] !== 'object' || result[k] === null) {
						// result[k] is scalar type
						result[k] = second[k];
					} else if (typeof second[k] !== 'object' || second[k] === null) {
						// key already in result but second[k] is scalar
						result[k] = second[k];
					} else {
						// otherwise second[k] is an object so merge it in
						result[k] = _merge(result[k], second[k]);
					}
				}
				break;
			case 'null':
				break;
			default:
				throw new Q.Exception("Cannot merge scalar '"+second+"' into Q.Tree");
		}
		return result;
	}
};

function _depthFirst(subpath, obj, callback, context)  {
	var k, v, path;
	for (k in obj) {
		v = obj[k];
		path = subpath.concat([k]);
		if (false === callback.call(this, path, v, obj, context)) {
			continue;
		}
		if (Q.isPlainObject(v)) {
			_depthFirst.call(this, path, v, callback, context);
		}
	}
}

function _breadthFirst(subpath, obj, callback, context) {
	var k, v, path;
	for (k in obj) {
		v = obj[k];
		path = subpath.concat([k]);
		if (false === callback.call(this, path, v, obj, context)) {
			break;
		}
	}
	for (k in obj) {
		if (Q.isPlainObject(v)) {
			path = subpath.concat([k]);
			_breadthFirst.call(this, path, v, callback);
		}
	}
}<|endoftext|>


<commit_before>$(function(){
	$('.updateCurrentWordcount').on('submit', function(e){
		e.preventDefault();
	})
})<commit_msg>Remove unnecessary preventDefault in update_current_wordcount js.<commit_after>$(function(){
	$('.updateCurrentWordcount').on('submit', function(e){
	})
})<|endoftext|>


<commit_before>// 19: rest - with-destructuring
// To do: make all tests pass, leave the assert lines unchanged!

describe('rest with destrcturing', () => {

  it('rest parameter must be last', () => {
    const [...all] = [1, 2, 3, 4];
    assert.deepEqual(all, [1, 2, 3, 4]);
  });

  it('assign rest of an array to a variable', () => {
    const [, ...all] = [1, 2, 3, 4];
    assert.deepEqual(all, [2, 3, 4]);
  });

  it('concat differently', () => {
    const theEnd = [3, 4];
    const allInOne = [1, 2, ...theEnd];
    assert.deepEqual(allInOne, [1, 2, 3, 4]);
  });

  it('`apply` made simple, even for constructors', () => {
    const date = new Date(...[2015, 1, 1]);
    assert.deepEqual(new Date(2015, 1, 1), date);
  });

});
<commit_msg>A kata, all fails :).<commit_after>// 19: rest - with-destructuring
// To do: make all tests pass, leave the assert lines unchanged!

describe('rest with destrcturing', () => {

  it('rest parameter must be last', () => {
    const [all] = [1, 2, 3, 4];
    assert.deepEqual(all, [1, 2, 3, 4]);
  });

  it('assign rest of an array to a variable', () => {
    const [...all] = [1, 2, 3, 4];
    assert.deepEqual(all, [2, 3, 4]);
  });

  it('concat differently', () => {
    const theEnd = [3, 4];
    const allInOne = [1, 2, ...[theEnd]];
    assert.deepEqual(allInOne, [1, 2, 3, 4]);
  });

  it('`apply` made simple, even for constructors', () => {
    const theDate = [2015, 1, 1];
    const date = new Date(theDate);
    assert.deepEqual(new Date(2015, 1, 1), date);
  });

});
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

var fs;
var dir;

function onRead(entries) {
  console.log(entries);
}

function fsLoaded(fileSystem) {
  fs = fileSystem;
  console.log("file system loaded");
  var reader = fs.root.createReader();
  reader.readEntries(onRead);
}

window.webkitRequestFileSystem(window.PERSISTENT, 5 * 1024 * 1024 * 1024, fsLoaded);

function moduleDidLoad() {
  GitSalt.hideModule();
}

// Called by the GitSalt.js module.
function domContentLoaded(name, tc, config, width, height) {
  navigator.webkitPersistentStorage.requestQuota(1024 * 1024,
    function(bytes) {
      GitSalt.updateStatus(
          'Allocated ' + bytes + ' bytes of persistant storage.');
      GitSalt.attachDefaultListeners();
      GitSalt.createNaClModule(name, tc, config, width, height);
    },
    function(e) { alert('Failed to allocate space') });
}

// Called by the GitSalt.js module.
function attachListeners() {
  return;
}

function makeMessage(command, path) {
  // Package a message using a simple protocol containing:
  // command <path length> <path> <space-separated extra args>
  var msg = command;
  msg += ' ';
  msg += path.length;
  msg += ' ';
  msg += path;
  // Maybe add extra args
  for (var i = 2; i < arguments.length; ++i) {
    msg += ' ' + arguments[i];
  }
  return msg;
}

function saveFile() {
  if (GitSalt.naclModule) {
    GitSalt.naclModule.postMessage(makeMessage('sv', "/grvfs/spark3", "some text"));
  }
}

// Called by the GitSalt.js module.
function handleMessage(message_event) {
console.log(message_event);
var msg = message_event.data;
  var parts = msg.split('|');
  var command = parts[0];
  var args = parts.slice(1);

  if (command == 'ERR') {
    GitSalt.logMessage('Error: ' + args[0]);
  } else if (command == 'STAT') {
    GitSalt.logMessage(args[0]);
  } else if (command == 'READY') {
    GitSalt.logMessage('Filesystem ready!');
  } else if (command == 'DISP') {
    // Find the file editor that is currently visible.
    var fileEditorEl =
        document.querySelector('.function:not([hidden]) > textarea');
    // Rejoin args with pipe (|) -- there is only one argument, and it can
    // contain the pipe character.
    fileEditorEl.value = args.join('|');
  } else if (command == 'LIST') {
    var listDirOutputEl = document.getElementById('listDirOutput');

    // NOTE: files with | in their names will be incorrectly split. Fixing this
    // is left as an exercise for the reader.

    // Remove all children of this element...
    while (listDirOutputEl.firstChild) {
      listDirOutputEl.removeChild(listDirOutputEl.firstChild);
    }

    if (args.length) {
      // Add new <li> elements for each file.
      for (var i = 0; i < args.length; ++i) {
        var itemEl = document.createElement('li');
        itemEl.textContent = args[i];
        listDirOutputEl.appendChild(itemEl);
      }
    } else {
      var itemEl = document.createElement('li');
      itemEl.textContent = '<empty directory>';
      listDirOutputEl.appendChild(itemEl);
    }
  }
}
<commit_msg>Cleanup unused functions in git_salt.js<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Called by the GitSalt.js module.
function domContentLoaded(name, tc, config, width, height) {
  navigator.webkitPersistentStorage.requestQuota(1024 * 1024,
    function(bytes) {
      GitSalt.updateStatus(
          'Allocated ' + bytes + ' bytes of persistant storage.');
      GitSalt.attachDefaultListeners();
      GitSalt.createNaClModule(name, tc, config, width, height);
    },
    function(e) { alert('Failed to allocate space') });
}

// Called by the GitSalt.js module.
function attachListeners() {
  return;
}

// Called by the GitSalt.js module.
function handleMessage(message_event) {
console.log(message_event);
var msg = message_event.data;
  var parts = msg.split('|');
  var command = parts[0];
  var args = parts.slice(1);

  if (command == 'ERR') {
    GitSalt.logMessage('Error: ' + args[0]);
  } else if (command == 'STAT') {
    GitSalt.logMessage(args[0]);
  } else if (command == 'READY') {
    GitSalt.logMessage('Filesystem ready!');
  } else if (command == 'DISP') {
    // Find the file editor that is currently visible.
    var fileEditorEl =
        document.querySelector('.function:not([hidden]) > textarea');
    // Rejoin args with pipe (|) -- there is only one argument, and it can
    // contain the pipe character.
    fileEditorEl.value = args.join('|');
  } else if (command == 'LIST') {
    var listDirOutputEl = document.getElementById('listDirOutput');

    // NOTE: files with | in their names will be incorrectly split. Fixing this
    // is left as an exercise for the reader.

    // Remove all children of this element...
    while (listDirOutputEl.firstChild) {
      listDirOutputEl.removeChild(listDirOutputEl.firstChild);
    }

    if (args.length) {
      // Add new <li> elements for each file.
      for (var i = 0; i < args.length; ++i) {
        var itemEl = document.createElement('li');
        itemEl.textContent = args[i];
        listDirOutputEl.appendChild(itemEl);
      }
    } else {
      var itemEl = document.createElement('li');
      itemEl.textContent = '<empty directory>';
      listDirOutputEl.appendChild(itemEl);
    }
  }
}
<|endoftext|>


<commit_before>// inbox.js -- update Fluid app dock badge for Google Inbox
//
// *NOT A BOOKMARKLET*, requires Safari >= 9 for proper WebKit
// to be used with Fluid.
//
// Copyright (C) 2015 Dan Poggi
//
// This software may be modified and distributed under the terms
// of the MIT license. See the LICENSE file for details.

(function() {
  var onlyCheckUnread, unreadIncludesPinned, predicate, parentEl;

  // If you want the dock badge to only count unread emails instead of
  // all of them (Mailbox behavior), set this to true. I like it the
  // Mailbox way.
  onlyCheckUnread = false;
  // If ya set the above option to true, do you want that number to
  // include messages you've pinned? Something tells me you might.
  unreadIncludesPinned = true;

  // Since my Fluid app likes to capture Google Docs links no matter
  // what I do...
  if (window.location.host.indexOf("inbox.google.com") === -1) {
    return;
  }

  function updateBadge(badge) {
    window.fluid.dockBadge = badge;
  }

  function isUnread(el) {
    return el.getElementsByClassName("qG").length > 0;
  }
  function isPinned(el) {
    return el.getElementsByClassName("itemIconPinned").length > 0;
  }

  if (onlyCheckUnread && unreadIncludesPinned) {
    predicate = function(el) { return isUnread(el) || isPinned(el); };
  } else if (onlyCheckUnread) {
    predicate = isUnread;
  } else {
    predicate = function(el) { return true; };
  }

  function checkInbox() {
    var items, count;

    items = Array.from(document.getElementsByClassName("top-level-item"));
    count = items.filter(function(item) { return predicate(item); }).length;

    if (count >= 1) {
      updateBadge(count);
    } else {
      updateBadge("");
    }
  }

  if (typeof window.disconnectObserver !== "function") {
    window.disconnectObserver = function(event) {
      if (typeof window.observer !== "undefined") {
        window.observer.disconnect();
      }
    }
  }

  window.disconnectObserver();
  window.observer = new MutationObserver(function(mutations) {
    checkInbox();
  });
  window.observerConfig = {
    childList: true,
    attributes: false,
    characterData: false,
    subtree: true,
  };

  updateBadge("");

  parentEl = document.getElementById("Nr");
  if (parentEl !== null) {
    window.observer.observe(parentEl, window.observerConfig);
    checkInbox();
  } else {
    console.log("USERSCRIPT: Couldn't find parent element, dock badging disabled!");
  }

  // For some hope of dock badge predictability when handling multiple
  // tabs (multiple Gmail accounts).
  window.removeEventListener("beforeunload", window.disconnectObserver);
  window.addEventListener("beforeunload", window.disconnectObserver);
  window.removeEventListener("unload", window.disconnectObserver);
  window.addEventListener("unload", window.disconnectObserver);
})();
<commit_msg>SLOC trimming, because why not?!<commit_after>// inbox.js -- update Fluid app dock badge for Google Inbox
//
// *NOT A BOOKMARKLET*, requires Safari >= 9 for proper WebKit
// to be used with Fluid.
//
// Copyright (C) 2015 Dan Poggi
//
// This software may be modified and distributed under the terms
// of the MIT license. See the LICENSE file for details.

(function() {
  var onlyCheckUnread, unreadIncludesPinned, predicate, parentEl;

  // If you want the dock badge to only count unread emails instead of
  // all of them (Mailbox behavior), set this to true. I like it the
  // Mailbox way.
  onlyCheckUnread = false;
  // If ya set the above option to true, do you want that number to
  // include messages you've pinned? Something tells me you might.
  unreadIncludesPinned = true;

  // Since my Fluid app likes to capture Google Docs links no matter
  // what I do...
  if (window.location.host.indexOf("inbox.google.com") === -1) {
    return;
  }

  function updateBadge(badge) {
    window.fluid.dockBadge = badge;
  }

  function isUnread(el) {
    return el.getElementsByClassName("qG").length > 0;
  }
  function isPinned(el) {
    return el.getElementsByClassName("itemIconPinned").length > 0;
  }

  if (onlyCheckUnread && unreadIncludesPinned) {
    predicate = function(el) { return isUnread(el) || isPinned(el); };
  } else if (onlyCheckUnread) {
    predicate = isUnread;
  } else {
    predicate = function(el) { return true; };
  }

  function checkInbox() {
    var items, count;
    items = Array.from(document.getElementsByClassName("top-level-item"));
    count = items.filter(function(item) { return predicate(item); }).length;
    updateBadge(count >= 1 ? count : "");
  }

  if (typeof window.disconnectObserver !== "function") {
    window.disconnectObserver = function(event) {
      if (typeof window.observer !== "undefined") {
        window.observer.disconnect();
      }
    }
  }

  window.disconnectObserver();
  window.observer = new MutationObserver(function(mutations) {
    checkInbox();
  });
  window.observerConfig = {
    childList: true,
    attributes: false,
    characterData: false,
    subtree: true,
  };

  updateBadge("");
  parentEl = document.getElementById("Nr");
  if (parentEl !== null) {
    window.observer.observe(parentEl, window.observerConfig);
    checkInbox();
  } else {
    console.log("USERSCRIPT: Couldn't find parent element, dock badging disabled!");
  }

  // For some hope of dock badge predictability when handling multiple
  // tabs (multiple Gmail accounts).
  window.removeEventListener("beforeunload", window.disconnectObserver);
  window.addEventListener("beforeunload", window.disconnectObserver);
  window.removeEventListener("unload", window.disconnectObserver);
  window.addEventListener("unload", window.disconnectObserver);
})();
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
 * @fileoverview Defines the SIG type used in the OTR protocol.
 *
 * @author rcc@google.com (Ryan Chan)
 */

goog.provide('e2e.otr.Sig');

goog.require('e2e.async.Result');
goog.require('e2e.otr');
goog.require('e2e.otr.constants');
goog.require('e2e.otr.error.NotImplementedError');
goog.require('e2e.signer.Algorithm');
goog.require('e2e.signer.factory');
goog.require('goog.asserts');

/**
 * An OTRv3 SIG.
 * @constructor
 * @implements {e2e.otr.Serializable}
 * @param {!e2e.signer.key.Dsa} key The DSA key used for signing.
 * @param {!e2e.ByteArray} data The data to sign.
 */
e2e.otr.Sig = function(key, data) {
  assert(key.q.length == 20);
  this.sig_ = e2e.async.Result.getValue(
    e2e.signer.factory.get(e2e.signer.Algorithm.DSA, key).sign(data));
  e2e.otr.implements(e2e.otr.Sig, e2e.otr.Serializable);
};

/** @inheritDoc */
e2e.otr.Sig.prototype.serialize = function() {
  return e2e.otr.concat([this.sig_.r, this.sig_.s]);
};

/**
 * Extracts a SIG from the body, and returns the SIG.
 * @param {!Uint8Array} body The body from where to extract the data.
 * @return {!e2e.otr.Sig} The generated packet.
 */
e2e.otr.Sig.parse = function(body) {
  throw new e2e.otr.error.NotImplementedError('Not yet implemented.');
};
<commit_msg>SIG verify and deconstruct ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=73339814<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
 * @fileoverview Defines the SIG type used in the OTR protocol.
 *
 * @author rcc@google.com (Ryan Chan)
 */

goog.provide('e2e.otr.Sig');

goog.require('e2e.async.Result');
goog.require('e2e.otr');
goog.require('e2e.otr.constants');
goog.require('e2e.otr.error.NotImplementedError');
goog.require('e2e.signer.Algorithm');
goog.require('e2e.signer.factory');
goog.require('goog.asserts');

/**
 * An OTRv3 SIG.
 * @constructor
 * @implements {e2e.otr.Serializable}
 * @param {!e2e.signer.key.Dsa} key The DSA key used for signing.
 * @param {!e2e.ByteArray} data The data to sign.
 */
e2e.otr.Sig = function(key, data) {
  assert(key.q.length == 20);
  this.sig_ = e2e.async.Result.getValue(
    e2e.signer.factory.get(e2e.signer.Algorithm.DSA, key).sign(data));
  e2e.otr.implements(e2e.otr.Sig, e2e.otr.Serializable);
};

/** @inheritDoc */
e2e.otr.Sig.prototype.serialize = function() {
  return e2e.otr.concat([this.sig_.r, this.sig_.s]);
};

/**
 * Deconstructs SIG into component data.
 * @return {!e2e.signer.signature.Signature} The SIG data.
 */
e2e.otr.Sig.prototype.deconstruct = function() {
  return /** @type {!e2e.signer.signature.Signature} */ (
      goog.object.clone(this.sig_));
};

/**
 * Extracts a SIG from the body, and returns the SIG.
 * @param {!Uint8Array} body The body from where to extract the data.
 * @return {!e2e.otr.Sig} The generated packet.
 */
e2e.otr.Sig.parse = function(body) {
  throw new e2e.otr.error.NotImplementedError('Not yet implemented.');
};

/**
 * Verifies a signature.
 * @param {!e2e.signer.key.DsaPublicKey} key The public key for verification.
 * @param {!e2e.ByteArray} m The message to verify.
 * @param {!e2e.otr.Sig} sig The signature for the message.
 * @return {boolean} Whether the signature is valid.
 */
e2e.otr.Sig.verify = function(key, m, sig) {
  return e2e.async.Result.getValue(e2e.signer.factory.get(
      e2e.signer.Algorithm.DSA, key).verify(m, sig.deconstruct()));
};
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2017 Charles du Jeu - Abstrium SAS <team (at) pyd.io>
 * This file is part of Pydio.
 *
 * Pydio is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Pydio is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Pydio.  If not, see <http://www.gnu.org/licenses/>.
 *
 * The latest code can be found at <https://pydio.com>.
 */

import React from 'react'
import SoundObserver from './observer';
import { soundManager } from 'soundmanager2';
// import { threeSixtyPlayer } from '../../../sm/360-player/script/360player';

const self = this,
    pl = this,
    sm = soundManager, // soundManager instance
    uA = navigator.userAgent,
    isIE = (uA.match(/msie/i)),
    isOpera = (uA.match(/opera/i)),
    isSafari = (uA.match(/safari/i)),
    isChrome = (uA.match(/chrome/i)),
    isFirefox = (uA.match(/firefox/i)),
    isTouchDevice = (uA.match(/ipad|iphone/i)),
    hasRealCanvas = (typeof window.G_vmlCanvasManager === 'undefined' && typeof document.createElement('canvas').getContext('2d') !== 'undefined'),
    // I dunno what Opera doesn't like about this. I'm probably doing it wrong.
    fullCircle = (isOpera||isChrome?359.9:360);

const STATUS_DEFAULT = "STATUS_DEFAULT"
const STATUS_BUFFERING = "STATUS_BUFFERING"
const STATUS_PLAYING = "STATUS_PLAYING"
const STATUS_PAUSED = "STATUS_PAUSED"

const css = {
  STATUS_DEFAULT: 'sm2_link',
  STATUS_BUFFERING: 'sm2_buffering',
  STATUS_PLAYING: 'sm2_playing',
  STATUS_PAUSED: 'sm2_paused'
};

const soundObserver = new SoundObserver()

soundManager.setup({
    // path to directory containing SM2 SWF
    url: 'plugins/editor.soundmanager/sm/swf/',
});

class Player extends React.Component {
    constructor(props) {
        super(props)

        this.state = {
            status: STATUS_DEFAULT
        }
    }

    componentDidMount() {
        const {id, url, style, rich, autoPlay, onFinish} = this.props

        soundManager.onready(() => {
            const sound = soundManager.getSoundById(id)

            // First we check if it already exists
            if (sound) {
                return
            }

            soundManager.createSound({
                id: id,
                url: url,
                multiShot: false,
                onplay: () => soundObserver.play(id),
                onstop: () => soundObserver.stop(id),
                onpause: () => soundObserver.pause(id),
                onresume: () => soundObserver.resume(id),
                onfinish: () => soundObserver.finish(id),
                onbufferchange: () => soundObserver.bufferchange(id),
                whileloading: () => soundObserver.whileloading(id),
                whileplaying: () => soundObserver.whileplaying(id)
            })

            // Adding autoplay, listening to previous sound finish events
            const previousSoundID = soundManager.soundIDs.indexOf(id) - 1
            if (previousSoundID > -1) {
                soundObserver.observe("soundfinish" + soundManager.soundIDs[previousSoundID], () => {
                    soundManager.getSoundById(id).play()
                })
            }
        })

        const oCanvasCTX = this.canvas.getContext('2d');

        oCanvasCTX.translate(parseInt(style.width / 2), parseInt(style.height / 2));
        oCanvasCTX.rotate(deg2rad(-90))

        soundObserver.observe("soundplay" + id, () => this.setState({status: STATUS_PLAYING}))
        soundObserver.observe("soundpause" + id, () => this.setState({status: STATUS_PAUSED}))
        soundObserver.observe("soundbuffering" + id, () => this.setState({status: STATUS_BUFFERING}))
        soundObserver.observe("soundresume" + id, () => this.setState({status: STATUS_PLAYING}))
        soundObserver.observe("soundstop" + id, () => {
            clearCanvas(this.canvas)
            this.setState({status: STATUS_DEFAULT})
        })
        soundObserver.observe("soundfinish" + id, () => {
            clearCanvas(this.canvas)
            this.setState({status: STATUS_DEFAULT})

            if (typeof onFinish === "function") {
                onFinish()
            }
        })

        soundObserver.observe("soundwhileplaying" + id, () => {
            const sound = soundManager.getSoundById(id)
            const radius = rich ? 60: 20
            const width = rich ? 20 : 5

            if (this.canvas) {
                // Background
                drawSolidArc(this.canvas, '#ddd', radius, width, deg2rad(fullCircle), 0, false);
                // Loading ring
                drawSolidArc(this.canvas, '#ccc', radius, width, deg2rad(fullCircle*(sound.bytesLoaded/sound.bytesTotal)), 0, true);
                // Playing ring
                drawSolidArc(this.canvas, '#000', radius, width, deg2rad(fullCircle*(sound.position/sound.durationEstimate)), 0, true);
            }

            this.setState({
                time: getTime(sound.position,true),
            })
        })

        // Making sure the status is correct if sound is already playing
        const sound = soundManager.getSoundById(id)
        if (sound && sound.playState == 1) {
            if (sound.paused) {
                this.setState({
                    status: STATUS_PAUSED
                })
            } else {
                this.setState({
                    status: STATUS_PLAYING
                })
            }
        }
    }

    _handleEvent(e) {
        const {id, rich} = this.props

        const offset = rich ? 20 : 5
        const sound = soundManager.getSoundById(id)
        const coords = getMouseXY(e)
        const x = coords[0]
        const y = coords[1]

        const rect = this.canvas.getBoundingClientRect();

        const canvasMidX = rect.left + parseInt(this.canvas.width / 2)
        const canvasMidY = rect.top + parseInt(this.canvas.height / 2)

        const deltaX = x-canvasMidX
        const deltaY = y-canvasMidY

        if (Math.abs(deltaX) < offset && Math.abs(deltaY) < offset) {
            if (e.type == "mouseup") {
                soundManager.soundIDs.map((soundID) => soundID !== id && soundManager.sounds[soundID].stop())
                sound.togglePause()
            }
            return
        }

        const angle = Math.floor(fullCircle-(rad2deg(Math.atan2(deltaX,deltaY))+180));

        const position = Math.floor(sound.durationEstimate*(angle/fullCircle) / 1000)

        sound.setPosition(position * 1000);
        sound.resume()
    }

    handleMouseUp(e) {
        e.preventDefault()
        e.stopPropagation()

        this.dragging = false

        this._handleEvent(e)

        return false
    }

    handleMouseMove(e) {
        e.preventDefault()
        e.stopPropagation()

        if (this.dragging) {
            this._handleEvent(e)
        }

        return false
    }

    handleMouseDown(e) {
        e.preventDefault()
        e.stopPropagation()

        this.dragging = true

        this._handleEvent(e)

        return false
    }

    render() {
        const {status, time} = this.state
        let className="ui360"
        if (this.props.rich) {
            className += " ui360-vis"
        }

        const style = {
            ...this.props.style,
            "backgroundImage": "none",
        }

        const canvasStyle = {
            "width": this.props.style.width,
            "height": this.props.style.height,
            "backgroundColor": "transparent",
            "borderRadius": 0,
            "boxShadow": "none"
        }

        const childStyle = {
            "width": this.props.style.width,
            "height": this.props.style.height,
            "backgroundColor": "transparent",
            "border": 0,
            "borderRadius": 0,
            "boxShadow": "none"
        }

        const btnStyle = {
            "width": this.props.style.width,
            "height": this.props.style.height,
            "lineHeight": this.props.style.width + "px",
            "margin": 0,
            "top": 0,
            "left": 0,
            "bottom": 0,
            "right": 0
        }

        const timingStyle = {
            "width": this.props.style.width,
            "height": this.props.style.height,
            "lineHeight": this.props.style.height + "px"
        }

        const coverStyle = {
            "width": this.props.style.width,
            "height": this.props.style.height,
            "lineHeight": this.props.style.height + "px"
        }

        //

        return (

 this.handleMouseMove(e)} onMouseUp={(e) => this.handleMouseUp(e)} onMouseDown={(e) => this.handleMouseDown(e)}>

                        <canvas ref={(el) => this.canvas = el} className="sm2-canvas" style={canvasStyle} width={this.props.style.width} height={this.props.style.height}></canvas>

{time}

        )
    }
}

Player.propTypes = {
    // threeSixtyPlayer: React.PropTypes.object,
    autoPlay: React.PropTypes.bool,
    rich: React.PropTypes.bool.isRequired,
    onReady: React.PropTypes.func
}

Player.defaultProps = {
    autoPlay: false,
    rich: true
}

const deg2rad = function(nDeg) {
  return (nDeg * Math.PI/180);
};

const rad2deg = function(nRad) {
  return (nRad * 180/Math.PI);
};

const getTime = function(nMSec,bAsString) {

  // convert milliseconds to mm:ss, return as object literal or string
  var nSec = Math.floor(nMSec/1000),
      min = Math.floor(nSec/60),
      sec = nSec-(min*60);
  // if (min === 0 && sec === 0) return null; // return 0:00 as null
  return (bAsString?(min+':'+(sec<10?'0'+sec:sec)):{'min':min,'sec':sec});

};

const getArcEndpointCoords = function(radius, radians) {

  return {
    x: radius * Math.cos(radians),
    y: radius * Math.sin(radians)
  };

};

const clearCanvas = function(oCanvas) {

  var canvas = oCanvas,
      ctx = null,
      width, height;
  if (canvas && canvas.getContext){
    // use getContext to use the canvas for drawing
    ctx = canvas.getContext('2d');
  }
  width = canvas.offsetWidth;
  height = canvas.offsetHeight;
  ctx.clearRect(-(width/2), -(height/2), width, height);

};

const drawSolidArc = function(oCanvas, color, radius, width, radians, startAngle, noClear) {

  var x = radius,
      y = radius,
      canvas = oCanvas,
      ctx, innerRadius, doesntLikeZero, endPoint;

  if (canvas && canvas.getContext){
    // use getContext to use the canvas for drawing
    ctx = canvas.getContext('2d');
  }

  // re-assign canvas as the actual context
  oCanvas = ctx;

  if (!noClear) {
    clearCanvas(canvas);
  }
  // ctx.restore();

  if (color) {
    ctx.fillStyle = color;
  }

  oCanvas.beginPath();

  if (isNaN(radians)) {
    radians = 0;
  }

  innerRadius = radius-width;
  doesntLikeZero = (isOpera || isSafari); // safari 4 doesn't actually seem to mind.

  if (!doesntLikeZero || (doesntLikeZero && radius > 0)) {
    oCanvas.arc(0, 0, radius, startAngle, radians, false);
    endPoint = getArcEndpointCoords(innerRadius, radians);
    oCanvas.lineTo(endPoint.x, endPoint.y);
    oCanvas.arc(0, 0, innerRadius, radians, startAngle, true);
    oCanvas.closePath();
    oCanvas.fill();
  }

};

const getMouseXY = function(e) {

  // http://www.quirksmode.org/js/events_properties.html
  e = e?e:window.event;
  if (isTouchDevice && e.touches) {
    e = e.touches[0];
  }
  if (e.pageX || e.pageY) {
    return [e.pageX,e.pageY];
  } else if (e.clientX || e.clientY) {
    return [e.clientX+getScrollLeft(),e.clientY+getScrollTop()];
  }

};

const getScrollLeft = function() {
  return (document.body.scrollLeft+document.documentElement.scrollLeft);
};

const getScrollTop = function() {
  return (document.body.scrollTop+document.documentElement.scrollTop);
};

export default Player
<commit_msg>Fix for safari duration<commit_after>/*
 * Copyright 2007-2017 Charles du Jeu - Abstrium SAS <team (at) pyd.io>
 * This file is part of Pydio.
 *
 * Pydio is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Pydio is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Pydio.  If not, see <http://www.gnu.org/licenses/>.
 *
 * The latest code can be found at <https://pydio.com>.
 */

import React from 'react'
import SoundObserver from './observer';
import { soundManager } from 'soundmanager2';
// import { threeSixtyPlayer } from '../../../sm/360-player/script/360player';

const self = this,
    pl = this,
    sm = soundManager, // soundManager instance
    uA = navigator.userAgent,
    isIE = (uA.match(/msie/i)),
    isOpera = (uA.match(/opera/i)),
    isSafari = (uA.match(/safari/i)),
    isChrome = (uA.match(/chrome/i)),
    isFirefox = (uA.match(/firefox/i)),
    isTouchDevice = (uA.match(/ipad|iphone/i)),
    hasRealCanvas = (typeof window.G_vmlCanvasManager === 'undefined' && typeof document.createElement('canvas').getContext('2d') !== 'undefined'),
    // I dunno what Opera doesn't like about this. I'm probably doing it wrong.
    fullCircle = (isOpera||isChrome?359.9:360);

const STATUS_DEFAULT = "STATUS_DEFAULT"
const STATUS_BUFFERING = "STATUS_BUFFERING"
const STATUS_PLAYING = "STATUS_PLAYING"
const STATUS_PAUSED = "STATUS_PAUSED"

const css = {
  STATUS_DEFAULT: 'sm2_link',
  STATUS_BUFFERING: 'sm2_buffering',
  STATUS_PLAYING: 'sm2_playing',
  STATUS_PAUSED: 'sm2_paused'
};

const soundObserver = new SoundObserver()

soundManager.setup({
    // path to directory containing SM2 SWF
    url: 'plugins/editor.soundmanager/sm/swf/',
});

class Player extends React.Component {
    constructor(props) {
        super(props)

        this.state = {
            status: STATUS_DEFAULT
        }
    }

    componentDidMount() {
        const {id, url, style, rich, autoPlay, onFinish} = this.props

        soundManager.onready(() => {
            const sound = soundManager.getSoundById(id)

            // First we check if it already exists
            if (sound) {
                return
            }

            soundManager.createSound({
                id: id,
                url: url,
                multiShot: false,
                onplay: () => soundObserver.play(id),
                onstop: () => soundObserver.stop(id),
                onpause: () => soundObserver.pause(id),
                onresume: () => soundObserver.resume(id),
                onfinish: () => soundObserver.finish(id),
                onbufferchange: () => soundObserver.bufferchange(id),
                whileloading: () => soundObserver.whileloading(id),
                whileplaying: () => soundObserver.whileplaying(id)
            })

            // Adding autoplay, listening to previous sound finish events
            const previousSoundID = soundManager.soundIDs.indexOf(id) - 1
            if (previousSoundID > -1) {
                soundObserver.observe("soundfinish" + soundManager.soundIDs[previousSoundID], () => {
                    soundManager.getSoundById(id).play()
                })
            }
        })

        const oCanvasCTX = this.canvas.getContext('2d');

        oCanvasCTX.translate(parseInt(style.width / 2), parseInt(style.height / 2));
        oCanvasCTX.rotate(deg2rad(-90))

        soundObserver.observe("soundplay" + id, () => this.setState({status: STATUS_PLAYING}))
        soundObserver.observe("soundpause" + id, () => this.setState({status: STATUS_PAUSED}))
        soundObserver.observe("soundbuffering" + id, () => this.setState({status: STATUS_BUFFERING}))
        soundObserver.observe("soundresume" + id, () => this.setState({status: STATUS_PLAYING}))
        soundObserver.observe("soundstop" + id, () => {
            clearCanvas(this.canvas)
            this.setState({status: STATUS_DEFAULT})
        })
        soundObserver.observe("soundfinish" + id, () => {
            clearCanvas(this.canvas)
            this.setState({status: STATUS_DEFAULT})

            if (typeof onFinish === "function") {
                onFinish()
            }
        })

        soundObserver.observe("soundwhileplaying" + id, () => {
            const sound = soundManager.getSoundById(id)
            const radius = rich ? 60: 20
            const width = rich ? 20 : 5

            const durationEstimate = sound.durationEstimate > 0 ? sound.durationEstimate : sound.buffered[0].end

            if (this.canvas) {
                // Background
                drawSolidArc(this.canvas, '#dddddd', radius, width, deg2rad(fullCircle), 0, false);
                // Loading ring
                drawSolidArc(this.canvas, '#cccccc', radius, width, deg2rad(fullCircle*(sound.bytesLoaded/sound.bytesTotal)), 0, true);
                // Playing ring
                drawSolidArc(this.canvas, '#000000', radius, width, deg2rad(fullCircle*(sound.position/durationEstimate)), 0, true);
            }

            this.setState({
                time: getTime(sound.position,true),
            })
        })

        // Making sure the status is correct if sound is already playing
        const sound = soundManager.getSoundById(id)
        if (sound && sound.playState == 1) {
            if (sound.paused) {
                this.setState({
                    status: STATUS_PAUSED
                })
            } else {
                this.setState({
                    status: STATUS_PLAYING
                })
            }
        }
    }

    _handleEvent(e) {
        const {id, rich} = this.props

        const offset = rich ? 20 : 5
        const sound = soundManager.getSoundById(id)
        const coords = getMouseXY(e)
        const x = coords[0]
        const y = coords[1]

        const rect = this.canvas.getBoundingClientRect();

        const canvasMidX = rect.left + parseInt(this.canvas.width / 2)
        const canvasMidY = rect.top + parseInt(this.canvas.height / 2)

        const deltaX = x-canvasMidX
        const deltaY = y-canvasMidY

        if (Math.abs(deltaX) < offset && Math.abs(deltaY) < offset) {
            if (e.type == "mouseup") {
                soundManager.soundIDs.map((soundID) => soundID !== id && soundManager.sounds[soundID].stop())
                sound.togglePause()
            }
            return
        }

        const angle = Math.floor(fullCircle-(rad2deg(Math.atan2(deltaX,deltaY))+180));

        const durationEstimate = sound.durationEstimate > 0 ? sound.durationEstimate : sound.buffered[0].end
        const position = Math.floor(durationEstimate*(angle/fullCircle) / 1000)

        sound.setPosition(position * 1000);
        sound.resume()
    }

    handleMouseUp(e) {
        e.preventDefault()
        e.stopPropagation()

        this.dragging = false

        this._handleEvent(e)

        return false
    }

    handleMouseMove(e) {
        e.preventDefault()
        e.stopPropagation()

        if (this.dragging) {
            this._handleEvent(e)
        }

        return false
    }

    handleMouseDown(e) {
        e.preventDefault()
        e.stopPropagation()

        this.dragging = true

        this._handleEvent(e)

        return false
    }

    render() {
        const {status, time} = this.state
        let className="ui360"
        if (this.props.rich) {
            className += " ui360-vis"
        }

        const style = {
            ...this.props.style,
            "backgroundImage": "none",
        }

        const canvasStyle = {
            "width": this.props.style.width,
            "height": this.props.style.height,
            "backgroundColor": "transparent",
            "borderRadius": 0,
            "boxShadow": "none"
        }

        const childStyle = {
            "width": this.props.style.width,
            "height": this.props.style.height,
            "backgroundColor": "transparent",
            "border": 0,
            "borderRadius": 0,
            "boxShadow": "none"
        }

        const btnStyle = {
            "width": this.props.style.width,
            "height": this.props.style.height,
            "lineHeight": this.props.style.width + "px",
            "margin": 0,
            "top": 0,
            "left": 0,
            "bottom": 0,
            "right": 0
        }

        const timingStyle = {
            "width": this.props.style.width,
            "height": this.props.style.height,
            "lineHeight": this.props.style.height + "px"
        }

        const coverStyle = {
            "width": this.props.style.width,
            "height": this.props.style.height,
            "lineHeight": this.props.style.height + "px"
        }

        //

        return (

 this.handleMouseMove(e)} onMouseUp={(e) => this.handleMouseUp(e)} onMouseDown={(e) => this.handleMouseDown(e)}>

                        <canvas ref={(el) => this.canvas = el} className="sm2-canvas" style={canvasStyle} width={this.props.style.width} height={this.props.style.height}></canvas>

{time}

        )
    }
}

Player.propTypes = {
    // threeSixtyPlayer: React.PropTypes.object,
    autoPlay: React.PropTypes.bool,
    rich: React.PropTypes.bool.isRequired,
    onReady: React.PropTypes.func
}

Player.defaultProps = {
    autoPlay: false,
    rich: true
}

const deg2rad = function(nDeg) {
  return (nDeg * Math.PI/180);
};

const rad2deg = function(nRad) {
  return (nRad * 180/Math.PI);
};

const getTime = function(nMSec,bAsString) {

  // convert milliseconds to mm:ss, return as object literal or string
  var nSec = Math.floor(nMSec/1000),
      min = Math.floor(nSec/60),
      sec = nSec-(min*60);
  // if (min === 0 && sec === 0) return null; // return 0:00 as null
  return (bAsString?(min+':'+(sec<10?'0'+sec:sec)):{'min':min,'sec':sec});

};

const getArcEndpointCoords = function(radius, radians) {

  return {
    x: radius * Math.cos(radians),
    y: radius * Math.sin(radians)
  };

};

const clearCanvas = function(oCanvas) {

  var canvas = oCanvas,
      ctx = null,
      width, height;
  if (canvas && canvas.getContext){
    // use getContext to use the canvas for drawing
    ctx = canvas.getContext('2d');
  }
  width = canvas.offsetWidth;
  height = canvas.offsetHeight;
  ctx.clearRect(-(width/2), -(height/2), width, height);

};

const drawSolidArc = function(oCanvas, color, radius, width, radians, startAngle, noClear) {

  var x = radius,
      y = radius,
      canvas = oCanvas,
      ctx, innerRadius, doesntLikeZero, endPoint;

  if (canvas && canvas.getContext){
    // use getContext to use the canvas for drawing
    ctx = canvas.getContext('2d');
  }

  // re-assign canvas as the actual context
  oCanvas = ctx;

  if (!noClear) {
    clearCanvas(canvas);
  }
  // ctx.restore();

  if (color) {
    ctx.fillStyle = color;
  }

  oCanvas.beginPath();

  if (isNaN(radians)) {
    radians = 0;
  }

  innerRadius = radius-width;
  doesntLikeZero = (isOpera || isSafari); // safari 4 doesn't actually seem to mind.

  if (!doesntLikeZero || (doesntLikeZero && radius > 0)) {
    oCanvas.arc(0, 0, radius, startAngle, radians, false);
    endPoint = getArcEndpointCoords(innerRadius, radians);
    oCanvas.lineTo(endPoint.x, endPoint.y);
    oCanvas.arc(0, 0, innerRadius, radians, startAngle, true);
    oCanvas.closePath();
    oCanvas.fill();
  }

};

const getMouseXY = function(e) {

  // http://www.quirksmode.org/js/events_properties.html
  e = e?e:window.event;
  if (isTouchDevice && e.touches) {
    e = e.touches[0];
  }
  if (e.pageX || e.pageY) {
    return [e.pageX,e.pageY];
  } else if (e.clientX || e.clientY) {
    return [e.clientX+getScrollLeft(),e.clientY+getScrollTop()];
  }

};

const getScrollLeft = function() {
  return (document.body.scrollLeft+document.documentElement.scrollLeft);
};

const getScrollTop = function() {
  return (document.body.scrollTop+document.documentElement.scrollTop);
};

export default Player
<|endoftext|>


<commit_before>var Location = function(ui) {
	this._ui = ui
	var location = window.location
	this.updateActualValues()
	var self = this
	var context = ui._context
	context.window.on("hashchange", function() { self._ui.hash = location.hash }.bind(this))
	context.window.on("popstate", function() { self.updateActualValues() }.bind(this))
}

Location.prototype.updateActualValues = function() {
	var ui = this._ui
	var windowContext = ui._context.window.dom
	ui.hash = windowContext.location.hash
	ui.href = windowContext.location.href
	ui.port = windowContext.location.port
	ui.host = windowContext.location.host
	ui.origin = windowContext.location.origin
	ui.hostname = windowContext.location.hostname
	ui.pathname = windowContext.location.pathname
	ui.protocol = windowContext.location.protocol
	ui.search = windowContext.location.search
	ui.state = windowContext.history.state
}

Location.prototype.changeHref = function(href) {
	this._ui._context.window.dom.location.href = href
	this.updateActualValues()
}

Location.prototype.pushState = function(state, title, url) {
	var ui = this._ui
	var windowContext = ui._context.window.dom
	if (windowContext.location.hostname) {
		windowContext.history.pushState(state, title, url)
		this.updateActualValues()
	} else {
		ui._context.document.title = title
		this.state = state
	}
}

exports.createLocation = function(ui) {
	return new Location(ui)
}

exports.Location = Location
<commit_msg>Fix local state property changing in html location<commit_after>var Location = function(ui) {
	this._ui = ui
	var location = window.location
	this.updateActualValues()
	var self = this
	var context = ui._context
	context.window.on("hashchange", function() { self._ui.hash = location.hash }.bind(this))
	context.window.on("popstate", function() { self.updateActualValues() }.bind(this))
}

Location.prototype.updateActualValues = function() {
	var ui = this._ui
	var windowContext = ui._context.window.dom
	ui.hash = windowContext.location.hash
	ui.href = windowContext.location.href
	ui.port = windowContext.location.port
	ui.host = windowContext.location.host
	ui.origin = windowContext.location.origin
	ui.hostname = windowContext.location.hostname
	ui.pathname = windowContext.location.pathname
	ui.protocol = windowContext.location.protocol
	ui.search = windowContext.location.search
	ui.state = windowContext.history.state
}

Location.prototype.changeHref = function(href) {
	this._ui._context.window.dom.location.href = href
	this.updateActualValues()
}

Location.prototype.pushState = function(state, title, url) {
	var ui = this._ui
	var windowContext = ui._context.window.dom
	if (windowContext.location.hostname) {
		windowContext.history.pushState(state, title, url)
		this.updateActualValues()
	} else {
		ui._context.document.title = title
		this._ui.state = state
	}
}

exports.createLocation = function(ui) {
	return new Location(ui)
}

exports.Location = Location
<|endoftext|>