<commit_before>Highcharts.setOptions({
    global: {
        useUTC: false
    }
});

options = {
    chart: {
        renderTo: 'content',
        type: 'spline'
    },
    title: {
        text: 'Temperatures of the last 24h'
    },
    subtitle: {
        text: ''
    },
    colors: ['#4572A7', '#AA4643', '#89A54E', '#80699B', '#3D96AE', '#DB843D', '#92A8CD', '#A47D7C', '#B5CA92'],
    xAxis: {
        type: 'datetime',
        dateTimeLabelFormats: {
            hour: '%H. %M',
        }
    },
    yAxis: {
        title: {
            text: 'T (°C)'
        }
    },
    tooltip: {
        formatter: function () {
            return '' + this.series.name + '
' + Highcharts.dateFormat('%H:%M', this.x) + ': ' + this.y.toFixed(1) + '°C';
        }
    },

    plotOptions: {
        series: {
            marker: {
                radius: 2
            }
        }
    },

    lineWidth: 1,

    series: []
}

function computeSunrise(day, sunrise) {

    /*Sunrise/Sunset Algorithm taken from
     http://williams.best.vwh.net/sunrise_sunset_algorithm.htm
     inputs:
     day = day of the year
     sunrise = true for sunrise, false for sunset
     output:
     time of sunrise/sunset in hours */

    //lat, lon for Berlin, Germany
    var longitude = 13.408056;
    var latitude = 52.518611;
    var zenith = 90.83333333333333;
    var D2R = Math.PI / 180;
    var R2D = 180 / Math.PI;

    // convert the longitude to hour value and calculate an approximate time
    var lnHour = longitude / 15;
    var t;
    if (sunrise) {
        t = day + ((6 - lnHour) / 24);
    } else {
        t = day + ((18 - lnHour) / 24);
    }
    //calculate the Sun's mean anomaly
    var M = (0.9856 * t) - 3.289;

    //calculate the Sun's true longitude
    var L = M + (1.916 * Math.sin(M * D2R)) + (0.020 * Math.sin(2 * M * D2R)) + 282.634;
    if (L > 360) {
        L = L - 360;
    } else if (L < 0) {
        L = L + 360;
    }
    //calculate the Sun's right ascension
    var RA = R2D * Math.atan(0.91764 * Math.tan(L * D2R));
    if (RA > 360) {
        RA = RA - 360;
    } else if (RA < 0) {
        RA = RA + 360;
    }
    //right ascension value needs to be in the same qua
    var Lquadrant = (Math.floor(L / (90))) * 90;
    var RAquadrant = (Math.floor(RA / 90)) * 90;
    RA = RA + (Lquadrant - RAquadrant);

    //right ascension value needs to be converted into hours
    RA = RA / 15;

    //calculate the Sun's declination
    var sinDec = 0.39782 * Math.sin(L * D2R);
    var cosDec = Math.cos(Math.asin(sinDec));

    //calculate the Sun's local hour angle
    var cosH = (Math.cos(zenith * D2R) - (sinDec * Math.sin(latitude * D2R))) / (cosDec * Math.cos(latitude * D2R));
    var H;
    if (sunrise) {
        H = 360 - R2D * Math.acos(cosH)
    } else {
        H = R2D * Math.acos(cosH)
    }
    H = H / 15;

    //calculate local mean time of rising/setting
    var T = H + RA - (0.06571 * t) - 6.622;

    //adjust back to UTC
    var UT = T - lnHour;
    if (UT > 24) {
        UT = UT - 24;
    } else if (UT < 0) {
        UT = UT + 24;
    }

    //convert UT value to local time zone of latitude/longitude
    var localT = UT + 1;

    //convert to Milliseconds
    return localT * 3600 * 1000;
}

function dayOfYear() {
    var yearFirstDay = Math.floor(new Date().setFullYear(new Date().getFullYear(), 0, 1) / 86400000);
    var today = Math.ceil((new Date().getTime()) / 86400000);
    return today - yearFirstDay;
}
<commit_msg>switch to summer time<commit_after>Highcharts.setOptions({
    global: {
        useUTC: false
    }
});

options = {
    chart: {
        renderTo: 'content',
        type: 'spline'
    },
    title: {
        text: 'Temperatures of the last 24h'
    },
    subtitle: {
        text: ''
    },
    colors: ['#4572A7', '#AA4643', '#89A54E', '#80699B', '#3D96AE', '#DB843D', '#92A8CD', '#A47D7C', '#B5CA92'],
    xAxis: {
        type: 'datetime',
        dateTimeLabelFormats: {
            hour: '%H. %M',
        }
    },
    yAxis: {
        title: {
            text: 'T (°C)'
        }
    },
    tooltip: {
        formatter: function () {
            return '' + this.series.name + '
' + Highcharts.dateFormat('%H:%M', this.x) + ': ' + this.y.toFixed(1) + '°C';
        }
    },

    plotOptions: {
        series: {
            marker: {
                radius: 2
            }
        }
    },

    lineWidth: 1,

    series: []
}

function computeSunrise(day, sunrise) {

    /*Sunrise/Sunset Algorithm taken from
     http://williams.best.vwh.net/sunrise_sunset_algorithm.htm
     inputs:
     day = day of the year
     sunrise = true for sunrise, false for sunset
     output:
     time of sunrise/sunset in hours */

    //lat, lon for Berlin, Germany
    var longitude = 13.408056;
    var latitude = 52.518611;
    var zenith = 90.83333333333333;
    var D2R = Math.PI / 180;
    var R2D = 180 / Math.PI;

    // convert the longitude to hour value and calculate an approximate time
    var lnHour = longitude / 15;
    var t;
    if (sunrise) {
        t = day + ((6 - lnHour) / 24);
    } else {
        t = day + ((18 - lnHour) / 24);
    }
    //calculate the Sun's mean anomaly
    var M = (0.9856 * t) - 3.289;

    //calculate the Sun's true longitude
    var L = M + (1.916 * Math.sin(M * D2R)) + (0.020 * Math.sin(2 * M * D2R)) + 282.634;
    if (L > 360) {
        L = L - 360;
    } else if (L < 0) {
        L = L + 360;
    }
    //calculate the Sun's right ascension
    var RA = R2D * Math.atan(0.91764 * Math.tan(L * D2R));
    if (RA > 360) {
        RA = RA - 360;
    } else if (RA < 0) {
        RA = RA + 360;
    }
    //right ascension value needs to be in the same qua
    var Lquadrant = (Math.floor(L / (90))) * 90;
    var RAquadrant = (Math.floor(RA / 90)) * 90;
    RA = RA + (Lquadrant - RAquadrant);

    //right ascension value needs to be converted into hours
    RA = RA / 15;

    //calculate the Sun's declination
    var sinDec = 0.39782 * Math.sin(L * D2R);
    var cosDec = Math.cos(Math.asin(sinDec));

    //calculate the Sun's local hour angle
    var cosH = (Math.cos(zenith * D2R) - (sinDec * Math.sin(latitude * D2R))) / (cosDec * Math.cos(latitude * D2R));
    var H;
    if (sunrise) {
        H = 360 - R2D * Math.acos(cosH)
    } else {
        H = R2D * Math.acos(cosH)
    }
    H = H / 15;

    //calculate local mean time of rising/setting
    var T = H + RA - (0.06571 * t) - 6.622;

    //adjust back to UTC
    var UT = T - lnHour;
    if (UT > 24) {
        UT = UT - 24;
    } else if (UT < 0) {
        UT = UT + 24;
    }

    //convert UT value to local time zone of latitude/longitude
    var localT = UT + 2;

    //convert to Milliseconds
    return localT * 3600 * 1000;
}

function dayOfYear() {
    var yearFirstDay = Math.floor(new Date().setFullYear(new Date().getFullYear(), 0, 1) / 86400000);
    var today = Math.ceil((new Date().getTime()) / 86400000);
    return today - yearFirstDay;
}
<|endoftext|>


<commit_before>import * as React from "react"
import iconFox from "../images/fox-icon.svg"

const Footer = () => (

Find me

        Github

        Codepen

        LinkedIn

          Email me

      ©{` `}
      {new Date().getFullYear()}
      {` `}
      Craig Fox
      {` `}

      {` `}
      Front-end developer

)

export default Footer
<commit_msg>Update footer.js<commit_after>import * as React from "react"
import iconFox from "../images/fox-icon.svg"

const Footer = () => (

Find me

        Github

        Codepen

        LinkedIn

          Email

      ©{` `}
      {new Date().getFullYear()}
      {` `}
      Craig Fox
      {` `}

      {` `}
      Front-end developer

)

export default Footer
<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import Helmet from 'react-helmet'
import { StaticQuery, graphql } from 'gatsby'

import '../assets/scss/main.scss'

const Layout = ({ children, location }) => {

  let content;

  if (location && location.pathname === '/') {
    content = (

        {children}

    )
  } else {
    content = (

          {children}

    )
  }

  return (
    <StaticQuery
      query={graphql`
        query SiteTitleQuery {
          site {
            siteMetadata {
              title
            }
          }
        }
      `}
      render={data => (
        <>
          <Helmet
            title={data.site.siteMetadata.title}
            meta={[
              { name: 'description', content: 'Dan Nate - Web Developer' },
              { name: 'keywords', content: 'freelance, contractor, contract, web design, web developer, js, javascript, react' },
            ]}
          >

            <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css" integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU" crossorigin="anonymous" />
          </Helmet>
          {content}
        </>
      )}
    />
  )
}

Layout.propTypes = {
  children: PropTypes.node.isRequired,
}

export default Layout
<commit_msg>Analytics<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import Helmet from 'react-helmet'
import { StaticQuery, graphql } from 'gatsby'

import '../assets/scss/main.scss'

const Layout = ({ children, location }) => {

  let content;

  if (location && location.pathname === '/') {
    content = (

        {children}

    )
  } else {
    content = (

          {children}

    )
  }

  return (
    <StaticQuery
      query={graphql`
        query SiteTitleQuery {
          site {
            siteMetadata {
              title
            }
          }
        }
      `}
      render={data => (
        <>
          <Helmet
            title={data.site.siteMetadata.title}
            meta={[
              { name: 'description', content: 'Dan Nate - Web Developer' },
              { name: 'keywords', content: 'freelance, contractor, contract, web design, web developer, js, javascript, react' },
            ]}
          >

            <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css" integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU" crossorigin="anonymous" />
          </Helmet>
          {content}
        </>
      )}
    />
  )
}

Layout.propTypes = {
  children: PropTypes.node.isRequired,
}

export default Layout
<|endoftext|>


<commit_before>(function () {
    'use strict';

    angular
        .module('orange')
        .controller('SharingReportCtrl', SharingReportCtrl);

    SharingReportCtrl.$inject = ['$scope', '$stateParams', '$cordovaActionSheet', '$cordovaFile',
                                 'PDFViewerService', 'PatientService'];

    function SharingReportCtrl($scope, $stateParams, $cordovaActionSheet, $cordovaFile, pdf, PatientService) {
        var reportDir = cordova.file.externalCacheDirectory || cordova.file.cacheDirectory,
            fileName = $stateParams.id + '.pdf',
            printPdf = window.plugins.PrintPDF,
            pdfData,
            buttonLabels = ['by Email'],
            deviceVersion = _.map(device.version.split('.'), Number);

        // Only for iOS & Android 4.4+
        if (!(device.platform === 'Android' && (
                deviceVersion[0] < 4 || deviceVersion[0] === 4 && deviceVersion[1] < 4))) {
            buttonLabels.push('Print');
        }

        $scope.pdfURL = '';
        $scope.viewer = pdf.Instance('viewer');
        $scope.currentPage = 0;
        $scope.totalPages = 0;
        $scope.getReport = getReport;
        $scope.share = share;
        $scope.pdfHeight = window.innerHeight - 120;
        $scope.pdfWidth = window.innerWidth;

        $scope.pageLoaded = function(currentPage, totalPages) {
            $scope.currentPage = currentPage;
            $scope.totalPages = totalPages;
        };

        $scope.loadProgress = function(loaded, total, state) {
            console.log('loaded =', loaded, 'total =', total, 'state =', state);
            $scope.loading = false;
        };

        getReport();

        function getReport() {
            $scope.loading = true;
            $scope.$broadcast('scroll.refreshComplete');
            $scope.totalPages = 0;
            $scope.pdfURL = '';
            PatientService.getReport($stateParams.id, $stateParams.month).then(
                function (data) {
                    pdfData = data;
                    $cordovaFile.writeFile(reportDir, fileName, data, true).then(
                        setPfdUrl,
                        function (error) {
                            $scope.loading = false;
                            console.log(error);
                        }
                    );
                }
            )
        }

        function setPfdUrl() {
            $scope.pdfURL = reportDir + fileName;
        }

        function share() {
            $cordovaActionSheet.show({
                title: 'Select service for share',
                buttonLabels: buttonLabels,
                addCancelButtonWithLabel: 'Cancel',
                androidEnableCancelButton: true
            }).then(function (index) {
                switch (index) {
                    case 1:
                        window.plugins.socialsharing.shareViaEmail('', 'Orange Report', null, null, null, $scope.pdfURL);
                        break;
                    case 2:
                        if (buttonLabels.length !== index) {
                            break;
                        }
                        printPdf.isPrintingAvailable(function (success) {
                            if (success) {
                                printPdf.print({
                                    data: _arrayBufferToBase64(pdfData),
                                    title: 'Report'
                                });
                            } else {
                                console.log('print is not available');
                            }
                        });
                        break;
                }
            });
        }

        function _arrayBufferToBase64( buffer ) {
            var binary = '';
            var bytes = new Uint8Array( buffer );
            var len = bytes.byteLength;
            for (var i = 0; i < len; i++) {
                binary += String.fromCharCode( bytes[ i ] );
            }
            return window.btoa( binary );
        }
    }
})();
<commit_msg>[bugfix][ORANGE-183] Fix share PDF menu<commit_after>(function () {
    'use strict';

    angular
        .module('orange')
        .controller('SharingReportCtrl', SharingReportCtrl);

    SharingReportCtrl.$inject = ['$scope', '$stateParams', '$cordovaActionSheet', '$cordovaFile',
                                 'PDFViewerService', 'PatientService'];

    function SharingReportCtrl($scope, $stateParams, $cordovaActionSheet, $cordovaFile, pdf, PatientService) {
        var reportDir = cordova.file.externalCacheDirectory || cordova.file.cacheDirectory,
            fileName = $stateParams.id + '.pdf',
            printPdf = window.plugins.PrintPDF,
            pdfData,
            buttonLabels = ['Email'],
            deviceVersion = _.map(device.version.split('.'), Number);

        // Only for iOS & Android 4.4+
        if (!(device.platform === 'Android' && (
                deviceVersion[0] < 4 || deviceVersion[0] === 4 && deviceVersion[1] < 4))) {
            buttonLabels.push('Print');
        }

        $scope.pdfURL = '';
        $scope.viewer = pdf.Instance('viewer');
        $scope.currentPage = 0;
        $scope.totalPages = 0;
        $scope.getReport = getReport;
        $scope.share = share;
        $scope.pdfHeight = window.innerHeight - 120;
        $scope.pdfWidth = window.innerWidth;

        $scope.pageLoaded = function(currentPage, totalPages) {
            $scope.currentPage = currentPage;
            $scope.totalPages = totalPages;
        };

        $scope.loadProgress = function(loaded, total, state) {
            console.log('loaded =', loaded, 'total =', total, 'state =', state);
            $scope.loading = false;
        };

        getReport();

        function getReport() {
            $scope.loading = true;
            $scope.$broadcast('scroll.refreshComplete');
            $scope.totalPages = 0;
            $scope.pdfURL = '';
            PatientService.getReport($stateParams.id, $stateParams.month).then(
                function (data) {
                    pdfData = data;
                    $cordovaFile.writeFile(reportDir, fileName, data, true).then(
                        setPfdUrl,
                        function (error) {
                            $scope.loading = false;
                            console.log(error);
                        }
                    );
                }
            )
        }

        function setPfdUrl() {
            $scope.pdfURL = reportDir + fileName;
        }

        function share() {
            $cordovaActionSheet.show({
                title: 'Select service for share',
                buttonLabels: buttonLabels,
                addCancelButtonWithLabel: 'Cancel',
                androidEnableCancelButton: true
            }).then(function (index) {
                switch (index) {
                    case 1:
                        window.plugins.socialsharing.shareViaEmail('', 'Orange Report', null, null, null, $scope.pdfURL);
                        break;
                    case 2:
                        if (buttonLabels.length !== index) {
                            break;
                        }
                        printPdf.isPrintingAvailable(function (success) {
                            if (success) {
                                printPdf.print({
                                    data: _arrayBufferToBase64(pdfData),
                                    title: 'Report'
                                });
                            } else {
                                console.log('print is not available');
                            }
                        });
                        break;
                }
            });
        }

        function _arrayBufferToBase64( buffer ) {
            var binary = '';
            var bytes = new Uint8Array( buffer );
            var len = bytes.byteLength;
            for (var i = 0; i < len; i++) {
                binary += String.fromCharCode( bytes[ i ] );
            }
            return window.btoa( binary );
        }
    }
})();
<|endoftext|>


<commit_before>const debug = require('debug')('components:letter')
const React = require('react')
const { connect } = require('react-redux')
const request = require('superagent');
const { Link } = require('react-router')

class letter extends React.Component{

constructor() {
    super()

    this.playCapital = this.playCapital.bind(this)
    this.playLower = this.playLower.bind(this)
  }

  playCapital(cap) {
    this.refs[cap].load()
    this.refs[cap].play()
  }

  playLower(low) {
    this.refs[low].load()
    this.refs[low].play()
  }

  render(){
    debug(this.props)
    const cap = 'cap'
    const low = 'low'
    const { dispatch, letter } = this.props
    const singleLetter = letter.letter.letter

    return(

          <audio key={singleLetter.capitalSound} ref={`${cap}`} >
            <source src={singleLetter.capitalSound} preload='auto' />
          </audio>

  <audio key={singleLetter.lowerSound} ref={`${low}`} >
    <source src={singleLetter.lowerSound} preload='auto' />
  </audio>

        <button type="button" className="btn btn-lg display"
          onClick={() =>
            this.playCapital(cap)
          }>
          {singleLetter.capital}
        </button>

        <button type="button" className="btn btn-lg display"
          onClick={() =>
            this.playLower(low)
          }>
          {singleLetter.lowercase}
        </button>

        <button type="button" className="btn btn-lg display">
          {singleLetter.word}
        </button>

    )
  }

  handleClick(e){
    e.preventDefault()
    this.props.router.push(`/`)
  }

}

module.exports = connect((state) => state)(letter)

  //
  // <audio ref={`${cap}`} >
  //   <source src={singleLetter.capitalSound} preload='auto'/>
  // </audio>
  //
  // <audio ref={`${low}`} >
  //   <source src={singleLetter.lowerSound} preload='auto'/>
  // </audio>
<commit_msg>Indentation + removing commented code at the bottom<commit_after>const debug = require('debug')('components:letter')
const React = require('react')
const { connect } = require('react-redux')
const request = require('superagent');
const { Link } = require('react-router')

class letter extends React.Component{

constructor() {
    super()

    this.playCapital = this.playCapital.bind(this)
    this.playLower = this.playLower.bind(this)
  }

  playCapital(cap) {
    this.refs[cap].load()
    this.refs[cap].play()
  }

  playLower(low) {
    this.refs[low].load()
    this.refs[low].play()
  }

  render(){
    debug(this.props)
    const cap = 'cap'
    const low = 'low'
    const { dispatch, letter } = this.props
    const singleLetter = letter.letter.letter

    return(

          <audio key={singleLetter.capitalSound} ref={`${cap}`} >
            <source src={singleLetter.capitalSound} preload='auto' />
          </audio>

          <audio key={singleLetter.lowerSound} ref={`${low}`} >
            <source src={singleLetter.lowerSound} preload='auto' />
          </audio>

        <button type="button" className="btn btn-lg display"
          onClick={() =>
            this.playCapital(cap)
          }>
          {singleLetter.capital}
        </button>

        <button type="button" className="btn btn-lg display"
          onClick={() =>
            this.playLower(low)
          }>
          {singleLetter.lowercase}
        </button>

        <button type="button" className="btn btn-lg display">
          {singleLetter.word}
        </button>

    )
  }

  handleClick(e){
    e.preventDefault()
    this.props.router.push(`/`)
  }
}

module.exports = connect((state) => state)(letter)

<|endoftext|>


<commit_before>(async () => {
  const isCI = location.port === "8081" && location.search.includes("ci=true");
  const url = isCI ? "/csound.esm.js" : "/csound.dev.esm.js";
  const { Csound } = await import(url);

  const helloWorld = `
<CsoundSynthesizer>
<CsOptions>
    -odac
</CsOptions>
<CsInstruments>
    instr 1
    prints "Hello World!\n"
    endin
</CsInstruments>
<CsScore>
    i 1 0 0
</CsScore>
</CsoundSynthesizer>
`;

  const shortTone = `
<CsoundSynthesizer>
<CsOptions>
    -odac
</CsOptions>
<CsInstruments>
    0dbfs = 1

    chnset(1, "test1")
    chnset(2, "test2")

    instr 1
    out poscil(0dbfs/3, 440) * linen:a(1, .01, p3, .01)
    endin
</CsInstruments>
<CsScore>
    i 1 0 1
</CsScore>
</CsoundSynthesizer>
`;

  const shortTone2 = `
<CsoundSynthesizer>
<CsOptions>
    -odac
</CsOptions>
<CsInstruments>
    0dbfs = 1

    chnset(440, "freq")

    instr 1
    out poscil(0dbfs/3, chnget:k("freq")) * linen:a(1, .01, p3, .01)
    endin
</CsInstruments>
<CsScore>
    i 1 0 1
</CsScore>
</CsoundSynthesizer>
`;

  const stringChannelTest = `
<CsoundSynthesizer>
<CsOptions>
    -odac
</CsOptions>
<CsInstruments>
    0dbfs = 1

    chnset("test0", "strChannel")

</CsInstruments>
<CsScore>
    i 1 0 1
</CsScore>
</CsoundSynthesizer>
`;

  const pluginTest = `
<CsoundSynthesizer>
<CsOptions>
 -odac
</CsOptions>
<CsInstruments>
  0dbfs=1
  instr 1
    i1 = 2
    i2 = 2
    i3 mult i1, i2
    print i3
  endin
  instr 2
    k1 = 2
    k2 = 2
    k3 mult k1, k2
    printk2 k3
  endin
  instr 3
    a1 oscili 0dbfs, 440
    a2 oscili 0dbfs, 356
    a3 mult a1, a2
    out a3
  endin
</CsInstruments>
<CsScore>
  i1 0 0
  i2 0 1
  i3 0 2
  e 0 0
</CsScore>
</CsoundSynthesizer>
`;

  const cxxPluginTest = `
<CsoundSynthesizer>
<CsOptions>
 -odac
</CsOptions>
<CsInstruments>
  0dbfs=1
instr 1
 kcone_lengths[] fillarray 0.0316, 0.051, .3, 0.2
 kradii_in[] fillarray 0.0055, 0.00635, 0.0075, 0.0075
 kradii_out[]  fillarray 0.0055, 0.0075, 0.0075, 0.0275
 kcurve_type[] fillarray 1, 1, 1, 2
 kLength linseg 0.2, 2, 0.3
 kPick_Pos = 1.0
 kEndReflection init 1.0
 kEndReflection = 1.0
 kDensity = 1.0
 kComputeVisco = 0
 aImpulse mpulse .5, .1
 aFeedback, aSound resontube 0.005*aImpulse, kLength, kcone_lengths, kradii_in, kradii_out, kcurve_type, kEndReflection, kDensity, kPick_Pos, kComputeVisco
 out aSound
endin
</CsInstruments>
<CsScore>
i1 0 2
</CsScore>
</CsoundSynthesizer>
`;

  const ftableTest = `
<CsoundSynthesizer>
<CsOptions>
    -odac
</CsOptions>
<CsInstruments>
    instr 1
    prints "Hello Fibonnaci!\\n"
    prints "Table length %d\\n", tableng:i(1)
    endin
</CsInstruments>
<CsScore>
    f 1 0 8 -2 0 1 1 2 3 5 8 13
    i 1 0 -1
</CsScore>
</CsoundSynthesizer>
`;

  mocha.setup("bdd").fullTrace();

  if (isCI) {
    MochaWebdriverClient.install(mocha);
  }

  const csoundVariations = [
    { useWorker: false, useSPN: false, name: "SINGLE THREAD, AW" },
    { useWorker: false, useSPN: true, name: "SINGLE THREAD, SPN" },
    { useWorker: true, useSAB: true, name: "WORKER, AW, SAB" },
    { useWorker: true, useSAB: false, name: "WORKER, AW, Messageport" },
    { useWorker: true, useSAB: false, useSPN: true, name: "WORKER, SPN, MessagePort" },
  ];

  csoundVariations.forEach((test) => {
    describe(`@csound/browser : ${test.name}`, async () => {
      it("can be started", async function () {
        this.timeout(10000);
        const cs = await Csound(test);
        console.log(`Csound version: ${cs.name}`);
        const startReturn = await cs.start();
        assert.equal(startReturn, 0);
        await cs.stop();
        cs.terminateInstance && (await cs.terminateInstance());
      });

      it("has expected methods", async function () {
        this.timeout(10000);
        const cs = await Csound(test);
        assert.property(cs, "getAudioContext", "has .getAudioContext() method");
        assert.property(cs, "start", "has .start() method");
        assert.property(cs, "stop", "has .stop() method");
        assert.property(cs, "pause", "has .pause() method");
        await cs.stop();
        await cs.terminateInstance();
      });

      it("can use run using just compileOrc", async function () {
        this.timeout(10000);
        const cs = await Csound(test);
        await cs.compileOrc(`
        ksmps=64
        instr 1
          out oscili(.25, 110)
        endin
        schedule(1,0,1)
      `);
        const startReturn = await cs.start();
        assert.equal(startReturn, 0);
        await cs.stop();
        await cs.terminateInstance();
      });

      it("can play tone and get channel values", async function () {
        this.timeout(10000);
        const cs = await Csound(test);
        const compileReturn = await cs.compileCsdText(shortTone);
        assert.equal(compileReturn, 0);
        const startReturn = await cs.start();

        assert.equal(startReturn, 0);
        assert.equal(1, await cs.getControlChannel("test1"));
        assert.equal(2, await cs.getControlChannel("test2"));
        await cs.stop();
        await cs.terminateInstance();
      });

      it("can play tone and send channel values", async function () {
        this.timeout(10000);
        const cs = await Csound(test);
        const compileReturn = await cs.compileCsdText(shortTone2);
        assert.equal(compileReturn, 0);
        const startReturn = await cs.start();
        assert.equal(startReturn, 0);
        await cs.setControlChannel("freq", 880);
        assert.equal(880, await cs.getControlChannel("freq"));
        await cs.stop();
        await cs.terminateInstance();
      });

      it("can send and receive string channel values", async function () {
        this.timeout(10000);
        const cs = await Csound(test);
        const compileReturn = await cs.compileCsdText(stringChannelTest);
        assert.equal(compileReturn, 0);
        const startReturn = await cs.start();
        assert.equal(startReturn, 0);
        assert.equal("test0", await cs.getStringChannel("strChannel"));
        await cs.setStringChannel("strChannel", "test1");
        assert.equal("test1", await cs.getStringChannel("strChannel"));
        await cs.stop();
        await cs.terminateInstance();
      });

      it("can load and run plugins", async function () {
        const testWithPlugin = Object.assign(
          {
            withPlugins: ["./plugin_example.wasm"],
          },
          test,
        );
        const cs = await Csound(testWithPlugin);
        assert.equal(0, await cs.compileCsdText(pluginTest));
        await cs.start();
        await cs.stop();
        await cs.terminateInstance();
      });

      it("can load and run c++ plugins", async function () {
        const testWithPlugin = Object.assign(
          {
            withPlugins: ["./plugin_example_cxx.wasm"],
          },
          test,
        );
        const cs = await Csound(testWithPlugin);
        assert.equal(0, await cs.compileCsdText(cxxPluginTest));
        await cs.start();
        await cs.stop();
        await cs.terminateInstance();
      });

      it("emits public events in realtime performance", async function () {
        this.timeout(10000);
        const eventPlaySpy = sinon.spy();
        const eventPauseSpy = sinon.spy();
        const eventStopSpy = sinon.spy();
        const eventOnAudioNodeCreatedSpy = sinon.spy();

        const csoundObj = await Csound(test);

        csoundObj.on("play", eventPlaySpy);
        csoundObj.on("pause", eventPauseSpy);
        csoundObj.on("stop", eventStopSpy);
        csoundObj.on("onAudioNodeCreated", eventOnAudioNodeCreatedSpy);

        await csoundObj.setOption("-odac");
        await csoundObj.compileCsdText(shortTone);
        await csoundObj.start();
        await csoundObj.pause();
        await csoundObj.resume();
        await csoundObj.stop();

        assert(eventPlaySpy.calledTwice, 'The "play" event was emitted twice');
        assert(eventPauseSpy.calledOnce, 'The "pause" event was emitted once');
        assert(eventStopSpy.calledOnce, 'The "stop" event was emitted once');
        assert(
          eventOnAudioNodeCreatedSpy.calledOnce,
          'The "onAudioNodeCreated" event was emitted once',
        );
        assert(
          eventOnAudioNodeCreatedSpy.calledWith(sinon.match.instanceOf(AudioNode)),
          'The argument provided to the callback of "onAudioNodeCreated" was an AudioNode',
        );
        await csoundObj.terminateInstance();
      });

      it("can read and write ftables in realtime", async function () {
        const csoundObj = await Csound(test);
        await csoundObj.setOption("-odac");
        await csoundObj.compileCsdText(ftableTest);
        await csoundObj.start();

        // assert few indicies
        assert.equal(8, await csoundObj.tableLength(1), "The length of the table counts as 8");
        assert.equal(0, await csoundObj.tableGet(1, 0, "The first index is 0"));
        assert.equal(1, await csoundObj.tableGet(1, 1, "The second index is 1"));
        assert.equal(1, await csoundObj.tableGet(1, 2, "The third index is 2"));
        assert.equal(2, await csoundObj.tableGet(1, 3, "The fourth index is 3"));

        await csoundObj.tableSet(1, 0, 123);
        await csoundObj.tableSet(1, 1, 666);

        assert.equal(123, await csoundObj.tableGet(1, 0, "The first index was modified to 123"));
        assert.equal(666, await csoundObj.tableGet(1, 1, "The second index was modified to 666"));
        await csoundObj.stop();
        await csoundObj.terminateInstance();
      });

      it("can read and write arraybuffers to/from ftables in realtime", async function () {
        const csoundObj = await Csound(test);
        await csoundObj.setOption("-odac");
        await csoundObj.compileCsdText(ftableTest);
        await csoundObj.start();

        const tableLength = await csoundObj.tableLength(1);

        // we initialize a float64 typed array
        // using the length of the original csound table
        const float64array = new Float64Array(tableLength);

        // we then fill the arrays with test values
        float64array.set([1, 1.1, 1.01, 1.001]);

        // then we copy the the array from js into csound's runtime onto table 1
        await csoundObj.tableCopyIn(1, float64array);

        // assert that the values got delivered
        assert.equal(
          float64array[0],
          await csoundObj.tableGet(1, 0),
          "The first index from table1 matches the first index of the copied array",
        );
        assert.equal(
          float64array[1],
          await csoundObj.tableGet(1, 1),
          "The second index from table1 matches the second index of the copied array",
        );
        assert.equal(
          float64array[2],
          await csoundObj.tableGet(1, 2),
          "The third index from table1 matches the third index of the copied array",
        );
        assert.equal(
          float64array[3],
          await csoundObj.tableGet(1, 3),
          "The fourth index from table1 matches the fourth index of the copied array",
        );

        const csoundTableOneFloat64 = await csoundObj.tableCopyOut(1);
        // we convert it to normal Array for readability
        const csoundTableOneArray = Array.from(csoundTableOneFloat64);
        assert.deepEqual(
          csoundTableOneArray,
          [1, 1.1, 1.01, 1.001, 0, 0, 0, 0],
          "The current csound table matches the 4 numbers we copied into it followed by 4 empty values (0)",
        );
        await csoundObj.stop();
        await csoundObj.terminateInstance();
      });

      it("can stop() and reset() without start()", async function () {
        const csoundObj = await Csound(test);
        await csoundObj.stop();
        await csoundObj.reset();
        await csoundObj.start();
        await csoundObj.stop();
        await csoundObj.terminateInstance();
      });

      it("can start() -> stop() -> reset() and start again", async function () {
        this.timeout(10000);
        const csoundObj = await Csound(test);
        await csoundObj.compileCsdText(helloWorld);
        await csoundObj.start();
        await csoundObj.stop();
        await csoundObj.reset();
        await csoundObj.compileCsdText(helloWorld);
        await csoundObj.start();
        await csoundObj.stop();
        await csoundObj.terminateInstance();
      });
    });
  });

  const triggerEvent = "ontouchstart" in document.documentElement ? "touchend" : "click";
  document.querySelector("#all_tests").addEventListener(triggerEvent, async function () {
    mocha.fullTrace(true);
    mocha.checkLeaks(false); // worker + spn defenitely leaks
    mocha.cleanReferencesAfterRun(true);
    mocha.run();
  });
  if (isCI) {
    mocha.run();
  }
})();
<commit_msg>set global mocha timeout<commit_after>(async () => {
  const isCI = location.port === "8081" && location.search.includes("ci=true");
  const url = isCI ? "/csound.esm.js" : "/csound.dev.esm.js";
  const { Csound } = await import(url);

  const helloWorld = `
<CsoundSynthesizer>
<CsOptions>
    -odac
</CsOptions>
<CsInstruments>
    instr 1
    prints "Hello World!\n"
    endin
</CsInstruments>
<CsScore>
    i 1 0 0
</CsScore>
</CsoundSynthesizer>
`;

  const shortTone = `
<CsoundSynthesizer>
<CsOptions>
    -odac
</CsOptions>
<CsInstruments>
    0dbfs = 1

    chnset(1, "test1")
    chnset(2, "test2")

    instr 1
    out poscil(0dbfs/3, 440) * linen:a(1, .01, p3, .01)
    endin
</CsInstruments>
<CsScore>
    i 1 0 1
</CsScore>
</CsoundSynthesizer>
`;

  const shortTone2 = `
<CsoundSynthesizer>
<CsOptions>
    -odac
</CsOptions>
<CsInstruments>
    0dbfs = 1

    chnset(440, "freq")

    instr 1
    out poscil(0dbfs/3, chnget:k("freq")) * linen:a(1, .01, p3, .01)
    endin
</CsInstruments>
<CsScore>
    i 1 0 1
</CsScore>
</CsoundSynthesizer>
`;

  const stringChannelTest = `
<CsoundSynthesizer>
<CsOptions>
    -odac
</CsOptions>
<CsInstruments>
    0dbfs = 1

    chnset("test0", "strChannel")

</CsInstruments>
<CsScore>
    i 1 0 1
</CsScore>
</CsoundSynthesizer>
`;

  const pluginTest = `
<CsoundSynthesizer>
<CsOptions>
 -odac
</CsOptions>
<CsInstruments>
  0dbfs=1
  instr 1
    i1 = 2
    i2 = 2
    i3 mult i1, i2
    print i3
  endin
  instr 2
    k1 = 2
    k2 = 2
    k3 mult k1, k2
    printk2 k3
  endin
  instr 3
    a1 oscili 0dbfs, 440
    a2 oscili 0dbfs, 356
    a3 mult a1, a2
    out a3
  endin
</CsInstruments>
<CsScore>
  i1 0 0
  i2 0 1
  i3 0 2
  e 0 0
</CsScore>
</CsoundSynthesizer>
`;

  const cxxPluginTest = `
<CsoundSynthesizer>
<CsOptions>
 -odac
</CsOptions>
<CsInstruments>
  0dbfs=1
instr 1
 kcone_lengths[] fillarray 0.0316, 0.051, .3, 0.2
 kradii_in[] fillarray 0.0055, 0.00635, 0.0075, 0.0075
 kradii_out[]  fillarray 0.0055, 0.0075, 0.0075, 0.0275
 kcurve_type[] fillarray 1, 1, 1, 2
 kLength linseg 0.2, 2, 0.3
 kPick_Pos = 1.0
 kEndReflection init 1.0
 kEndReflection = 1.0
 kDensity = 1.0
 kComputeVisco = 0
 aImpulse mpulse .5, .1
 aFeedback, aSound resontube 0.005*aImpulse, kLength, kcone_lengths, kradii_in, kradii_out, kcurve_type, kEndReflection, kDensity, kPick_Pos, kComputeVisco
 out aSound
endin
</CsInstruments>
<CsScore>
i1 0 2
</CsScore>
</CsoundSynthesizer>
`;

  const ftableTest = `
<CsoundSynthesizer>
<CsOptions>
    -odac
</CsOptions>
<CsInstruments>
    instr 1
    prints "Hello Fibonnaci!\\n"
    prints "Table length %d\\n", tableng:i(1)
    endin
</CsInstruments>
<CsScore>
    f 1 0 8 -2 0 1 1 2 3 5 8 13
    i 1 0 -1
</CsScore>
</CsoundSynthesizer>
`;

  mocha.setup({ ui: "bdd", timeout: 10000 }).fullTrace();

  if (isCI) {
    MochaWebdriverClient.install(mocha);
  }

  const csoundVariations = [
    { useWorker: false, useSPN: false, name: "SINGLE THREAD, AW" },
    { useWorker: false, useSPN: true, name: "SINGLE THREAD, SPN" },
    { useWorker: true, useSAB: true, name: "WORKER, AW, SAB" },
    { useWorker: true, useSAB: false, name: "WORKER, AW, Messageport" },
    { useWorker: true, useSAB: false, useSPN: true, name: "WORKER, SPN, MessagePort" },
  ];

  csoundVariations.forEach((test) => {
    describe(`@csound/browser : ${test.name}`, async () => {
      it("can be started", async function () {
        const cs = await Csound(test);
        console.log(`Csound version: ${cs.name}`);
        const startReturn = await cs.start();
        assert.equal(startReturn, 0);
        await cs.stop();
        cs.terminateInstance && (await cs.terminateInstance());
      });

      it("has expected methods", async function () {
        const cs = await Csound(test);
        assert.property(cs, "getAudioContext", "has .getAudioContext() method");
        assert.property(cs, "start", "has .start() method");
        assert.property(cs, "stop", "has .stop() method");
        assert.property(cs, "pause", "has .pause() method");
        await cs.stop();
        await cs.terminateInstance();
      });

      it("can use run using just compileOrc", async function () {
        const cs = await Csound(test);
        await cs.compileOrc(`
        ksmps=64
        instr 1
          out oscili(.25, 110)
        endin
        schedule(1,0,1)
      `);
        const startReturn = await cs.start();
        assert.equal(startReturn, 0);
        await cs.stop();
        await cs.terminateInstance();
      });

      it("can play tone and get channel values", async function () {
        const cs = await Csound(test);
        const compileReturn = await cs.compileCsdText(shortTone);
        assert.equal(compileReturn, 0);
        const startReturn = await cs.start();

        assert.equal(startReturn, 0);
        assert.equal(1, await cs.getControlChannel("test1"));
        assert.equal(2, await cs.getControlChannel("test2"));
        await cs.stop();
        await cs.terminateInstance();
      });

      it("can play tone and send channel values", async function () {
        const cs = await Csound(test);
        const compileReturn = await cs.compileCsdText(shortTone2);
        assert.equal(compileReturn, 0);
        const startReturn = await cs.start();
        assert.equal(startReturn, 0);
        await cs.setControlChannel("freq", 880);
        assert.equal(880, await cs.getControlChannel("freq"));
        await cs.stop();
        await cs.terminateInstance();
      });

      it("can send and receive string channel values", async function () {
        const cs = await Csound(test);
        const compileReturn = await cs.compileCsdText(stringChannelTest);
        assert.equal(compileReturn, 0);
        const startReturn = await cs.start();
        assert.equal(startReturn, 0);
        assert.equal("test0", await cs.getStringChannel("strChannel"));
        await cs.setStringChannel("strChannel", "test1");
        assert.equal("test1", await cs.getStringChannel("strChannel"));
        await cs.stop();
        await cs.terminateInstance();
      });

      it("can load and run plugins", async function () {
        const testWithPlugin = Object.assign(
          {
            withPlugins: ["./plugin_example.wasm"],
          },
          test,
        );
        const cs = await Csound(testWithPlugin);
        assert.equal(0, await cs.compileCsdText(pluginTest));
        await cs.start();
        await cs.stop();
        await cs.terminateInstance();
      });

      it("can load and run c++ plugins", async function () {
        const testWithPlugin = Object.assign(
          {
            withPlugins: ["./plugin_example_cxx.wasm"],
          },
          test,
        );
        const cs = await Csound(testWithPlugin);
        assert.equal(0, await cs.compileCsdText(cxxPluginTest));
        await cs.start();
        await cs.stop();
        await cs.terminateInstance();
      });

      it("emits public events in realtime performance", async function () {
        const eventPlaySpy = sinon.spy();
        const eventPauseSpy = sinon.spy();
        const eventStopSpy = sinon.spy();
        const eventOnAudioNodeCreatedSpy = sinon.spy();

        const csoundObj = await Csound(test);

        csoundObj.on("play", eventPlaySpy);
        csoundObj.on("pause", eventPauseSpy);
        csoundObj.on("stop", eventStopSpy);
        csoundObj.on("onAudioNodeCreated", eventOnAudioNodeCreatedSpy);

        await csoundObj.setOption("-odac");
        await csoundObj.compileCsdText(shortTone);
        await csoundObj.start();
        await csoundObj.pause();
        await csoundObj.resume();
        await csoundObj.stop();

        assert(eventPlaySpy.calledTwice, 'The "play" event was emitted twice');
        assert(eventPauseSpy.calledOnce, 'The "pause" event was emitted once');
        assert(eventStopSpy.calledOnce, 'The "stop" event was emitted once');
        assert(
          eventOnAudioNodeCreatedSpy.calledOnce,
          'The "onAudioNodeCreated" event was emitted once',
        );
        assert(
          eventOnAudioNodeCreatedSpy.calledWith(sinon.match.instanceOf(AudioNode)),
          'The argument provided to the callback of "onAudioNodeCreated" was an AudioNode',
        );
        await csoundObj.terminateInstance();
      });

      it("can read and write ftables in realtime", async function () {
        const csoundObj = await Csound(test);
        await csoundObj.setOption("-odac");
        await csoundObj.compileCsdText(ftableTest);
        await csoundObj.start();

        // assert few indicies
        assert.equal(8, await csoundObj.tableLength(1), "The length of the table counts as 8");
        assert.equal(0, await csoundObj.tableGet(1, 0, "The first index is 0"));
        assert.equal(1, await csoundObj.tableGet(1, 1, "The second index is 1"));
        assert.equal(1, await csoundObj.tableGet(1, 2, "The third index is 2"));
        assert.equal(2, await csoundObj.tableGet(1, 3, "The fourth index is 3"));

        await csoundObj.tableSet(1, 0, 123);
        await csoundObj.tableSet(1, 1, 666);

        assert.equal(123, await csoundObj.tableGet(1, 0, "The first index was modified to 123"));
        assert.equal(666, await csoundObj.tableGet(1, 1, "The second index was modified to 666"));
        await csoundObj.stop();
        await csoundObj.terminateInstance();
      });

      it("can read and write arraybuffers to/from ftables in realtime", async function () {
        const csoundObj = await Csound(test);
        await csoundObj.setOption("-odac");
        await csoundObj.compileCsdText(ftableTest);
        await csoundObj.start();

        const tableLength = await csoundObj.tableLength(1);

        // we initialize a float64 typed array
        // using the length of the original csound table
        const float64array = new Float64Array(tableLength);

        // we then fill the arrays with test values
        float64array.set([1, 1.1, 1.01, 1.001]);

        // then we copy the the array from js into csound's runtime onto table 1
        await csoundObj.tableCopyIn(1, float64array);

        // assert that the values got delivered
        assert.equal(
          float64array[0],
          await csoundObj.tableGet(1, 0),
          "The first index from table1 matches the first index of the copied array",
        );
        assert.equal(
          float64array[1],
          await csoundObj.tableGet(1, 1),
          "The second index from table1 matches the second index of the copied array",
        );
        assert.equal(
          float64array[2],
          await csoundObj.tableGet(1, 2),
          "The third index from table1 matches the third index of the copied array",
        );
        assert.equal(
          float64array[3],
          await csoundObj.tableGet(1, 3),
          "The fourth index from table1 matches the fourth index of the copied array",
        );

        const csoundTableOneFloat64 = await csoundObj.tableCopyOut(1);
        // we convert it to normal Array for readability
        const csoundTableOneArray = Array.from(csoundTableOneFloat64);
        assert.deepEqual(
          csoundTableOneArray,
          [1, 1.1, 1.01, 1.001, 0, 0, 0, 0],
          "The current csound table matches the 4 numbers we copied into it followed by 4 empty values (0)",
        );
        await csoundObj.stop();
        await csoundObj.terminateInstance();
      });

      it("can stop() and reset() without start()", async function () {
        const csoundObj = await Csound(test);
        await csoundObj.stop();
        await csoundObj.reset();
        await csoundObj.start();
        await csoundObj.stop();
        await csoundObj.terminateInstance();
      });

      it("can start() -> stop() -> reset() and start again", async function () {
        const csoundObj = await Csound(test);
        await csoundObj.compileCsdText(helloWorld);
        await csoundObj.start();
        await csoundObj.stop();
        await csoundObj.reset();
        await csoundObj.compileCsdText(helloWorld);
        await csoundObj.start();
        await csoundObj.stop();
        await csoundObj.terminateInstance();
      });
    });
  });

  const triggerEvent = "ontouchstart" in document.documentElement ? "touchend" : "click";
  document.querySelector("#all_tests").addEventListener(triggerEvent, async function () {
    mocha.fullTrace(true);
    mocha.checkLeaks(false); // worker + spn defenitely leaks
    mocha.cleanReferencesAfterRun(true);
    mocha.run();
  });
  if (isCI) {
    mocha.run();
  }
})();
<|endoftext|>


<commit_before>
define(function() {

    $.fn.initInlineEditing = function() {
        return $(this)
        .attr('contenteditable', true)
        .off('focus').on('focus', function(evt) {
            $(evt.target).data('old-value', $(evt.target).html());
        })
        .off('keydown').on('keydown', function(evt) {
            if (evt.keyCode == 27) {
                $(evt.target).html($(evt.target).data('old-value')).blur();
                return;
            }
            if (evt.keyCode == 13) {
                $(evt.target).blur();
                evt.preventDefault();
            }
        });
    };

    return function(iframe, chart) {
        var doc = iframe.get(0).contentDocument,
            lastNotification;

        $('.label[data-column][data-row] span', doc)
            .initInlineEditing()
            .off('blur').on('blur', function(evt) {
                var span = $(evt.target),
                    val = $.trim(span.html()),
                    label = span.parent(),
                    transpose = chart.get('metadata.data.transpose', false),
                    dataset = chart.dataset(),
                    column = String(label.data('column')),
                    row = label.data('row'),
                    c = !transpose ? dataset.indexOf(column) : 0,
                    r = !transpose ? row+1 : dataset.indexOf(column);

                if (val !== '' && val != $.trim($(evt.target).data('old-value'))) {
                    var changes = chart.get('metadata.data.changes', []).slice(0),
                        change = { row: r, column: c, value: val };
                    changes.push(change);
                    chart.set('metadata.data.changes', changes);
                    if (!lastNotification) lastNotification = dw.backend.notify(dw.backend.messages.liveEditSuccess.replace('[', '').replace(']', ''));
                }
            });

        $('.chart-title', doc)
            .initInlineEditing()
            .off('blur').on('blur', function() {
                var new_val = $('.chart-title', doc).html();
                chart.set('title', new_val);
                $('#text-title').val(new_val);
            });

        $('.chart-intro', doc)
            .initInlineEditing()
            .off('blur').on('blur', function() {
                chart.set('metadata.describe.intro', $('.chart-intro', doc).html());
                $('#text-intro').val($('.chart-intro', doc).html());
            });
    };

});<commit_msg>allow multi-row inline editing<commit_after>
define(function() {

    $.fn.initInlineEditing = function() {
        return $(this)
        .attr('contenteditable', true)
        .off('focus').on('focus', function(evt) {
            $(evt.target).data('old-value', $(evt.target).html());
        })
        .off('keydown').on('keydown', function(evt) {
            if (evt.keyCode == 27) {
                $(evt.target).html($(evt.target).data('old-value')).blur();
                return;
            }
            if (evt.keyCode == 13) {
                $(evt.target).blur();
                evt.preventDefault();
            }
        });
    };

    return function(iframe, chart) {
        var doc = iframe.get(0).contentDocument,
            lastNotification;

        $('.label[data-column][data-row] span', doc)
            .initInlineEditing()
            .off('blur').on('blur', function(evt) {
                var span = $(evt.target),
                    val = $.trim(span.html()),
                    label = span.parent(),
                    transpose = chart.get('metadata.data.transpose', false),
                    dataset = chart.dataset(),
                    column = String(label.data('column')),
                    row = String(label.data('row')).split(','),
                    c = !transpose ? dataset.indexOf(column) : 0,
                    r = row.map(function(row) {
                        return !transpose ? (+row)+1 : dataset.indexOf(column);
                    });

                if (val !== '' && val != $.trim($(evt.target).data('old-value'))) {
                    var changes = chart.get('metadata.data.changes', []).slice(0);
                    r.forEach(function(r) {
                        change = { row: r, column: c, value: val };
                        console.log(change);
                        changes.push(change);
                    });
                    chart.set('metadata.data.changes', changes);
                    if (!lastNotification) lastNotification = dw.backend.notify(dw.backend.messages.liveEditSuccess.replace('[', '').replace(']', ''));
                }
            });

        $('.chart-title', doc)
            .initInlineEditing()
            .off('blur').on('blur', function() {
                var new_val = $('.chart-title', doc).html();
                chart.set('title', new_val);
                $('#text-title').val(new_val);
            });

        $('.chart-intro', doc)
            .initInlineEditing()
            .off('blur').on('blur', function() {
                chart.set('metadata.describe.intro', $('.chart-intro', doc).html());
                $('#text-intro').val($('.chart-intro', doc).html());
            });
    };

});<|endoftext|>


<commit_before>var charts = (function() {
    var fn = {};
    var renderPie = function (config, data, svgSelector) {
        return function () {
            // preaggregate the data in the case of multiple levels of aggregation
            // todo: this could be done on the server side too which is probably more efficient
            var aggregatedData = [];
            var aggregatedDataDict = {};
            var current, aggregation, record;
            for (var i = 0; i < data.length; i++) {
                current = data[i];
                aggregation = current[config.aggregation_column];
                if (!aggregatedDataDict.hasOwnProperty(aggregation)) {
                    record = {
                        x: aggregation,
                        y: 0
                    };
                    aggregatedDataDict[aggregation] = record;
                    aggregatedData.push(record);
                } else {
                    record = aggregatedDataDict[aggregation];
                }
                record.y += current[config.value_column];
            }

            var chart = nv.models.pieChart()
                .showLabels(true);

            d3.select(svgSelector)
                .datum(aggregatedData)
                .transition()
                .duration(500)
                .call(chart)
            ;
            nv.utils.windowResize(chart.update);
            return chart;
        };
    };

    var renderMultibarAggregate = function (config, data, svgSelector) {
        return function() {
            var transformedDataDict = {};
            var transformedData = [];
            var secondaryValues = {};
            var record, primary, current, secondary, value;  // loop variables

            // first create intermediate data structures to make it easy to generate
            // the formatted chart data.
            // this also aggregates if there are any duplicate key pairs in the data set.
            for (var i = 0; i < data.length; i++) {
                current = data[i];
                primary = current[config.primary_aggregation];
                if (!transformedDataDict.hasOwnProperty(primary)) {
                    record = {};
                    transformedDataDict[primary] = record;
                } else {
                    record = transformedDataDict[primary];
                }
                if (!record.hasOwnProperty(current[config.secondary_aggregation])) {
                    record[current[config.secondary_aggregation]] = 0;
                }
                secondaryValues[current[config.secondary_aggregation]] = null;
                record[current[config.secondary_aggregation]] += current[config.value_column];
            }

            // this annoying extra nested loop is because nvd3 appears to choke if the data
            // is not uniform
            for (primary in transformedDataDict) {
                record = {
                    "key": primary,
                    "values": []
                };
                if (transformedDataDict.hasOwnProperty(primary)) {
                    for (secondary in secondaryValues) {
                        if (secondaryValues.hasOwnProperty(secondary)) {
                            if (transformedDataDict[primary].hasOwnProperty(secondary)) {
                                value = transformedDataDict[primary][secondary];
                            } else {
                                value = 0;
                            }
                            record.values.push({
                                'x': secondary,
                                'y': value
                            });
                        }
                    }
                }
                transformedData.push(record);
            }
            var chart = nv.models.multiBarChart()
                .transitionDuration(350)
                .reduceXTicks(true)
                .rotateLabels(0)
                .showControls(true)
                .groupSpacing(0.1)
            ;

            d3.select(svgSelector)
                .datum(transformedData)
                .call(chart);
            nv.utils.windowResize(chart.update);
            return chart;
        };
    };

    var renderMultibar = function (config, data, svgSelector) {
        return function() {
            var valuesDict = {};
            var chartData =[];
            var i, j, current, record;

            // initialize records
            for (i = 0; i < config.y_axis_columns.length; i++) {
                record = {
                    key: config.y_axis_columns[i],
                    values: []
                };
                valuesDict[config.y_axis_columns[i]] = record;
                chartData.push(record);
            }
            for (i = 0; i < data.length; i++) {
                current = data[i];
                for (j = 0; j < config.y_axis_columns.length; j++) {
                    record = valuesDict[config.y_axis_columns[j]];
                    record.values.push({
                        x: current[config.x_axis_column],
                        y: current[config.y_axis_columns[j]]
                    });
                }
            }
            var chart = nv.models.multiBarChart()
                .transitionDuration(350)
                .reduceXTicks(true)
                .rotateLabels(0)
                .showControls(true)
                .groupSpacing(0.1)
                .stacked(true)
            ;

            d3.select(svgSelector)
                .datum(chartData)
                .call(chart);
            nv.utils.windowResize(chart.update);
            return chart;
        };
    };

    var chartMap = {
        'pie': renderPie,
        'multibar': renderMultibar,
        'multibar-aggregate': renderMultibarAggregate
    };

    fn.render = function (configs, data, chartContainer) {
        chartContainer.show();
        chartContainer.empty();
        for (var i = 0; i < configs.length; i++) {
            var config = configs[i];
            if (chartMap[config.type] === undefined) {
                console.error("Bad chart configuration: " + config.type);
            } else {
                if (config.title) {
                    $('<h2 />').text(config.title).appendTo(chartContainer);
                }
                var $svg = d3.select(chartContainer[0]).append("svg");
                var id = 'chart-' + i;
                $svg.attr({id: id, width: "50%", height: "200"});
                nv.addGraph(chartMap[config.type](config, data, '#' + id));
            }
        }
    };
    return fn;

})();<commit_msg>fix for null value crashing charts<commit_after>var charts = (function() {
    var fn = {};
    var renderPie = function (config, data, svgSelector) {
        return function () {
            // preaggregate the data in the case of multiple levels of aggregation
            // todo: this could be done on the server side too which is probably more efficient
            var aggregatedData = [];
            var aggregatedDataDict = {};
            var current, aggregation, record;
            for (var i = 0; i < data.length; i++) {
                current = data[i];
                aggregation = current[config.aggregation_column];
                if (!aggregatedDataDict.hasOwnProperty(aggregation)) {
                    record = {
                        x: aggregation,
                        y: 0
                    };
                    aggregatedDataDict[aggregation] = record;
                    aggregatedData.push(record);
                } else {
                    record = aggregatedDataDict[aggregation];
                }
                record.y += current[config.value_column];
            }

            var chart = nv.models.pieChart()
                .showLabels(true);

            d3.select(svgSelector)
                .datum(aggregatedData)
                .transition()
                .duration(500)
                .call(chart)
            ;
            nv.utils.windowResize(chart.update);
            return chart;
        };
    };

    var renderMultibarAggregate = function (config, data, svgSelector) {
        return function() {
            var transformedDataDict = {};
            var transformedData = [];
            var secondaryValues = {};
            var record, primary, current, secondary, value;  // loop variables

            // first create intermediate data structures to make it easy to generate
            // the formatted chart data.
            // this also aggregates if there are any duplicate key pairs in the data set.
            for (var i = 0; i < data.length; i++) {
                current = data[i];
                primary = current[config.primary_aggregation];
                if (!transformedDataDict.hasOwnProperty(primary)) {
                    record = {};
                    transformedDataDict[primary] = record;
                } else {
                    record = transformedDataDict[primary];
                }
                if (!record.hasOwnProperty(current[config.secondary_aggregation])) {
                    record[current[config.secondary_aggregation]] = 0;
                }
                secondaryValues[current[config.secondary_aggregation]] = null;
                record[current[config.secondary_aggregation]] += current[config.value_column];
            }

            // this annoying extra nested loop is because nvd3 appears to choke if the data
            // is not uniform
            for (primary in transformedDataDict) {
                record = {
                    "key": primary,
                    "values": []
                };
                if (transformedDataDict.hasOwnProperty(primary)) {
                    for (secondary in secondaryValues) {
                        if (secondaryValues.hasOwnProperty(secondary)) {
                            if (transformedDataDict[primary].hasOwnProperty(secondary)) {
                                value = transformedDataDict[primary][secondary];
                            } else {
                                value = 0;
                            }
                            record.values.push({
                                'x': secondary,
                                'y': value
                            });
                        }
                    }
                }
                transformedData.push(record);
            }
            var chart = nv.models.multiBarChart()
                .transitionDuration(350)
                .reduceXTicks(true)
                .rotateLabels(0)
                .showControls(true)
                .groupSpacing(0.1)
            ;

            d3.select(svgSelector)
                .datum(transformedData)
                .call(chart);
            nv.utils.windowResize(chart.update);
            return chart;
        };
    };

    var renderMultibar = function (config, data, svgSelector) {
        return function() {
            var valuesDict = {};
            var chartData =[];
            var i, j, current, record;

            // initialize records
            for (i = 0; i < config.y_axis_columns.length; i++) {
                record = {
                    key: config.y_axis_columns[i],
                    values: []
                };
                valuesDict[config.y_axis_columns[i]] = record;
                chartData.push(record);
            }
            for (i = 0; i < data.length; i++) {
                current = data[i];
                for (j = 0; j < config.y_axis_columns.length; j++) {
                    record = valuesDict[config.y_axis_columns[j]];
                    record.values.push({
                        x: current[config.x_axis_column] || '',
                        y: current[config.y_axis_columns[j]]
                    });
                }
            }
            var chart = nv.models.multiBarChart()
                .transitionDuration(350)
                .reduceXTicks(true)
                .rotateLabels(0)
                .showControls(true)
                .groupSpacing(0.1)
                .stacked(true)
            ;

            d3.select(svgSelector)
                .datum(chartData)
                .call(chart);
            nv.utils.windowResize(chart.update);
            return chart;
        };
    };

    var chartMap = {
        'pie': renderPie,
        'multibar': renderMultibar,
        'multibar-aggregate': renderMultibarAggregate
    };

    fn.render = function (configs, data, chartContainer) {
        chartContainer.show();
        chartContainer.empty();
        for (var i = 0; i < configs.length; i++) {
            var config = configs[i];
            if (chartMap[config.type] === undefined) {
                console.error("Bad chart configuration: " + config.type);
            } else {
                if (config.title) {
                    $('<h2 />').text(config.title).appendTo(chartContainer);
                }
                var $svg = d3.select(chartContainer[0]).append("svg");
                var id = 'chart-' + i;
                $svg.attr({id: id, width: "50%", height: "200"});
                nv.addGraph(chartMap[config.type](config, data, '#' + id));
            }
        }
    };
    return fn;

})();<|endoftext|>


<commit_before>// Copyright (c) 2012 Johannes Zellner webmaster@nebulon.de - All Rights Reserved
// DOM renderer

"use strict";

/*
 **************************************************
 * Predefined basic elements
 **************************************************
 */
function Item(id, parent) {
    var elem = new Element(id, parent);

    elem.addProperty("-webkit-user-select", "none");
    elem.addProperty("-moz-user-select", "none");
    elem.addProperty("hoverEnabled", false);
    elem.addProperty("mouseAbsX", 0);
    elem.addProperty("mouseAbsY", 0);
    elem.addProperty("mouseRelX", 0);
    elem.addProperty("mouseRelY", 0);
    elem.addProperty("width", 100);
    elem.addProperty("height", 100);
    elem.addProperty("top", 0);
    elem.addProperty("bottom", function () { return this.top + this.height; });
    elem.addProperty("verticalCenter", function () { return this.height / 2.0; });
    elem.addProperty("left", 0);
    elem.addProperty("right", function () { return this.left + this.width; });
    elem.addProperty("horizontalCenter", function () { return this.width / 2.0; });
    elem.addProperty("mouseRelStartX", 0);
    elem.addProperty("mouseRelStartY", 0);
    elem.addProperty("mousePressed", false);
    elem.addProperty("containsMouse", false);
    elem.addProperty("scale", 1);
    elem.addProperty("-webkit-transform", function () {
        var s = this.scale.toFixed(10);
        return "scale(" + s + ", " + s + ")";
    });

    return elem;
}

// FIXME global leak
var tmpTextElement;
function Text(id, parent) {
    var elem = new Item(id, parent);

    elem.addProperty("textWidth", 0);
    elem.addProperty("textHeight", 0);
    elem.addProperty("font-size", "12pt");
    elem.addProperty("font-family", "Source Code Pro");
    elem.addProperty("text", "");
    elem.addProperty("width", function() { return this.textWidth; });
    elem.addProperty("height", function() { return this.textHeight; });

    // all this below for calculating the text width
    if (!tmpTextElement) {
        tmpTextElement = window.document.createElement("div");
        tmpTextElement.style.position = "absolute";
        tmpTextElement.style.visibility = "hidden";
        tmpTextElement.style.width = "auto";
        tmpTextElement.style.height = "auto";
        document.body.appendChild(tmpTextElement);
    }

    elem.addChanged("text", function () {
        var tmpProperty = elem.text;
        var width = 0;
        var height = 0;

        if (tmpTextElement.textContent === tmpProperty) {
            width = (tmpTextElement.clientWidth + 1);
            height = (tmpTextElement.clientHeight + 1);
        } else if (tmpProperty !== "") {
            tmpTextElement.textContent = tmpProperty;
            width = (tmpTextElement.clientWidth + 1);
            height = (tmpTextElement.clientHeight + 1);
        }

        elem.textWidth = width;
        elem.textHeight = height;
    });

    return elem;
}

function Rectangle(id, parent) {
    var elem = new Item(id, parent);

    elem.addProperty("background-color", "white");
    elem.addProperty("border-color", "black");
    elem.addProperty("border-style", "solid");
    elem.addProperty("border-width", 1);
    elem.addProperty("border-radius", 0);

    return elem;
}

function Image(id, parent) {
    var elem = new Item(id, parent);

    elem.addProperty("text-align", "center");
    elem.addProperty("src", "image.png");
    elem.addProperty("background-image", function () {
        if (this.src.indexOf("url('") === 0) {
            return this.src;
        }

        return "url('" + this.src + "')";
    });

    return elem;
}

function Button(id, parent) {
    var elem = new Rectangle(id, parent);

    elem.addProperty("text-align", "center");
    elem.addProperty("cursor", "pointer");
    elem.addProperty("background-color", "lightgray");

    return elem;
}

/*
 **************************************************
 * DOM renderer
 **************************************************
 */
function QuickRendererDOM() {

}

QuickRendererDOM.prototype.createElement = function (typeHint, object) {
    var elem;

    if (typeHint === 'object') {
        elem = document.createElement('object');
    } else if (typeHint === 'item') {
        elem = document.createElement('div');
        elem.style.position = 'absolute';
    } else if (typeHint === 'input') {
        elem = document.createElement('input');
    }

    elem.onclick = function () { object.emit('click'); };
    elem.onmouseover = function () {
        if (object.hoverEnabled) {
            object.containsMouse = true;
            object.emit('mouseover');
        }
    };
    elem.onmouseout = function () {
        if (object.hoverEnabled) {
            object.containsMouse = false;
            object.emit('mouseout');
        }
    };
    elem.onmousedown = function (event) {
        object.mousePressed = true;
        object.mouseRelStartX = event.offsetX;
        object.mouseRelStartY = event.offsetY;
        object.emit('mousedown');
    };
    elem.onmouseup = function (event) {
        object.mousePressed = false;
        object.mouseRelStartX = 0;
        object.mouseRelStartY = 0;
        object.emit('mouseup');
    };
    elem.onmousemove = function (event) {
        if (object.hoverEnabled) {
            object.mouseAbsX = event.clientX;
            object.mouseAbsY = event.clientY;
            object.mouseRelX = event.offsetX;
            object.mouseRelY = event.offsetY;
            object.emit('mousemove');
        }
    };

    return elem;
};

QuickRendererDOM.prototype.addElement = function (element, parent) {
    if (parent && parent.element) {
        parent.element.appendChild(element.element);
    } else {
        document.body.appendChild(element.element);
    }
};

QuickRendererDOM.prototype.addElements = function (elements, parent) {
    var fragment = document.createDocumentFragment();

    for (var i = 0; i < elements.length; ++i) {
        fragment.appendChild(elements[i].element);
    }

    if (parent && parent.element) {
        parent.element.appendChild(fragment);
    } else {
        document.body.appendChild(fragment);
    }
};

QuickRendererDOM.prototype.renderElement = function (element) {
    // console.log("renderElement: " + element.id + " properties: " + Object.keys(element.properties).length);
    var name;
    if (element.element) {
        for (name in element._dirtyProperties) {
            if (name === 'text') {
                element.element.textContent = element[name];
            } else {
                element.element.style[name] = element[name];
            }
        }
        element._dirtyProperties = {};
    }
};
<commit_msg>use font-size/family again to fix text item bug<commit_after>// Copyright (c) 2012 Johannes Zellner webmaster@nebulon.de - All Rights Reserved
// DOM renderer

"use strict";

/*
 **************************************************
 * Predefined basic elements
 **************************************************
 */
function Item(id, parent) {
    var elem = new Element(id, parent);

    elem.addProperty("-webkit-user-select", "none");
    elem.addProperty("-moz-user-select", "none");
    elem.addProperty("hoverEnabled", false);
    elem.addProperty("mouseAbsX", 0);
    elem.addProperty("mouseAbsY", 0);
    elem.addProperty("mouseRelX", 0);
    elem.addProperty("mouseRelY", 0);
    elem.addProperty("width", 100);
    elem.addProperty("height", 100);
    elem.addProperty("top", 0);
    elem.addProperty("bottom", function () { return this.top + this.height; });
    elem.addProperty("verticalCenter", function () { return this.height / 2.0; });
    elem.addProperty("left", 0);
    elem.addProperty("right", function () { return this.left + this.width; });
    elem.addProperty("horizontalCenter", function () { return this.width / 2.0; });
    elem.addProperty("mouseRelStartX", 0);
    elem.addProperty("mouseRelStartY", 0);
    elem.addProperty("mousePressed", false);
    elem.addProperty("containsMouse", false);
    elem.addProperty("scale", 1);
    elem.addProperty("-webkit-transform", function () {
        var s = this.scale.toFixed(10);
        return "scale(" + s + ", " + s + ")";
    });

    return elem;
}

// FIXME global leak
var tmpTextElement;
function Text(id, parent) {
    var elem = new Item(id, parent);

    elem.addProperty("textWidth", 0);
    elem.addProperty("textHeight", 0);
    elem.addProperty("font-size", "12pt");
    elem.addProperty("font-family", "Source Code Pro");
    elem.addProperty("text", "");
    elem.addProperty("width", function() { return this.textWidth; });
    elem.addProperty("height", function() { return this.textHeight; });

    // all this below for calculating the text width
    if (!tmpTextElement) {
        tmpTextElement = window.document.createElement("div");
        tmpTextElement.style.position = "absolute";
        tmpTextElement.style.visibility = "hidden";
        tmpTextElement.style.width = "auto";
        tmpTextElement.style.height = "auto";
        document.body.appendChild(tmpTextElement);
    }

    elem.addChanged("text", function () {
        var tmpProperty = elem.text;
        var width = 0;
        var height = 0;

        tmpTextElement.style["font-size"] = elem["font-size"];
        tmpTextElement.style["font-family"] = elem["font-family"];

        if (tmpTextElement.textContent === tmpProperty) {
            width = (tmpTextElement.clientWidth + 1);
            height = (tmpTextElement.clientHeight + 1);
        } else if (tmpProperty !== "") {
            tmpTextElement.textContent = tmpProperty;
            width = (tmpTextElement.clientWidth + 1);
            height = (tmpTextElement.clientHeight + 1);
        }

        elem.textWidth = width;
        elem.textHeight = height;
    });

    return elem;
}

function Rectangle(id, parent) {
    var elem = new Item(id, parent);

    elem.addProperty("background-color", "white");
    elem.addProperty("border-color", "black");
    elem.addProperty("border-style", "solid");
    elem.addProperty("border-width", 1);
    elem.addProperty("border-radius", 0);

    return elem;
}

function Image(id, parent) {
    var elem = new Item(id, parent);

    elem.addProperty("text-align", "center");
    elem.addProperty("src", "image.png");
    elem.addProperty("background-image", function () {
        if (this.src.indexOf("url('") === 0) {
            return this.src;
        }

        return "url('" + this.src + "')";
    });

    return elem;
}

function Button(id, parent) {
    var elem = new Rectangle(id, parent);

    elem.addProperty("text-align", "center");
    elem.addProperty("cursor", "pointer");
    elem.addProperty("background-color", "lightgray");

    return elem;
}

/*
 **************************************************
 * DOM renderer
 **************************************************
 */
function QuickRendererDOM() {

}

QuickRendererDOM.prototype.createElement = function (typeHint, object) {
    var elem;

    if (typeHint === 'object') {
        elem = document.createElement('object');
    } else if (typeHint === 'item') {
        elem = document.createElement('div');
        elem.style.position = 'absolute';
    } else if (typeHint === 'input') {
        elem = document.createElement('input');
    }

    elem.onclick = function () { object.emit('click'); };
    elem.onmouseover = function () {
        if (object.hoverEnabled) {
            object.containsMouse = true;
            object.emit('mouseover');
        }
    };
    elem.onmouseout = function () {
        if (object.hoverEnabled) {
            object.containsMouse = false;
            object.emit('mouseout');
        }
    };
    elem.onmousedown = function (event) {
        object.mousePressed = true;
        object.mouseRelStartX = event.offsetX;
        object.mouseRelStartY = event.offsetY;
        object.emit('mousedown');
    };
    elem.onmouseup = function (event) {
        object.mousePressed = false;
        object.mouseRelStartX = 0;
        object.mouseRelStartY = 0;
        object.emit('mouseup');
    };
    elem.onmousemove = function (event) {
        if (object.hoverEnabled) {
            object.mouseAbsX = event.clientX;
            object.mouseAbsY = event.clientY;
            object.mouseRelX = event.offsetX;
            object.mouseRelY = event.offsetY;
            object.emit('mousemove');
        }
    };

    return elem;
};

QuickRendererDOM.prototype.addElement = function (element, parent) {
    if (parent && parent.element) {
        parent.element.appendChild(element.element);
    } else {
        document.body.appendChild(element.element);
    }
};

QuickRendererDOM.prototype.addElements = function (elements, parent) {
    var fragment = document.createDocumentFragment();

    for (var i = 0; i < elements.length; ++i) {
        fragment.appendChild(elements[i].element);
    }

    if (parent && parent.element) {
        parent.element.appendChild(fragment);
    } else {
        document.body.appendChild(fragment);
    }
};

QuickRendererDOM.prototype.renderElement = function (element) {
    // console.log("renderElement: " + element.id + " properties: " + Object.keys(element.properties).length);
    var name;
    if (element.element) {
        for (name in element._dirtyProperties) {
            if (name === 'text') {
                element.element.textContent = element[name];
            } else {
                element.element.style[name] = element[name];
            }
        }
        element._dirtyProperties = {};
    }
};
<|endoftext|>


<commit_before>AFRAME.registerComponent('gui-slider', {
    schema: {
        percent: {type: 'number', default: '0.5'},
        handleOuterRadius: {type: 'number', default: '0.17'},
        handleInnerRadius: {type: 'number', default: '0.13'},
        handleOuterDepth: {type: 'number', default: '0.04'},
        handleInnerDepth: {type: 'number', default: '0.02'},
        sliderBarHeight: {type: 'number', default: '0.05'},
        sliderBarDepth: {type: 'number', default: '0.03'},
        leftRightPadding: {type: 'number', default: '0.25'},
        topBottomPadding: {type: 'number', default: '0.125'},

        borderColor: {type: 'string', default: key_grey},
        backgroundColor: {type: 'string', default: key_offwhite},
        hoverColor: {type: 'string', default: key_grey_light},
        activeColor: {type: 'string', default: key_orange},
        handleColor: {type: 'string', default: key_white},
    },
    init: function() {

        var data = this.data;
        var el = this.el;
        var guiItem = el.getAttribute("gui-item");
        var sliderWidth = guiItem.width - data.leftRightPadding*2.0
        var sliderHeight = guiItem.height - data.topBottomPadding*2.0

        el.setAttribute('geometry', `primitive: plane; height: ${guiItem.height}; width: ${guiItem.height};`);
        el.setAttribute('material', `shader: flat; opacity: 1;  color: ${data.backgroundColor}; side:front;`);

        var sliderActiveBar = document.createElement("a-entity");
        sliderActiveBar.setAttribute('geometry', `primitive: box; width: ${data.percent*sliderWidth}; height: ${data.sliderBarHeight}; depth: ${data.sliderBarDepth};`);
        sliderActiveBar.setAttribute('material', `shader: flat; opacity: 1; side:double; color: ${data.activeColor};`);
        sliderActiveBar.setAttribute('position', `${data.percent - sliderWidth*0.5} 0 ${data.sliderBarDepth - 0.01}`);
        el.appendChild(sliderActiveBar);

        var sliderBar = document.createElement("a-entity");
        sliderBar.setAttribute('geometry', `primitive: box; width: ${sliderWidth - data.percent * sliderWidth}; height: ${data.sliderBarHeight}; depth: ${data.sliderBarDepth};`);
        sliderBar.setAttribute('material', `shader: flat; opacity: 1; side:double; color: ${data.borderColor};`);
        sliderBar.setAttribute('position', `${data.percent * sliderWidth * 0.5} 0 ${data.sliderBarDepth - 0.01}`);
        el.appendChild(sliderBar);

        var handleContainer = document.createElement("a-entity");
        handleContainer.setAttribute('geometry', `primitive: cylinder; radius: ${data.handleOuterRadius}; height: ${data.handleOuterDepth};`);
        handleContainer.setAttribute('material', `shader: flat; opacity: 1; side:double; color: ${data.borderColor};`);
        handleContainer.setAttribute('rotation', '90 0 0');
        handleContainer.setAttribute('position', `${data.percent*sliderWidth - sliderWidth*0.5} 0 ${data.handleOuterDepth - 0.01}`);
        el.appendChild(handleContainer);

        var handle = document.createElement("a-entity");
        handle.setAttribute('geometry', `primitive: cylinder; radius: ${data.handleInnerRadius}; height: ${data.handleInnerDepth};`);
        handle.setAttribute('material', `shader: flat; opacity: 1; side:double; color: ${data.handleColor};`);
        handle.setAttribute('position', `0 ${data.handleInnerDepth} 0`);
        handleContainer.appendChild(handle);

        el.addEventListener('mouseenter', function () {
            handle.setAttribute('material', 'color', data.hoverColor);
        });

        el.addEventListener('mouseleave', function () {
            handle.setAttribute('material', 'color', data.handleColor);
        });

        el.addEventListener('click', function (evt) {
            console.log('I was clicked at: ', evt.detail.intersection.point);
            var localCoordinates = el.object3D.worldToLocal(evt.detail.intersection.point);
            console.log('local coordinates: ', localCoordinates);
            console.log('current percent: '+data.percent);
            var sliderBarWidth = 2; // total width of slider bar
            if (localCoordinates.x <= (-sliderBarWidth / 2)) {
                data.percent = 0;
            } else if (localCoordinates.x >= (sliderBarWidth / 2)) {
                data.percent = 1.0;
            } else {
                data.percent = (localCoordinates.x + (sliderBarWidth /2)) / sliderBarWidth;
            }
            console.log("handle container: "+handleContainer);
            sliderActiveBar.setAttribute('geometry', `primitive: box; width: ${data.percent*2}; height: 0.05; depth: 0.03;`);
            sliderActiveBar.setAttribute('position', `${data.percent-1} 0 0.02`);
            sliderBar.setAttribute('geometry', `primitive: box; width: ${2-data.percent*2}; height: 0.05; depth: 0.03;`);
            sliderBar.setAttribute('position', `${data.percent*1} 0 0.02`);
            handleContainer.setAttribute('position', `${data.percent*2-1} 0 0.03`);
            var guiInteractable = el.getAttribute("gui-interactable");
            console.log("guiInteractable: "+guiInteractable);
            var clickActionFunctionName = guiInteractable.clickAction;
            console.log("clickActionFunctionName: "+clickActionFunctionName);
            // find object
            var clickActionFunction = window[clickActionFunctionName];
            //console.log("clickActionFunction: "+clickActionFunction);
            // is object a function?
            if (typeof clickActionFunction === "function") clickActionFunction();
        });

    },
    update: function () {
    },
    tick: function () {
    },
    remove: function () {
    },
    pause: function () {
    },
    play: function () {
    },
});

AFRAME.registerPrimitive( 'a-gui-slider', {
    defaultComponents: {
        'gui-interactable': { },
        'gui-item': { type: 'slider' },
        'gui-slider': { }
    },
    mappings: {
        'onclick': 'gui-interactable.clickAction',
        'onhover': 'gui-interactable.hoverAction',
        'key-code': 'gui-interactable.keyCode',
        'width': 'gui-item.width',
        'height': 'gui-item.height',
        'margin': 'gui-item.margin',
        'percent': 'gui-slider.percent',
        'handle-outer-radius': 'gui-slider.handleOuterRadius',
        'handle-inner-radius': 'gui-slider.handleInnerRadius',
        'handle-outer-depth': 'gui-slider.handleOuterDepth',
        'handle-inner-depth': 'gui-slider.handleInnerDepth',
        'slider-bar-height': 'gui-slider.sliderBarHeight',
        'slider-bar-depth': 'gui-slider.sliderBarDepth',
        'left-right-padding': 'gui-slider.leftRightPadding',
        'top-bottom-padding': 'gui-slider.topBottomPadding',
        'border-color': 'gui-slider.borderColor',
        'background-color': 'gui-slider.backgroundColor',
        'hover-color': 'gui-slider.hoverColor',
        'active-color': 'gui-slider.activeColor',
        'handle-color': 'gui-slider.handleColor'
    }
});<commit_msg>Modified the slider component It now notifies the user of the current position of the slider by emitting an event using clickActionFunction(data.percent)<commit_after>AFRAME.registerComponent('gui-slider', {
    schema: {
        percent: {type: 'number', default: '0.5'},
        handleOuterRadius: {type: 'number', default: '0.17'},
        handleInnerRadius: {type: 'number', default: '0.13'},
        handleOuterDepth: {type: 'number', default: '0.04'},
        handleInnerDepth: {type: 'number', default: '0.02'},
        sliderBarHeight: {type: 'number', default: '0.05'},
        sliderBarDepth: {type: 'number', default: '0.03'},
        leftRightPadding: {type: 'number', default: '0.25'},
        topBottomPadding: {type: 'number', default: '0.125'},

        borderColor: {type: 'string', default: key_grey},
        backgroundColor: {type: 'string', default: key_offwhite},
        hoverColor: {type: 'string', default: key_grey_light},
        activeColor: {type: 'string', default: key_orange},
        handleColor: {type: 'string', default: key_white},
    },
    init: function() {

        var data = this.data;
        var el = this.el;
        var guiItem = el.getAttribute("gui-item");
        var sliderWidth = guiItem.width - data.leftRightPadding*2.0
        var sliderHeight = guiItem.height - data.topBottomPadding*2.0

        el.setAttribute('geometry', `primitive: plane; height: ${guiItem.height}; width: ${guiItem.height};`);
        el.setAttribute('material', `shader: flat; opacity: 1;  color: ${data.backgroundColor}; side:front;`);

        var sliderActiveBar = document.createElement("a-entity");
        sliderActiveBar.setAttribute('geometry', `primitive: box; width: ${data.percent*sliderWidth}; height: ${data.sliderBarHeight}; depth: ${data.sliderBarDepth};`);
        sliderActiveBar.setAttribute('material', `shader: flat; opacity: 1; side:double; color: ${data.activeColor};`);
        sliderActiveBar.setAttribute('position', `${data.percent - sliderWidth*0.5} 0 ${data.sliderBarDepth - 0.01}`);
        el.appendChild(sliderActiveBar);

        var sliderBar = document.createElement("a-entity");
        sliderBar.setAttribute('geometry', `primitive: box; width: ${sliderWidth - data.percent * sliderWidth}; height: ${data.sliderBarHeight}; depth: ${data.sliderBarDepth};`);
        sliderBar.setAttribute('material', `shader: flat; opacity: 1; side:double; color: ${data.borderColor};`);
        sliderBar.setAttribute('position', `${data.percent * sliderWidth * 0.5} 0 ${data.sliderBarDepth - 0.01}`);
        el.appendChild(sliderBar);

        var handleContainer = document.createElement("a-entity");
        handleContainer.setAttribute('geometry', `primitive: cylinder; radius: ${data.handleOuterRadius}; height: ${data.handleOuterDepth};`);
        handleContainer.setAttribute('material', `shader: flat; opacity: 1; side:double; color: ${data.borderColor};`);
        handleContainer.setAttribute('rotation', '90 0 0');
        handleContainer.setAttribute('position', `${data.percent*sliderWidth - sliderWidth*0.5} 0 ${data.handleOuterDepth - 0.01}`);
        el.appendChild(handleContainer);

        var handle = document.createElement("a-entity");
        handle.setAttribute('geometry', `primitive: cylinder; radius: ${data.handleInnerRadius}; height: ${data.handleInnerDepth};`);
        handle.setAttribute('material', `shader: flat; opacity: 1; side:double; color: ${data.handleColor};`);
        handle.setAttribute('position', `0 ${data.handleInnerDepth} 0`);
        handleContainer.appendChild(handle);

        el.addEventListener('mouseenter', function () {
            handle.setAttribute('material', 'color', data.hoverColor);
        });

        el.addEventListener('mouseleave', function () {
            handle.setAttribute('material', 'color', data.handleColor);
        });

        el.addEventListener('click', function (evt) {
            console.log('I was clicked at: ', evt.detail.intersection.point);
            var localCoordinates = el.object3D.worldToLocal(evt.detail.intersection.point);
            console.log('local coordinates: ', localCoordinates);
            console.log('current percent: '+data.percent);
            var sliderBarWidth = 2; // total width of slider bar
            if (localCoordinates.x <= (-sliderBarWidth / 2)) {
                data.percent = 0;
            } else if (localCoordinates.x >= (sliderBarWidth / 2)) {
                data.percent = 1.0;
            } else {
                data.percent = (localCoordinates.x + (sliderBarWidth /2)) / sliderBarWidth;
            }
            console.log("handle container: "+handleContainer);
            sliderActiveBar.setAttribute('geometry', `primitive: box; width: ${data.percent*2}; height: 0.05; depth: 0.03;`);
            sliderActiveBar.setAttribute('position', `${data.percent-1} 0 0.02`);
            sliderBar.setAttribute('geometry', `primitive: box; width: ${2-data.percent*2}; height: 0.05; depth: 0.03;`);
            sliderBar.setAttribute('position', `${data.percent*1} 0 0.02`);
            handleContainer.setAttribute('position', `${data.percent*2-1} 0 0.03`);
            var guiInteractable = el.getAttribute("gui-interactable");
            console.log("guiInteractable: "+guiInteractable);
            var clickActionFunctionName = guiInteractable.clickAction;
            console.log("clickActionFunctionName: "+clickActionFunctionName);
            // find object
            var clickActionFunction = window[clickActionFunctionName];
            //console.log("clickActionFunction: "+clickActionFunction);
            // is object a function?
            if (typeof clickActionFunction === "function") clickActionFunction(data.percent);
        });

    },
    update: function () {
    },
    tick: function () {
    },
    remove: function () {
    },
    pause: function () {
    },
    play: function () {
    },
});

AFRAME.registerPrimitive( 'a-gui-slider', {
    defaultComponents: {
        'gui-interactable': { },
        'gui-item': { type: 'slider' },
        'gui-slider': { }
    },
    mappings: {
        'onclick': 'gui-interactable.clickAction',
        'onhover': 'gui-interactable.hoverAction',
        'key-code': 'gui-interactable.keyCode',
        'width': 'gui-item.width',
        'height': 'gui-item.height',
        'margin': 'gui-item.margin',
        'percent': 'gui-slider.percent',
        'handle-outer-radius': 'gui-slider.handleOuterRadius',
        'handle-inner-radius': 'gui-slider.handleInnerRadius',
        'handle-outer-depth': 'gui-slider.handleOuterDepth',
        'handle-inner-depth': 'gui-slider.handleInnerDepth',
        'slider-bar-height': 'gui-slider.sliderBarHeight',
        'slider-bar-depth': 'gui-slider.sliderBarDepth',
        'left-right-padding': 'gui-slider.leftRightPadding',
        'top-bottom-padding': 'gui-slider.topBottomPadding',
        'border-color': 'gui-slider.borderColor',
        'background-color': 'gui-slider.backgroundColor',
        'hover-color': 'gui-slider.hoverColor',
        'active-color': 'gui-slider.activeColor',
        'handle-color': 'gui-slider.handleColor'
    }
});
<|endoftext|>