<commit_before>// @flow weak

import type { TrendsAPIGraph } from '../util/types';
import { seasonalRatio, trendRatio } from '../util/constants';
import * as d3 from 'd3';
import log from 'loglevel';

export default class LineChart {

  data: {
    term: string,
    points: {date: Date, value: number}[]
  }[];
  parentContainer: HTMLElement;
  title: string;
  type: string;
  range: number;
  width: number;
  height: number;
  margin: { top: number, left: number, bottom: number, right: number };
  svg: () => {};

  constructor(parentContainer: HTMLElement, type?: string, range?: number) {
    this.parentContainer = parentContainer;
    if (type) this.type = type;
    if (range) this.range = range;
    this.title = this.getTitle(this.type);
    this.margin = { top: 36, right: 4, bottom: 30, left: 42 };
    const size = this.getSize();
    this.width = size.width;
    this.height = size.height;
    this.data = this.createEmptyChart(this.type);
    this.createElements(parentContainer);
  }

  getSize() {
    const { parentContainer, margin, type } = this;
    const width = parentContainer.offsetWidth - (margin.left + margin.right);
    const baseHeight = type !== 'seasonal' ? width * trendRatio : width * seasonalRatio;
    const height = baseHeight - (margin.top + margin.bottom);
    return { width, height };
  }

  resizeChart() {
    const { margin } = this;
    const size = this.getSize();
    const { width, height } = size;
    this.width = width;
    this.height = height;
    this.svg
      .attr('width', width + margin.left + margin.right)
      .attr('height', height + margin.top + margin.bottom);
  }

  createEmptyChart(type: string) {
    let data;
    if (type === 'seasonal') {
      data = [
        {
          term:"",
          points:[
            {"date":"2003-12-31","value":0},
            {"date":"2004-12-31","value":0}
          ]
        }
      ]
    } else {
      data = [
        {
            term:"",
            points:[
            {"date":"2003-12-31","value":0},
            {"date":"2017-05-31","value":100},
          ]
        }
      ]
    }
    return this.parseDates(data);
  }

  getTitle(type) {
    let title;
    switch (type) {
      case 'seasonal':
        title = 'Seasonal per year';
        break;
      case 'trend':
        title = 'Trend over time';
        break;
      default:
        title = 'Interest over time';
    }
    return title;
  }

  parseDates(data: TrendsAPIGraph[]) {
    const parseTime = d3.timeParse('%Y-%m-%d');
    return data.map((d, i) => {
      return {
        term: d.term,
        points: d.points.map((p, i) => {
          return { date: parseTime(p.date), value: p.value }
        })
      }
    });
  }

  updateData(data: TrendsAPIGraph[], type?: string, title? : string, range?: number) {
    const { svg } = this;
    svg.select('.line-chart .time-series')
      .classed('empty', false);

    this.data = this.parseDates(data);
    if (range) this.range = range;
    if (type && type !== this.type) {
      this.type = type;
      this.resizeChart();
    }
    this.title = title ? title : this.getTitle(this.type);
    this.updateElements();
  }

  createElements(parentContainer: HTMLElement) {
    const parentContainerSelection = d3.select(parentContainer);
    const { data, width, height, margin } = this;

    this.svg = parentContainerSelection.append('svg')
      .attr('class', 'chart-canvas');

    this.resizeChart();

    const chart = this.svg
      .append('g')
      .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
      .attr('class', 'line-chart');

    chart.append('g')
      .attr('class', 'x axis');

    chart.append('g')
      .attr('class', 'y axis')
      .append('text')
      .attr('class', 'title')
      .attr('text-anchor', 'start')
      .attr('x', -margin.left)
      .attr('y', -margin.top/2);

    chart.append('g')
      .attr('class', 'time-series empty');

    this.updateElements();
  }

  updateElements() {
    const { data, width, height, margin, svg, title, type, range } = this;
    const transitionDuration = 500;

    const x = d3.scaleTime()
      .range([0, width])
      .domain( d3.extent(data[0].points, function(p) { return p.date }) );

    let yMin, yMax;

    if (type === 'seasonal') {

      if (range) {
        yMin = -range;
        yMax = range;

      } else {
        yMin = d3.min(data, function(d, i) { return d3.min(d.points, function(p) { return p.value; }); });
        yMax = d3.max(data, function(d, i) { return d3.max(d.points, function(p) { return p.value; }); });
        const maxRange = Math.abs(yMin) > Math.abs(yMax) ? yMin : yMax;
        yMin = maxRange > 20 ? -maxRange : -20;
        yMax = maxRange > 20 ? maxRange : 20;
      }

    } else {
      yMin = 0;
      yMax = 100;
    }

    const y = d3.scaleLinear()
      .range([height, 0])
      .domain([yMin, yMax]);

    const xAxis = d3.axisBottom(x)
      .tickSize(0)
      .tickPadding(18);

    const isYear = d3.select(svg.node().parentNode.parentNode).classed('step-3') ? true : false;
    const isMobile = window.innerWidth < 600;

    if (type === 'seasonal' && !isYear) {
      xAxis.tickFormat(d3.timeFormat('%b'))
        .ticks(d3.timeMonth.every(isMobile ? 2 : 1));

    } else if (type === 'trend' || type === 'total' || isYear)  {
      xAxis.tickFormat(d3.timeFormat('%Y'))
        .ticks(d3.timeYear.every(2));

    } else if (type === 'mixed') {
      xAxis.tickFormat(d3.timeFormat('%b %Y'))
        .ticks(isMobile ? 3 : 5);
    }

    const yAxis = d3.axisLeft(y)
      .tickSize(12)
      .ticks(type === 'seasonal' ? 5 : 3);

    const line = d3.line()
      .x(function(d) { return x(d.date); })
      .y(function(d) { return y(d.value); });

    const chart = svg.select('.line-chart');

    chart.select('g.y')
      .transition()
      .duration(transitionDuration)
      .call(yAxis);

    chart.select('g.y .title')
      .text(title);

    chart.select('g.y')
      .selectAll('.tick text');

    let xAxisSelection = chart.select('g.x');
    if (!isMobile) xAxisSelection = xAxisSelection.transition().duration(transitionDuration);
    xAxisSelection.style('transform', `translate(0px, ${height}px)`)
      .call(xAxis)
      .select('path')
      .style('transform', type === 'seasonal' ? `translate(0px, ${-height/2}px)` : `translate(0px, 0px)`);

    const timeSeries = chart.selectAll('.time-series');

    const diseases = timeSeries.selectAll('.disease').data(data);

    const diseasesEnterUpdate = diseases.enter()
      .append('path')
      .attr('class', 'line disease')
      .merge(diseases)
      .transition()
      .duration(transitionDuration)
      .attr('d', function(d) {
        return line(d.points)
      });

    const diseasesExit = diseases.exit().remove();
  }
}
<commit_msg>Removed axis transition from Safari<commit_after>// @flow weak

import type { TrendsAPIGraph } from '../util/types';
import { seasonalRatio, trendRatio } from '../util/constants';
import * as d3 from 'd3';
import log from 'loglevel';

export default class LineChart {

  data: {
    term: string,
    points: {date: Date, value: number}[]
  }[];
  parentContainer: HTMLElement;
  title: string;
  type: string;
  range: number;
  width: number;
  height: number;
  margin: { top: number, left: number, bottom: number, right: number };
  svg: () => {};

  constructor(parentContainer: HTMLElement, type?: string, range?: number) {
    this.parentContainer = parentContainer;
    if (type) this.type = type;
    if (range) this.range = range;
    this.title = this.getTitle(this.type);
    this.margin = { top: 36, right: 4, bottom: 30, left: 42 };
    const size = this.getSize();
    this.width = size.width;
    this.height = size.height;
    this.data = this.createEmptyChart(this.type);
    this.createElements(parentContainer);
  }

  getSize() {
    const { parentContainer, margin, type } = this;
    const width = parentContainer.offsetWidth - (margin.left + margin.right);
    const baseHeight = type !== 'seasonal' ? width * trendRatio : width * seasonalRatio;
    const height = baseHeight - (margin.top + margin.bottom);
    return { width, height };
  }

  resizeChart() {
    const { margin } = this;
    const size = this.getSize();
    const { width, height } = size;
    this.width = width;
    this.height = height;
    this.svg
      .attr('width', width + margin.left + margin.right)
      .attr('height', height + margin.top + margin.bottom);
  }

  createEmptyChart(type: string) {
    let data;
    if (type === 'seasonal') {
      data = [
        {
          term:'',
          points:[
            {'date':'2003-12-31','value':0},
            {'date':'2004-12-31','value':0}
          ]
        }
      ]
    } else {
      data = [
        {
            term:'',
            points:[
            {'date':'2003-12-31','value':0},
            {'date':'2017-05-31','value':100},
          ]
        }
      ]
    }
    return this.parseDates(data);
  }

  getTitle(type) {
    let title;
    switch (type) {
      case 'seasonal':
        title = 'Seasonal per year';
        break;
      case 'trend':
        title = 'Trend over time';
        break;
      default:
        title = 'Interest over time';
    }
    return title;
  }

  parseDates(data: TrendsAPIGraph[]) {
    const parseTime = d3.timeParse('%Y-%m-%d');
    return data.map((d, i) => {
      return {
        term: d.term,
        points: d.points.map((p, i) => {
          return { date: parseTime(p.date), value: p.value }
        })
      }
    });
  }

  updateData(data: TrendsAPIGraph[], type?: string, title? : string, range?: number) {
    const { svg } = this;
    svg.select('.line-chart .time-series')
      .classed('empty', false);

    this.data = this.parseDates(data);
    if (range) this.range = range;
    if (type && type !== this.type) {
      this.type = type;
      this.resizeChart();
    }
    this.title = title ? title : this.getTitle(this.type);
    this.updateElements();
  }

  createElements(parentContainer: HTMLElement) {
    const parentContainerSelection = d3.select(parentContainer);
    const { data, width, height, margin } = this;

    this.svg = parentContainerSelection.append('svg')
      .attr('class', 'chart-canvas');

    this.resizeChart();

    const chart = this.svg
      .append('g')
      .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
      .attr('class', 'line-chart');

    chart.append('g')
      .attr('class', 'x axis');

    chart.append('g')
      .attr('class', 'y axis')
      .append('text')
      .attr('class', 'title')
      .attr('text-anchor', 'start')
      .attr('x', -margin.left)
      .attr('y', -margin.top/2);

    chart.append('g')
      .attr('class', 'time-series empty');

    this.updateElements();
  }

  updateElements() {
    const { data, width, height, margin, svg, title, type, range } = this;
    const transitionDuration = 500;

    const x = d3.scaleTime()
      .range([0, width])
      .domain( d3.extent(data[0].points, function(p) { return p.date }) );

    let yMin, yMax;

    if (type === 'seasonal') {

      if (range) {
        yMin = -range;
        yMax = range;

      } else {
        yMin = d3.min(data, function(d, i) { return d3.min(d.points, function(p) { return p.value; }); });
        yMax = d3.max(data, function(d, i) { return d3.max(d.points, function(p) { return p.value; }); });
        const maxRange = Math.abs(yMin) > Math.abs(yMax) ? yMin : yMax;
        yMin = maxRange > 20 ? -maxRange : -20;
        yMax = maxRange > 20 ? maxRange : 20;
      }

    } else {
      yMin = 0;
      yMax = 100;
    }

    const y = d3.scaleLinear()
      .range([height, 0])
      .domain([yMin, yMax]);

    const xAxis = d3.axisBottom(x)
      .tickSize(0)
      .tickPadding(18);

    const isYear = d3.select(svg.node().parentNode.parentNode).classed('step-3') ? true : false;
    const isMobile = window.innerWidth < 600;
    const isSafari = /constructor/i.test(window.HTMLElement) || (function (p) { return p.toString() === '[object SafariRemoteNotification]'; })(!window['safari'] || safari.pushNotification);

    if (type === 'seasonal' && !isYear) {
      xAxis.tickFormat(d3.timeFormat('%b'))
        .ticks(d3.timeMonth.every(isMobile ? 2 : 1));

    } else if (type === 'trend' || type === 'total' || isYear)  {
      xAxis.tickFormat(d3.timeFormat('%Y'))
        .ticks(d3.timeYear.every(2));

    } else if (type === 'mixed') {
      xAxis.tickFormat(d3.timeFormat('%b %Y'))
        .ticks(isMobile ? 3 : 5);
    }

    const yAxis = d3.axisLeft(y)
      .tickSize(12)
      .ticks(type === 'seasonal' ? 5 : 3);

    const line = d3.line()
      .x(function(d) { return x(d.date); })
      .y(function(d) { return y(d.value); });

    const chart = svg.select('.line-chart');

    chart.select('g.y')
      .transition()
      .duration(transitionDuration)
      .call(yAxis);

    chart.select('g.y .title')
      .text(title);

    chart.select('g.y')
      .selectAll('.tick text');

    let xAxisSelection = chart.select('g.x');
    if (!isMobile && !isSafari) xAxisSelection = xAxisSelection.transition().duration(transitionDuration);
    xAxisSelection.style('transform', `translate(0px, ${height}px)`)
      .call(xAxis)
      .select('path')
      .style('transform', type === 'seasonal' ? `translate(0px, ${-height/2}px)` : `translate(0px, 0px)`);

    const timeSeries = chart.selectAll('.time-series');

    const diseases = timeSeries.selectAll('.disease').data(data);

    const diseasesEnterUpdate = diseases.enter()
      .append('path')
      .attr('class', 'line disease')
      .merge(diseases)
      .transition()
      .duration(transitionDuration)
      .attr('d', function(d) {
        return line(d.points)
      });

    const diseasesExit = diseases.exit().remove();
  }
}
<|endoftext|>


<commit_before>import { map } from 'substance'

export default class DynamicCollection {
  constructor (api, type) {
    this._api = api
    this._type = type
  }

  getItems () {
    const api = this._api
    const doc = api._getDocument()
    const index = doc.getIndex('type')
    const nodesById = index.get(this._type)
    const items = map(nodesById, node => {
      return api._getModelForNode(node)
    })
    return items
  }

  addItem (item) {
    const api = this._api
    const model = api._addModel(item)
    return model
  }

  removeItem (item) {
    const api = this._api
    const model = api._removeModel(item)
    return model
  }
}
<commit_msg>Type getter.<commit_after>import { map } from 'substance'

export default class DynamicCollection {
  constructor (api, type) {
    this._api = api
    this._type = type
  }

  get type() {
    return this._type
  }

  getItems () {
    const api = this._api
    const doc = api._getDocument()
    const index = doc.getIndex('type')
    const nodesById = index.get(this._type)
    const items = map(nodesById, node => {
      return api._getModelForNode(node)
    })
    return items
  }

  addItem (item) {
    const api = this._api
    const model = api._addModel(item)
    return model
  }

  removeItem (item) {
    const api = this._api
    const model = api._removeModel(item)
    return model
  }
}
<|endoftext|>


<commit_before>'use strict'

const serviceUUID = '00001523-1212-efde-1523-785feabcd123';
const buttonCharacteristicUUID = '00001524-1212-efde-1523-785feabcd123';
const ledCharacteristicUUID = '00001525-1212-efde-1523-785feabcd123';

var bleDevice;
var bleServer;
var bleService;
var button1char;
var button1count = 0;

window.onload = function(){
  document.querySelector('#connect').addEventListener('click', connect);
  document.querySelector('#disconnect').addEventListener('click', disconnect);
};

function connect() {
  if (!navigator.bluetooth) {
      log('Web Bluetooth API is not available.\n' +
          'Please make sure the Web Bluetooth flag is enabled.');
      return;
  }
  log('Requesting Bluetooth Device...');
  navigator.bluetooth.requestDevice({filters: [{services: [serviceUUID]}]})
  .then(device => {
    bleDevice = device;
    return device.connectGATT();
  })
  .then(server => {
    bleServer = server;
    log('Got bleServer');
    return server.getPrimaryService(serviceUUID);
  })
  .then(service => {
    log('Got bleService');
    bleService = service;
  })
  .then(() => bleService.getCharacteristic(buttonCharacteristicUUID))
  .then( characteristic => {
    log('Got button1characteristic');
    button1char = characteristic;
    return button1char.startNotifications();
  })
  .then(() => {
    button1char.addEventListener('characteristicvaluechanged',handleNotifyButton1);
  })
  .catch(error => {
    log('> connect ' + error);
  });
}

function disconnect() {
  if (!bleDevice) {
    log('No Bluetooth Device connected...');
    return;
  }
  log('Disconnecting from Bluetooth Device...');
  if (bleDevice.gatt.connected) {
    bleDevice.gatt.disconnect();
    log('> Bluetooth Device connected: ' + bleDevice.gatt.connected);
  } else {
    log('> Bluetooth Device is already disconnected');
  }
}

function handleNotifyButton1(event) {
  button1count += 1;
  log('Notification triggered by Button 1');
  document.getElementById("btn1").innerHTML = button3count;
}

function log(text) {
    console.log(text);
    document.querySelector('#log').textContent += text + '\n';
}
<commit_msg>led toggle<commit_after>'use strict'

const serviceUUID = '00001523-1212-efde-1523-785feabcd123';
const buttonCharacteristicUUID = '00001524-1212-efde-1523-785feabcd123';
const ledCharacteristicUUID = '00001525-1212-efde-1523-785feabcd123';

var bleDevice;
var bleServer;
var bleService;
var button1char;
var button1count = 0;
var toggleFlag = true;

window.onload = function(){
  document.querySelector('#connect').addEventListener('click', connect);
  document.querySelector('#disconnect').addEventListener('click', disconnect);
  document.querySelector('#led2').addEventListener('click', toggleLED);
};

function connect() {
  if (!navigator.bluetooth) {
      log('Web Bluetooth API is not available.\n' +
          'Please make sure the Web Bluetooth flag is enabled.');
      return;
  }
  log('Requesting Bluetooth Device...');
  navigator.bluetooth.requestDevice({filters: [{services: [serviceUUID]}]})
  .then(device => {
    bleDevice = device;
    return device.connectGATT();
  })
  .then(server => {
    bleServer = server;
    log('Got bleServer');
    return server.getPrimaryService(serviceUUID);
  })
  .then(service => {
    log('Got bleService');
    bleService = service;
  })
  .then(() => bleService.getCharacteristic(buttonCharacteristicUUID))
  .then( characteristic => {
    log('Got button1characteristic');
    button1char = characteristic;
    return button1char.startNotifications();
  })
  .then(() => {
    button1char.addEventListener('characteristicvaluechanged',handleNotifyButton1);
  })
  .catch(error => {
    log('> connect ' + error);
  });
}

function disconnect() {
  if (!bleDevice) {
    log('No Bluetooth Device connected...');
    return;
  }
  log('Disconnecting from Bluetooth Device...');
  if (bleDevice.gatt.connected) {
    bleDevice.gatt.disconnect();
    log('> Bluetooth Device connected: ' + bleDevice.gatt.connected);
  } else {
    log('> Bluetooth Device is already disconnected');
  }
}

function handleNotifyButton1(event) {
  button1count += 1;
  log('Notification triggered by Button 1');
  document.getElementById("btn1").innerHTML = button1count;
}

function toggleLED(){
  bleService.getCharacteristic(ledCharacteristicUUID)
  .then(characteristic => {
    let toggle;
    if(toggleFlag === true){
      toggle = new Uint8Array([0]);
      toggleFlag = false;
    }
    else{
      toggle = new Uint8Array([1]);
      toggleFlag = false;
    }
    return characteristic.writeValue(toggle);
  })
  .then(() =>{
    log("Toggled LED");
  })
}

function log(text) {
    console.log(text);
    document.querySelector('#log').textContent += text + '\n';
}
<|endoftext|>


<commit_before>function VertexNOR(graph){
	Vertex.call(this, graph)
}

VertexNOR.prototype = Object.create(Vertex.prototype)
VertexNOR.prototype.constructor = VertexNOR

VertexNOR.prototype.color = "skyblue"
VertexNOR.prototype.symbol = "N"
VertexNOR.prototype.type = "nor"

VertexNOR.prototype.update = function(options){
	var max = Math.max.apply(null, this.inputs)
	for(var neighbor of this.neighbors)
		options.send(neighbor, -max)
	this.inputs = []
}<commit_msg>VertexNOR is redundant with VertexInverse<commit_after><|endoftext|>


<commit_before>import { Syncher } from 'service-framework/dist/Syncher';
import URI from 'urijs';
import Search from '../utils/Search';
import IdentityManager from 'service-framework/dist/IdentityManager';
import { Discovery } from 'service-framework/dist/Discovery';
import { callbackify } from 'util';

class ElearningPlayer {

  constructor(hypertyURL, bus, config) {
    let uri = new URI(hypertyURL);
    this.objectDescURL = `hyperty-catalogue://catalogue.${uri.hostname()}/.well-known/dataschema/Context`;
    this.syncher = new Syncher(hypertyURL, bus, config);
    this.identityManager = new IdentityManager(hypertyURL, config.runtimeURL, bus);
    this.discovery = new Discovery(hypertyURL, config.runtimeURL, bus);
    this.search = new Search(this.discovery, this.identityManager);
    this.currentPosition = null;
    this.identity = null;
    this.bus = bus;
    this.hypertyURL = hypertyURL;
    this.reporter = null;
    this.watchID = null;

  }

  _getRegisteredUser() {
    let _this = this;

    return new Promise((resolve, reject) => {
      _this.identityManager.discoverUserRegistered().then((identity) => {
        console.log('[ElearningPlayer] GET MY IDENTITY:', identity);
        resolve(identity);
      }).catch((error) => {
        console.error('[ElearningPlayer] ERROR:', error);
        reject(error);
      });
    });

  }

  _resumeReporters() {
    let _this = this;

    //debugger;
    return new Promise((resolve, reject) => {
      _this.syncher.resumeReporters({store: true}).then((reporters) => {
        console.log('[ElearningPlayer] Reporters resumed', reporters);

        let reportersList = Object.keys(reporters);

        if (reportersList.length  > 0) {

          _this._getRegisteredUser().then((identity) => {

            reportersList.forEach((dataObjectReporterURL) => {
              //debugger;
              console.log(identity);
              _this.identity = identity;
              console.log('[ElearningPlayer] ', dataObjectReporterURL);
              console.log('[ElearningPlayer]', reporters[dataObjectReporterURL]);

              if (identity.userURL == reporters[dataObjectReporterURL].metadata.subscriberUsers[0] && reporters[dataObjectReporterURL].metadata.name == 'elearning') {
                //debugger;
                _this.reporter = reporters[dataObjectReporterURL];
                _this.reporter.onSubscription((event) => event.accept());
                return resolve(true);
              }
            });
            return resolve(false);
          });
        } else {
          return resolve(false);
        }
      }).catch((reason) => {
        console.info('[ElearningPlayer] Reporters:', reason);
      });
    });
  }

  //FOR invite elearning  -> hyperty://sharing-cities-dsm/elearning
  invite(observer) {

    let _this = this;
    _this.reporter.inviteObservers([observer]);
  }

  initQuizSubmission() {
    //debugger;
    let _this = this;
    if (_this.reporter == null) {
      _this.syncher.create(_this.objectDescURL, [], {}, true, false, 'elearning', {}, { resources: ['learning-context'] })
        .then((reporter) => {
          _this.reporter = reporter;
          console.log('[ElearningPlayer]  DataObjectReporter', _this.reporter);
          reporter.onSubscription((event) => event.accept());
          _this.search.myIdentity().then(identity => {
            _this.identity = identity;
          });
        });
    } else {
    }
  }

  answer(id, answers) {
    let _this = this;
    let date = new Date();
    _this.reporter.data.values = [
      { id: id, date: date, answers: answers },
    ];

  }

  // can call with 'data://sharing-cities-dsm/elearning'
  retrieveQuizzes(quizzesURL) {

    return new Promise((resolve) => {
      let _this = this;

      let createMessage = {
        type: 'forward', to: quizzesURL, from: _this.hypertyURL,
        body: {
          from: _this.hypertyURL,
          type: 'read'
        }
      };
      console.log('elearning-player-retrieveQuizzes()', createMessage);

      _this.bus.postMessage(createMessage, (reply) => {
        resolve(reply);
        console.log('elearning-player-retrieveQuizzes() reply: ', reply);
      });

    });

  }

}

export default function activate(hypertyURL, bus, config) {
  return {
    name: 'ElearningPlayer',
    instance: new ElearningPlayer(hypertyURL, bus, config)
  };
}
<commit_msg>initQuizSubmission() is promise<commit_after>import { Syncher } from 'service-framework/dist/Syncher';
import URI from 'urijs';
import Search from '../utils/Search';
import IdentityManager from 'service-framework/dist/IdentityManager';
import { Discovery } from 'service-framework/dist/Discovery';
import { callbackify } from 'util';

class ElearningPlayer {

  constructor(hypertyURL, bus, config) {
    let uri = new URI(hypertyURL);
    this.objectDescURL = `hyperty-catalogue://catalogue.${uri.hostname()}/.well-known/dataschema/Context`;
    this.syncher = new Syncher(hypertyURL, bus, config);
    this.identityManager = new IdentityManager(hypertyURL, config.runtimeURL, bus);
    this.discovery = new Discovery(hypertyURL, config.runtimeURL, bus);
    this.search = new Search(this.discovery, this.identityManager);
    this.currentPosition = null;
    this.identity = null;
    this.bus = bus;
    this.hypertyURL = hypertyURL;
    this.reporter = null;
    this.watchID = null;

  }

  _getRegisteredUser() {
    let _this = this;

    return new Promise((resolve, reject) => {
      _this.identityManager.discoverUserRegistered().then((identity) => {
        console.log('[ElearningPlayer] GET MY IDENTITY:', identity);
        resolve(identity);
      }).catch((error) => {
        console.error('[ElearningPlayer] ERROR:', error);
        reject(error);
      });
    });

  }

  _resumeReporters() {
    let _this = this;

    //debugger;
    return new Promise((resolve, reject) => {
      _this.syncher.resumeReporters({ store: true }).then((reporters) => {
        console.log('[ElearningPlayer] Reporters resumed', reporters);

        let reportersList = Object.keys(reporters);

        if (reportersList.length > 0) {

          _this._getRegisteredUser().then((identity) => {

            reportersList.forEach((dataObjectReporterURL) => {
              //debugger;
              console.log(identity);
              _this.identity = identity;
              console.log('[ElearningPlayer] ', dataObjectReporterURL);
              console.log('[ElearningPlayer]', reporters[dataObjectReporterURL]);

              if (identity.userURL == reporters[dataObjectReporterURL].metadata.subscriberUsers[0] && reporters[dataObjectReporterURL].metadata.name == 'elearning') {
                //debugger;
                _this.reporter = reporters[dataObjectReporterURL];
                _this.reporter.onSubscription((event) => event.accept());
                return resolve(true);
              }
            });
            return resolve(false);
          });
        } else {
          return resolve(false);
        }
      }).catch((reason) => {
        console.info('[ElearningPlayer] Reporters:', reason);
      });
    });
  }

  //FOR invite elearning  -> hyperty://sharing-cities-dsm/elearning
  invite(observer) {

    let _this = this;
    _this.reporter.inviteObservers([observer]);
  }

  initQuizSubmission() {
    return new Promise((resolve) => {

      let _this = this;
      if (_this.reporter == null) {
        _this.syncher.create(_this.objectDescURL, [], {}, true, false, 'elearning', {}, { resources: ['learning-context'] })
          .then((reporter) => {
            _this.reporter = reporter;
            console.log('[ElearningPlayer]  DataObjectReporter', _this.reporter);
            reporter.onSubscription((event) => event.accept());
            _this.search.myIdentity().then(identity => {
              _this.identity = identity;
            });
            resolve(true);
          });
      } else {
        resolve(true);
      }
    });
  }

  answer(id, answers) {
    let _this = this;
    let date = new Date();
    _this.reporter.data.values = [
      { id: id, date: date, answers: answers },
    ];

  }

  // can call with 'data://sharing-cities-dsm/elearning'
  retrieveQuizzes(quizzesURL) {

    return new Promise((resolve) => {
      let _this = this;

      let createMessage = {
        type: 'forward', to: quizzesURL, from: _this.hypertyURL,
        body: {
          from: _this.hypertyURL,
          type: 'read'
        }
      };
      console.log('elearning-player-retrieveQuizzes()', createMessage);

      _this.bus.postMessage(createMessage, (reply) => {
        resolve(reply);
        console.log('elearning-player-retrieveQuizzes() reply: ', reply);
      });

    });

  }

}

export default function activate(hypertyURL, bus, config) {
  return {
    name: 'ElearningPlayer',
    instance: new ElearningPlayer(hypertyURL, bus, config)
  };
}
<|endoftext|>


<commit_before>/**
 * Created by andreas on 02.05.14.
 */
goog.provide('avnav.gui.Navpage');
goog.require('avnav.gui.Handler');
goog.require('avnav.gui.Page');

/**
 *
 * @constructor
 * @extends {avnav.gui.Page}
 */
avnav.gui.Navpage=function(){
    goog.base(this,'navpage');
    /** @private */
    this.options_=null;
    /**
     * @private
     * @type {number}
     */
    this.timer=0;
    /**
     * the current visible overlay (jQuery object)
     * @type {null}
     */
    this.overlay=null;
    /**
     * the time (in ms) when the current overlay should be hidden
     * @type {number}
     */
    this.hidetime=0;
    /**
     * the dom id of the map
     * @private
     * @type {string}
     */
    this.mapdom='avi_map_navpage';
    var self=this;
    $(document).on(avnav.nav.NavEvent.EVENT_TYPE, function(ev,evdata){
       self.navEvent(evdata);
    });
    $(document).on(avnav.map.MapEvent.EVENT_TYPE, function(ev,evdata){
        self.mapEvent(evdata);
    });

};
goog.inherits(avnav.gui.Navpage,avnav.gui.Page);

/**
 * get the mapholder
 * @private
 * @returns {avnav.map.MapHolder}
 */
avnav.gui.Navpage.prototype.getMap=function(){
    if (!this.gui) return null;
    return this.gui.map;
};

avnav.gui.Navpage.prototype.showPage=function(options){
    if (!this.gui) return;
    this.fillDisplayFromGps();
    if (options) this.options_=options;
    else {
        if (! this.options_){
            alert("invalid navpage call - no chart selected");
            return;
        }
    }
    //chartbase: optional url for charts
    //list: the base url
    var chartbase=this.options_.charturl;
    var list=this.options_.url;
    if (! chartbase){
        chartbase=list;
    }
    if (! list.match(/^http:/)){
        if (list.match(/^\//)){
            list=window.location.href.replace(/^([^\/:]*:\/\/[^\/]*).*/,'$1')+list;
        }
        else {
            list=window.location.href.replace(/[?].*/,'').replace(/[^\/]*$/,'')+"/"+list;
        }
    }
    var url=list+"/avnav.xml";
    var self=this;
    $.ajax({
        url:url,
        dataType: 'xml',
        cache: false,
        success: function(data){
            self.getMap().initMap(self.mapdom,data,chartbase);
        },
        error: function(ev){
            alert("unable to load charts "+ev.responseText);
        }
    });
    this.buttonUpdate(true);
    this.updateAisPanel();
    this.fillDisplayFromGps();
};
/**
 * the periodic timer call
 * update buttons and handle hiding of overlay
 * @param startTimer
 */
avnav.gui.Navpage.prototype.buttonUpdate=function(startTimer){
    //TODO: make this more generic
    var markerLock=this.gui.map.getMarkerLock();
    this.handleToggleButton('#avb_LockMarker',markerLock);
    var gpsLock=this.gui.map.getGpsLock();
    this.handleToggleButton('#avb_LockPos',gpsLock);
    var self=this;
    if (this.hidetime >0 && this.hidetime <= new Date().getTime()|| gpsLock){
        this.hideOverlay();
        this.hidetime=0;
    }
    if (startTimer) this.timer=window.setTimeout(function(){
        self.buttonUpdate(true);
        },
        self.gui.properties.getProperties().buttonUpdateTime
    );
};

avnav.gui.Navpage.prototype.hidePage=function(){
    if (this.timer) window.clearTimeout(this.timer);
    this.hideOverlay();
    this.hidetime=0;
};
/**
 *
 */
avnav.gui.Navpage.prototype.localInit=function(){
    $('#leftBottomMarker').click({page:this},function(ev){
        var marker=ev.data.page.navobject.getRawData(avnav.nav.NavEventType.NAV).markerLatlon;
        ev.data.page.gui.map.setCenter(marker);
    });
    $('#leftBottomPosition').click({page:this},function(ev){
        var gps=ev.data.page.navobject.getRawData(avnav.nav.NavEventType.GPS);
        if (gps.valid) ev.data.page.gui.map.setCenter(gps);
    });
    $('#centerDisplay').click({page:this},function(ev){
       ev.data.page.hideOverlay();
    });
    $('#aisInfo').click({page:this},function(ev){
        ev.data.page.gui.showPage('aispage');
    });
};

/**
 * @private
 * @param {Array.<string>} opt_names
 */
avnav.gui.Navpage.prototype.fillDisplayFromGps=function(opt_names){
    if (! this.navobject) return;
    var names=opt_names||this.navobject.getValueNames();
    for (var i=0;i< names.length;i++){
        this.getDiv().find('.avd_'+names[i]).text(this.navobject.getValue(names[i]));
    }
    if (this.navobject.getRawData(avnav.nav.NavEventType.GPS).valid){
        $('#boatPositionStatus').attr('src',this.gui.properties.getProperties().statusOkImage);
    }
    else {
        $('#boatPositionStatus').attr('src',this.gui.properties.getProperties().statusErrorImage);
    }
};

/**
 * update the AIS panel
 */
avnav.gui.Navpage.prototype.updateAisPanel=function() {
    var aisPanel = this.getDiv().find('.avn_aisInfo');
    if (aisPanel) {
        var nearestTarget = this.navobject.getAisData().getNearestAisTarget();
        if (nearestTarget.mmsi) {
            //should show the AIS panel
            if (this.showHideAdditionalPanel('#aisInfo', true, '#' + this.mapdom))
                this.gui.map.updateSize();
            var displayClass = "avn_ais_info_first";
            var warningClass = "avn_ais_info_warning";
            if (!nearestTarget.warning) {
                $('#aisInfo').removeClass(warningClass);
                if (nearestTarget.nearest) $('#aisInfo').addClass(displayClass);
                else $('#aisInfo').removeClass(displayClass);
            }
            else {
                $('#aisInfo').addClass(warningClass);
                $('#aisInfo').removeClass(displayClass);
            }
        }
        else {
            if (this.showHideAdditionalPanel('#aisInfo', false, '#' + this.mapdom))
                this.gui.map.updateSize();
        }
    }
};

/**
 *
 * @param {avnav.nav.NavEvent} evdata
 */
avnav.gui.Navpage.prototype.navEvent=function(evdata){
    if (! this.visible) return;
    if (evdata.type == avnav.nav.NavEventType.AIS){
        this.updateAisPanel();
    }
    this.fillDisplayFromGps(evdata.changedNames);
};
/**
 *
 * @param {avnav.map.MapEvent} evdata
 */
avnav.gui.Navpage.prototype.mapEvent=function(evdata){
    if (! this.visible) return;
    if (evdata.type == avnav.map.EventType.MOVE) {
        //show the center display if not visible
        if (this.overlay != null) {
            this.hidetime = new Date().getTime() + this.gui.properties.getProperties().centerDisplayTimeout;
            return;
        }
        this.overlay = this.getDiv().find('#centerDisplay');
        this.hidetime = new Date().getTime() + this.gui.properties.getProperties().centerDisplayTimeout;
        this.overlay.show();
    }
    if (evdata.type == avnav.map.EventType.SELECT){
        var feature=evdata.parameter.feature;
        if (! feature) return;
        if (feature.aisparam && feature.aisparam.mmsi){
            this.navobject.getAisData().setTrackedTarget(feature.aisparam.mmsi);
            this.gui.showPage('aispage');
        }
    }
};

avnav.gui.Navpage.prototype.hideOverlay=function(){
    if (this.overlay != null){
        this.overlay.hide();
        this.overlay=null;
        this.hidetime=0;
    }
};
//-------------------------- Buttons ----------------------------------------

avnav.gui.Navpage.prototype.btnZoomIn=function (button,ev){
    log("ZoomIn clicked");
    this.getMap().changeZoom(1);
};

avnav.gui.Navpage.prototype.btnZoomOut=function (button,ev){
    log("ZoomOut clicked");
    this.getMap().changeZoom(-1);
};
avnav.gui.Navpage.prototype.btnLockPos=function (button,ev){
    var nLock=! this.gui.map.getGpsLock();
    this.gui.map.setGpsLock(nLock);
    this.handleToggleButton(button,nLock);
    if (nLock) this.hideOverlay();
    log("LockPos clicked");
};
avnav.gui.Navpage.prototype.btnLockMarker=function (button,ev){
    var nLock=! this.gui.map.getMarkerLock();
    this.gui.map.setMarkerLock(nLock);
    this.handleToggleButton(button,nLock);
    log("LockMarker clicked");
};
avnav.gui.Navpage.prototype.btnCancelNav=function (button,ev){
    log("CancelNav clicked");
    this.gui.showPage('mainpage');
};

/**
 * create the page instance
 */
(function(){
    //create an instance of the status page handler
    var page=new avnav.gui.Navpage();
}());

<commit_msg>avoid slide in when map has not changed<commit_after>/**
 * Created by andreas on 02.05.14.
 */
goog.provide('avnav.gui.Navpage');
goog.require('avnav.gui.Handler');
goog.require('avnav.gui.Page');

/**
 *
 * @constructor
 * @extends {avnav.gui.Page}
 */
avnav.gui.Navpage=function(){
    goog.base(this,'navpage');
    /** @private */
    this.options_=null;
    /**
     * @private
     * @type {number}
     */
    this.timer=0;
    /**
     * the current visible overlay (jQuery object)
     * @type {null}
     */
    this.overlay=null;
    /**
     * the time (in ms) when the current overlay should be hidden
     * @type {number}
     */
    this.hidetime=0;
    /**
     * the dom id of the map
     * @private
     * @type {string}
     */
    this.mapdom='avi_map_navpage';
    var self=this;
    $(document).on(avnav.nav.NavEvent.EVENT_TYPE, function(ev,evdata){
       self.navEvent(evdata);
    });
    $(document).on(avnav.map.MapEvent.EVENT_TYPE, function(ev,evdata){
        self.mapEvent(evdata);
    });

};
goog.inherits(avnav.gui.Navpage,avnav.gui.Page);

/**
 * get the mapholder
 * @private
 * @returns {avnav.map.MapHolder}
 */
avnav.gui.Navpage.prototype.getMap=function(){
    if (!this.gui) return null;
    return this.gui.map;
};

avnav.gui.Navpage.prototype.showPage=function(options){
    if (!this.gui) return;
    this.fillDisplayFromGps();
    var newMap=false;
    if (options) {
        this.options_=options;
        newMap=true;
    }
    else {
        if (! this.options_){
            alert("invalid navpage call - no chart selected");
            return;
        }
    }
    if (newMap) {
        //chartbase: optional url for charts
        //list: the base url
        var chartbase = this.options_.charturl;
        var list = this.options_.url;
        if (!chartbase) {
            chartbase = list;
        }
        if (!list.match(/^http:/)) {
            if (list.match(/^\//)) {
                list = window.location.href.replace(/^([^\/:]*:\/\/[^\/]*).*/, '$1') + list;
            }
            else {
                list = window.location.href.replace(/[?].*/, '').replace(/[^\/]*$/, '') + "/" + list;
            }
        }
        var url = list + "/avnav.xml";
        var self = this;
        $.ajax({
            url: url,
            dataType: 'xml',
            cache: false,
            success: function (data) {
                self.getMap().initMap(self.mapdom, data, chartbase);
            },
            error: function (ev) {
                alert("unable to load charts " + ev.responseText);
            }
        });
    }
    this.buttonUpdate(true);
    this.updateAisPanel();
    this.fillDisplayFromGps();
};
/**
 * the periodic timer call
 * update buttons and handle hiding of overlay
 * @param startTimer
 */
avnav.gui.Navpage.prototype.buttonUpdate=function(startTimer){
    //TODO: make this more generic
    var markerLock=this.gui.map.getMarkerLock();
    this.handleToggleButton('#avb_LockMarker',markerLock);
    var gpsLock=this.gui.map.getGpsLock();
    this.handleToggleButton('#avb_LockPos',gpsLock);
    var self=this;
    if (this.hidetime >0 && this.hidetime <= new Date().getTime()|| gpsLock){
        this.hideOverlay();
        this.hidetime=0;
    }
    if (startTimer) this.timer=window.setTimeout(function(){
        self.buttonUpdate(true);
        },
        self.gui.properties.getProperties().buttonUpdateTime
    );
};

avnav.gui.Navpage.prototype.hidePage=function(){
    if (this.timer) window.clearTimeout(this.timer);
    this.hideOverlay();
    this.hidetime=0;
};
/**
 *
 */
avnav.gui.Navpage.prototype.localInit=function(){
    $('#leftBottomMarker').click({page:this},function(ev){
        var marker=ev.data.page.navobject.getRawData(avnav.nav.NavEventType.NAV).markerLatlon;
        ev.data.page.gui.map.setCenter(marker);
    });
    $('#leftBottomPosition').click({page:this},function(ev){
        var gps=ev.data.page.navobject.getRawData(avnav.nav.NavEventType.GPS);
        if (gps.valid) ev.data.page.gui.map.setCenter(gps);
    });
    $('#centerDisplay').click({page:this},function(ev){
       ev.data.page.hideOverlay();
    });
    $('#aisInfo').click({page:this},function(ev){
        ev.data.page.gui.showPage('aispage');
    });
};

/**
 * @private
 * @param {Array.<string>} opt_names
 */
avnav.gui.Navpage.prototype.fillDisplayFromGps=function(opt_names){
    if (! this.navobject) return;
    var names=opt_names||this.navobject.getValueNames();
    for (var i=0;i< names.length;i++){
        this.getDiv().find('.avd_'+names[i]).text(this.navobject.getValue(names[i]));
    }
    if (this.navobject.getRawData(avnav.nav.NavEventType.GPS).valid){
        $('#boatPositionStatus').attr('src',this.gui.properties.getProperties().statusOkImage);
    }
    else {
        $('#boatPositionStatus').attr('src',this.gui.properties.getProperties().statusErrorImage);
    }
};

/**
 * update the AIS panel
 */
avnav.gui.Navpage.prototype.updateAisPanel=function() {
    var aisPanel = this.getDiv().find('.avn_aisInfo');
    if (aisPanel) {
        var nearestTarget = this.navobject.getAisData().getNearestAisTarget();
        if (nearestTarget.mmsi) {
            //should show the AIS panel
            if (this.showHideAdditionalPanel('#aisInfo', true, '#' + this.mapdom))
                this.gui.map.updateSize();
            var displayClass = "avn_ais_info_first";
            var warningClass = "avn_ais_info_warning";
            if (!nearestTarget.warning) {
                $('#aisInfo').removeClass(warningClass);
                if (nearestTarget.nearest) $('#aisInfo').addClass(displayClass);
                else $('#aisInfo').removeClass(displayClass);
            }
            else {
                $('#aisInfo').addClass(warningClass);
                $('#aisInfo').removeClass(displayClass);
            }
        }
        else {
            if (this.showHideAdditionalPanel('#aisInfo', false, '#' + this.mapdom))
                this.gui.map.updateSize();
        }
    }
};

/**
 *
 * @param {avnav.nav.NavEvent} evdata
 */
avnav.gui.Navpage.prototype.navEvent=function(evdata){
    if (! this.visible) return;
    if (evdata.type == avnav.nav.NavEventType.AIS){
        this.updateAisPanel();
    }
    this.fillDisplayFromGps(evdata.changedNames);
};
/**
 *
 * @param {avnav.map.MapEvent} evdata
 */
avnav.gui.Navpage.prototype.mapEvent=function(evdata){
    if (! this.visible) return;
    if (evdata.type == avnav.map.EventType.MOVE) {
        //show the center display if not visible
        if (this.overlay != null) {
            this.hidetime = new Date().getTime() + this.gui.properties.getProperties().centerDisplayTimeout;
            return;
        }
        this.overlay = this.getDiv().find('#centerDisplay');
        this.hidetime = new Date().getTime() + this.gui.properties.getProperties().centerDisplayTimeout;
        this.overlay.show();
    }
    if (evdata.type == avnav.map.EventType.SELECT){
        var feature=evdata.parameter.feature;
        if (! feature) return;
        if (feature.aisparam && feature.aisparam.mmsi){
            this.navobject.getAisData().setTrackedTarget(feature.aisparam.mmsi);
            this.gui.showPage('aispage');
        }
    }
};

avnav.gui.Navpage.prototype.hideOverlay=function(){
    if (this.overlay != null){
        this.overlay.hide();
        this.overlay=null;
        this.hidetime=0;
    }
};
//-------------------------- Buttons ----------------------------------------

avnav.gui.Navpage.prototype.btnZoomIn=function (button,ev){
    log("ZoomIn clicked");
    this.getMap().changeZoom(1);
};

avnav.gui.Navpage.prototype.btnZoomOut=function (button,ev){
    log("ZoomOut clicked");
    this.getMap().changeZoom(-1);
};
avnav.gui.Navpage.prototype.btnLockPos=function (button,ev){
    var nLock=! this.gui.map.getGpsLock();
    this.gui.map.setGpsLock(nLock);
    this.handleToggleButton(button,nLock);
    if (nLock) this.hideOverlay();
    log("LockPos clicked");
};
avnav.gui.Navpage.prototype.btnLockMarker=function (button,ev){
    var nLock=! this.gui.map.getMarkerLock();
    this.gui.map.setMarkerLock(nLock);
    this.handleToggleButton(button,nLock);
    log("LockMarker clicked");
};
avnav.gui.Navpage.prototype.btnCancelNav=function (button,ev){
    log("CancelNav clicked");
    this.gui.showPage('mainpage');
};

/**
 * create the page instance
 */
(function(){
    //create an instance of the status page handler
    var page=new avnav.gui.Navpage();
}());

<|endoftext|>


<commit_before><commit_msg>Removed temporary file name.<commit_after><|endoftext|>


<commit_before><commit_msg>Add method __add__ for strings with surrogate pairs<commit_after><|endoftext|>


<commit_before><commit_msg>Fix for slashdot<commit_after><|endoftext|>


<commit_before>/*
Copyright (c) 2011 Cimaron Shanahan

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

GraphicsContext3D = (function() {

	function Initializer() {

		//public:
		this.webglCtx = null;
		this.canvas = null;

		this.buffer = null;
		this.context = null;

		//private:
		this._state = {};
		this._dirty = false;

		this._frame = {};
		this._quality = {};
	}

	var GraphicsContext3D = new jClass('GraphicsContext3D', Initializer);

	//public:

	GraphicsContext3D.GraphicsContext3D = function(webglCtx) {
		this.webglCtx = webglCtx;
		this.canvas = webglCtx.canvas;
		this.context = this.canvas.getContext('2d');

		//create our cnvGL context here;
		this._scale = 1;

		this._createBuffer();

		//initialize state
		glClearColor(0, 0, 0, 255);
		glClearDepth(1.0);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		this._quality.factor = 1;
		this.setTargetFps(2);

		var This = this;
		setInterval(function() { This._redraw(); }, 0);
	};

	//public:

	GraphicsContext3D.activeTexture = function(texture) {
		glActiveTexture(texture);
	};

	GraphicsContext3D.attachShader = function(program, shader) {
		glAttachShader(program, shader);
	};

	GraphicsContext3D.bindBuffer = function(target, buffer) {
		glBindBuffer(target, buffer);
	};

	GraphicsContext3D.bindTexture = function(target, texture) {
		glBindTexture(target, texture);
	};

	GraphicsContext3D.bufferData = function(target, data, usage) {
		/*
		if (typeof data == 'number') {
		}
		*/
		glBufferData(target, data.length, data, usage);
	};

	GraphicsContext3D.clear = function(mask) {
		this._dirty = true;
		glClear(mask);
	};

	GraphicsContext3D.clearColor = function(red, green, blue, alpha) {
		glClearColor(red, green, blue, alpha);
	};

	GraphicsContext3D.compileShader = function(shader) {
		glCompileShader(shader);
	};

	GraphicsContext3D.createBuffer = function() {
		var buffers = [];
		glGenBuffers(1, buffers);
		return buffers[0][0];
	};

	GraphicsContext3D.createProgram = function() {
		return glCreateProgram();
	};

	GraphicsContext3D.createShader = function(type) {
		return glCreateShader(type);
	};

	GraphicsContext3D.createTexture = function() {
		var textures = [];
		glGenTextures(1, textures);
		return textures[0][0];
	};

	GraphicsContext3D.drawArrays = function(mode, first, count) {
		this._dirty = true;
		glDrawArrays(mode, first, count);
	};

	GraphicsContext3D.drawElements = function(mode, count, type, offset) {
		this._dirty = true;
		glDrawElements(mode, count, type, offset);
	};

	GraphicsContext3D.enable = function(cap) {
		glEnable(cap);
	};

	GraphicsContext3D.enableVertexAttribArray = function(index) {
		glEnableVertexAttribArray(index);
	};

	GraphicsContext3D.getAttribLocation = function(program, name) {
		return glGetAttribLocation(program, name);
	};

	GraphicsContext3D.getProgramParameter = function(program, pname) {
		var params = [];
		glGetProgramiv(program, pname, params);
		return params[0];
	};

	GraphicsContext3D.getShaderInfoLog = function(shader) {
		var length = [], infoLog = [];
		glGetShaderInfoLog(shader, null, length, infoLog);
		return infoLog[0];
	};

	GraphicsContext3D.getShaderParameter = function(shader, pname) {
		var params = [];
		glGetShaderiv(shader, pname, params);
		return params[0];
	};

	GraphicsContext3D.getUniformLocation = function(program, name) {
		return glGetUniformLocation(program, name);
	};

	GraphicsContext3D.linkProgram = function(program) {
		glLinkProgram(program);
	};

	GraphicsContext3D.pixelStorei = function(pname, param) {
		switch (pname) {
			case 0x9240:
				this._state.UNPACK_FLIP_Y_WEBGL = pname;
				break;
			default:
				glPixelStorei(pname, param);
		}
	};

	GraphicsContext3D.shaderSource = function(shader, string) {
		glShaderSource(shader, 1, [string], [string.length]);
	};

	GraphicsContext3D.uniform1i = function(location, x) {
		return glUniform1i(location, x);
	};

	GraphicsContext3D.uniformMatrix4fv = function(location, transpose, value) {
		return glUniformMatrix4fv(location, value.length / 16, transpose, value);
	};

	GraphicsContext3D.useProgram = function(program) {
		glUseProgram(program);
	};

	GraphicsContext3D.texImage2D = function(target, level, internalformat, format, type, source) {
		var width, height, border, cnv, ctx, cnv, i, j, id, is, t;

		//todo: check origin-clean flag

		if (source instanceof HTMLImageElement) {
			cnv = document.createElement('canvas');
			cnv.width = source.width;
			cnv.height = source.height;
			ctx = cnv.getContext('2d');
			ctx.drawImage(source, 0, 0, source.width, source.height);
			source = cnv;
		}

		if (source instanceof HTMLCanvasElement) {
			if (!ctx) {
				ctx = source.getContext('2d');
			}
			source = ctx.getImageData(0, 0, source.width, source.height);
		}

		if (source.data) {
			width = source.width;
			height = source.height;
			border = 0;
			source = source.data;
		} else {
			width = format;
			height = type;
			border = source;
			format = arguments[6];
			type = arguments[7];
			source = arguments[8];
			if (!source) {
				source = new Uint8Array(width * height * 4);
			}
		}

		//need to invert data rows
		if (this._state.UNPACK_FLIP_Y_WEBGL) {
			t = new Uint8Array(width * height * 4);
			for (i = 0; i < height; i++) {
				for (j = 0; j < width; j++) {
					is = ((width * i) + j) * 4;
					id = ((width * (height - i)) + j) * 4;
					t[id] = source[is];
					t[id + 1] = source[is + 1];
					t[id + 2] = source[is + 2];
					t[id + 3] = source[is + 3];
				}
			}
			source = t;
		}

		glTexImage2D(target, level, internalformat, width, height, border, format, type, source);
	};

	GraphicsContext3D.texParameteri = function(target, pname, param) {
		glTexParameteri(target, pname, param);
	};

	GraphicsContext3D.vertexAttribPointer = function(idx, size, type, normalized, stride, offset) {
		var pointer = [];
		glVertexAttribPointer(idx, size, type, normalized, stride, offset);
	};

	GraphicsContext3D.viewport = function(x, y, width, height) {
		x = Math.round(x / this._quality.factor);
		y = Math.round(y / this._quality.factor);
		width = Math.round(width / this._quality.factor);
		height = Math.round(height / this._quality.factor);

		glViewport(x, y, width, height);
	};

	GraphicsContext3D.setTargetFps = function(low, high) {
		this._frame.fps = 0;
		this._frame.last = [];
		this._quality.fpsLow = low;
		this._quality.fpsHigh = high ? high : 4 * low;
		this._quality.fpsLowThreshold = 0;
		this._quality.fpsHighThreshold = 0;
	};

	//private:

	GraphicsContext3D._createBuffer = function() {
		var ctx, width, height;

		ctx = cnvgl_context.getCurrentContext();

		if (this._quality.factor > 1) {
			if (!this._quality.cnv) {
				this._quality.cnv = document.createElement('canvas');
			}
			width = Math.round(this.canvas.width / this._quality.factor);
			height = Math.round(this.canvas.height / this._quality.factor);
			this.webglCtx.drawingBufferWidth = width;
			this.webglCtx.drawingBufferHeight = height;
			this._quality.cnv.width = width;
			this._quality.cnv.height = height;
			this._quality.ctx = this._quality.cnv.getContext('2d');
			this.context.mozImageSmoothingEnabled = false;
		} else {
			width = this.canvas.width;
			height = this.canvas.height;
		}

		//initialize buffers
		this.buffer = this.context.createImageData(width, height);
		ctx.color_buffer = this.buffer.data;
		ctx.depth_buffer = new Float32Array(width * height);
	};

	GraphicsContext3D._updateFrame = function() {
		var time, dur;
		//update frame counts, fps, etc.
		this._frame.count++;
		time = new Date().getTime();
		this._frame.last.push(time);

		//average over one second period
		dur = time - this._frame.last[0];
		this._frame.fps = 1000 * this._frame.last.length / dur;
		if (dur > 1000) {
			this._frame.last.shift();
		}
	};

	GraphicsContext3D._checkFps = function() {
		var change;

		if (this._frame.fps < this._quality.fpsLow) {
			this._quality.fpsLowThreshold++;
		}

		//must maintain low fps over period of one second
		if (this._quality.fpsLowThreshold > this._frame.fps) {
			this._quality.fpsLowThreshold = 0;
			change = 1 + this._quality.fpsLow / Math.max(this._frame.fps, 1) / 4;
			this._quality.factor *= change;
			this._createBuffer();
		}

		if (this._frame.fps > this._quality.fpsHigh) {
			this._quality.fpsHighThreshold++;
		}

		//must maintain high fps over period of one second
		if (this._quality.fpsHighThreshold > this._frame.fps && this._quality.factor > 1) {
			this._quality.fpsHighThreshold = 0;
			//and even then, only slowly increase the resolution
			this._quality.factor = Math.max(1, this._quality.factor / 1.1);
			this._createBuffer();
		}
	};

	GraphicsContext3D._redraw = function() {

		this._updateFrame();

		if (this._dirty) {
			this._dirty = false;

			if (this._quality.factor <= 1) {
				this.context.putImageData(this.buffer, 0, 0);
			} else {
				this._quality.ctx.putImageData(this.buffer, 0, 0);
				this.context.drawImage(this._quality.cnv, 0, 0, this.canvas.width, this.canvas.height);
			}
		}

		this._checkFps();

	};

	return GraphicsContext3D.Constructor;

}());

<commit_msg>Minor fixes<commit_after>/*
Copyright (c) 2011 Cimaron Shanahan

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

GraphicsContext3D = (function() {

	function Initializer() {

		//public:
		this.webglCtx = null;
		this.canvas = null;

		this.buffer = null;
		this.context = null;

		//private:
		this._state = {};
		this._dirty = false;

		this._frame = {};
		this._quality = {};
	}

	var GraphicsContext3D = new jClass('GraphicsContext3D', Initializer);

	//public:

	GraphicsContext3D.GraphicsContext3D = function(webglCtx) {
		this.webglCtx = webglCtx;
		this.canvas = webglCtx.canvas;
		this.context = this.canvas.getContext('2d');

		//create our cnvGL context here;
		this._scale = 1;

		this._createBuffer();

		//initialize state
		glClearColor(0, 0, 0, 255);
		glClearDepth(1.0);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		this._quality.factor = 1;
		this.setTargetFps(2);

		var This = this;
		setInterval(function() { This._redraw(); }, 0);
	};

	//public:

	GraphicsContext3D.activeTexture = function(texture) {
		glActiveTexture(texture);
	};

	GraphicsContext3D.attachShader = function(program, shader) {
		glAttachShader(program, shader);
	};

	GraphicsContext3D.bindBuffer = function(target, buffer) {
		glBindBuffer(target, buffer);
	};

	GraphicsContext3D.bindTexture = function(target, texture) {
		glBindTexture(target, texture);
	};

	GraphicsContext3D.bufferData = function(target, data, usage) {
		/*
		if (typeof data == 'number') {
		}
		*/
		glBufferData(target, data.length, data, usage);
	};

	GraphicsContext3D.clear = function(mask) {
		this._dirty = true;
		glClear(mask);
	};

	GraphicsContext3D.clearColor = function(red, green, blue, alpha) {
		glClearColor(red, green, blue, alpha);
	};

	GraphicsContext3D.compileShader = function(shader) {
		glCompileShader(shader);
	};

	GraphicsContext3D.createBuffer = function() {
		var buffers = [];
		glGenBuffers(1, buffers);
		return buffers[0][0];
	};

	GraphicsContext3D.createProgram = function() {
		return glCreateProgram();
	};

	GraphicsContext3D.createShader = function(type) {
		return glCreateShader(type);
	};

	GraphicsContext3D.createTexture = function() {
		var textures = [];
		glGenTextures(1, textures);
		return textures[0][0];
	};

	GraphicsContext3D.drawArrays = function(mode, first, count) {
		this._dirty = true;
		glDrawArrays(mode, first, count);
	};

	GraphicsContext3D.drawElements = function(mode, count, type, offset) {
		this._dirty = true;
		glDrawElements(mode, count, type, offset);
	};

	GraphicsContext3D.enable = function(cap) {
		glEnable(cap);
	};

	GraphicsContext3D.enableVertexAttribArray = function(index) {
		glEnableVertexAttribArray(index);
	};

	GraphicsContext3D.getAttribLocation = function(program, name) {
		return glGetAttribLocation(program, name);
	};

	GraphicsContext3D.getProgramParameter = function(program, pname) {
		var params = [];
		glGetProgramiv(program, pname, params);
		return params[0];
	};

	GraphicsContext3D.getShaderInfoLog = function(shader) {
		var length = [], infoLog = [];
		glGetShaderInfoLog(shader, null, length, infoLog);
		return infoLog[0];
	};

	GraphicsContext3D.getShaderParameter = function(shader, pname) {
		var params = [];
		glGetShaderiv(shader, pname, params);
		return params[0];
	};

	GraphicsContext3D.getUniformLocation = function(program, name) {
		return glGetUniformLocation(program, name);
	};

	GraphicsContext3D.linkProgram = function(program) {
		glLinkProgram(program);
	};

	GraphicsContext3D.pixelStorei = function(pname, param) {
		switch (pname) {
			case 0x9240:
				this._state.UNPACK_FLIP_Y_WEBGL = pname;
				break;
			default:
				glPixelStorei(pname, param);
		}
	};

	GraphicsContext3D.shaderSource = function(shader, string) {
		glShaderSource(shader, 1, [string], [string.length]);
	};

	GraphicsContext3D.uniform1i = function(location, x) {
		return glUniform1i(location, x);
	};

	GraphicsContext3D.uniformMatrix4fv = function(location, transpose, value) {
		return glUniformMatrix4fv(location, value.length / 16, transpose, value);
	};

	GraphicsContext3D.useProgram = function(program) {
		glUseProgram(program);
	};

	GraphicsContext3D.texImage2D = function(target, level, internalformat, format, type, source) {
		var width, height, border, cnv, ctx, cnv, i, j, id, is, t;

		//todo: check origin-clean flag

		if (source instanceof HTMLImageElement) {
			cnv = document.createElement('canvas');
			cnv.width = source.width;
			cnv.height = source.height;
			ctx = cnv.getContext('2d');
			ctx.drawImage(source, 0, 0, source.width, source.height);
			source = cnv;
		}

		if (source instanceof HTMLCanvasElement) {
			if (!ctx) {
				ctx = source.getContext('2d');
			}
			source = ctx.getImageData(0, 0, source.width, source.height);
		}

		if (source.data) {
			width = source.width;
			height = source.height;
			border = 0;
			source = source.data;
		} else {
			width = format;
			height = type;
			border = source;
			format = arguments[6];
			type = arguments[7];
			source = arguments[8];
			if (!source) {
				source = new Uint8Array(width * height * 4);
			}
		}

		//need to invert data rows
		if (this._state.UNPACK_FLIP_Y_WEBGL) {
			t = new Uint8Array(width * height * 4);
			for (i = 0; i < height; i++) {
				for (j = 0; j < width; j++) {
					is = ((width * i) + j) * 4;
					id = ((width * (height - i - 1)) + j) * 4;
					t[id] = source[is];
					t[id + 1] = source[is + 1];
					t[id + 2] = source[is + 2];
					t[id + 3] = source[is + 3];
				}
			}
			source = t;
		}

		glTexImage2D(target, level, internalformat, width, height, border, format, type, source);
	};

	GraphicsContext3D.texParameteri = function(target, pname, param) {
		glTexParameteri(target, pname, param);
	};

	GraphicsContext3D.vertexAttribPointer = function(idx, size, type, normalized, stride, offset) {
		var pointer = [];
		glVertexAttribPointer(idx, size, type, normalized, stride, offset);
	};

	GraphicsContext3D.viewport = function(x, y, width, height) {
		x = Math.round(x / this._quality.factor);
		y = Math.round(y / this._quality.factor);
		width = Math.round(width / this._quality.factor);
		height = Math.round(height / this._quality.factor);

		glViewport(x, y, width, height);
	};

	GraphicsContext3D.setTargetFps = function(low, high) {
		this._frame.fps = 0;
		this._frame.last = [];
		this._quality.fpsLow = low;
		this._quality.fpsHigh = high ? high : 4 * low;
		this._quality.fpsLowThreshold = 0;
		this._quality.fpsHighThreshold = 0;
	};

	//private:

	GraphicsContext3D._createBuffer = function() {
		var ctx, width, height;

		ctx = cnvgl_context.getCurrentContext();

		if (this._quality.factor > 1) {
			if (!this._quality.cnv) {
				this._quality.cnv = document.createElement('canvas');
			}
			width = Math.round(this.canvas.width / this._quality.factor);
			height = Math.round(this.canvas.height / this._quality.factor);
			this.webglCtx.drawingBufferWidth = width;
			this.webglCtx.drawingBufferHeight = height;
			this._quality.cnv.width = width;
			this._quality.cnv.height = height;
			this._quality.ctx = this._quality.cnv.getContext('2d');
			this.context.mozImageSmoothingEnabled = false;
		} else {
			width = this.canvas.width;
			height = this.canvas.height;
		}

		//initialize buffers
		this.buffer = this.context.createImageData(width, height);
		ctx.color_buffer = this.buffer.data;
		ctx.depth_buffer = new Float32Array(width * height);
	};

	GraphicsContext3D._updateFrame = function() {
		var time, dur;
		//update frame counts, fps, etc.
		this._frame.count++;
		time = new Date().getTime();
		this._frame.last.push(time);

		//average over one second period
		dur = time - this._frame.last[0];
		this._frame.fps = 1000 * this._frame.last.length / dur;
		if (dur > 1000) {
			this._frame.last.shift();
		}
	};

	GraphicsContext3D._checkFps = function() {
		var change;

		if (this._frame.fps < this._quality.fpsLow) {
			this._quality.fpsLowThreshold++;
		}

		//must maintain low fps over period of one second
		if (this._quality.fpsLowThreshold > this._frame.fps) {
			this._quality.fpsLowThreshold = 0;
			change = 1 + this._quality.fpsLow / Math.max(this._frame.fps, 1) / 4;
			this._quality.factor *= change;
			this._createBuffer();
		}

		if (this._frame.fps > this._quality.fpsHigh) {
			this._quality.fpsHighThreshold++;
		}

		//must maintain high fps over period of one second
		if (this._quality.fpsHighThreshold > this._frame.fps && this._quality.factor > 1) {
			this._quality.fpsHighThreshold = 0;
			//and even then, only slowly increase the resolution
			this._quality.factor = Math.max(1, this._quality.factor / 1.1);
			this._createBuffer();
		}
	};

	GraphicsContext3D._redraw = function() {

		this._updateFrame();

		if (this._dirty) {
			this._dirty = false;

			if (this._quality.factor <= 1) {
				this.context.putImageData(this.buffer, 0, 0);
			} else {
				this._quality.ctx.putImageData(this.buffer, 0, 0);
				this.context.drawImage(this._quality.cnv, 0, 0, this.canvas.width, this.canvas.height);
			}
		}

		this._checkFps();

	};

	return GraphicsContext3D.Constructor;

}());

<|endoftext|>


<commit_before>import Ember from 'ember';

export default Ember.Component.extend({
  classNameBindings: [
    "isCollapsed:collapsible-panel-container--collapsed:collapsible-panel-container",
    "alignmentNorth:collapsible-panel--north",
    "alignmentEast:collapsible-panel--east",
    "alignmentSouth:collapsible-panel--south",
    "alignmentWest:collapsible-panel--west"
  ],

  actions: {
    collapsePanel(){
      this.set('isCollapsed', true);
      this.sendAction('collapsePanel');
    },
    expandPanel(){
      this.set('isCollapsed', false);
      this.sendAction('expandPanel');
    }
  },

  init(){
    this._super(...arguments);

    let config = this.get("config");

    switch(config.region){
    case "north":
      this.set("alignmentNorth", true);
      break;

    case "east":
      this.set("alignmentEast", true);
      break;

    case "south":
      this.set("alignmentSouth", true);
      break;

    case "west":
      this.set("alignmentWest", true);
      break;
    }
  }
});
<commit_msg>fix class names<commit_after>import Ember from 'ember';

export default Ember.Component.extend({
  classNameBindings: [
    "isCollapsed:collapsed:",
    "alignmentNorth:collapsible-panel--north",
    "alignmentEast:collapsible-panel--east",
    "alignmentSouth:collapsible-panel--south",
    "alignmentWest:collapsible-panel--west",
    "alignmentCenter:collapsible-panel--center"
  ],
  classNames: "collapsible-panel-container",

  actions: {
    collapsePanel(){
      this.set('isCollapsed', true);
      this.sendAction('collapsePanel');
    },
    expandPanel(){
      this.set('isCollapsed', false);
      this.sendAction('expandPanel');
    }
  },

  init(){
    this._super(...arguments);

    let config = this.get("config");

    switch(config.region){
    case "north":
      this.set("alignmentNorth", true);
      break;

    case "east":
      this.set("alignmentEast", true);
      break;

    case "south":
      this.set("alignmentSouth", true);
      break;

    case "west":
      this.set("alignmentWest", true);
      break;

    case "center":
      this.set("alignmentCenter", true);
      break;
    }
  }
});
<|endoftext|>


<commit_before>/* jshint expr: true */
import Ember from 'ember';
import layout from '../templates/components/power-select-tree';
const { get, set, isBlank, computed, A, Component, $ } = Ember;

export default Component.extend({
  layout,
  classNames: ['ember-power-select-tree'],
  defaultLabelOpt: 'label',
  __selectedOptions: null,
  advancedTreeOptions: computed('treeOptions.[]', function() {
    return A(get(this, 'treeOptions'))
      .map(o => this._collapsableOption(o))
      .map(o => this._buildPath(o));
  }),
  currentOptions: computed('advancedTreeOptions.[]', '__selectedOptions.[]', function() {
    const __selectedOptions = get(this, '__selectedOptions');
    return get(this, 'advancedTreeOptions')
      .map(o => this._treeTraverse(o, (node) => this._setChecked(node, __selectedOptions)));
  }),

  groupedSelectedOptions: computed('__selectedOptions.[]', function() {
    return A(get(this, '__selectedOptions')).reduce((prev, curr) => {
      const humanPath = get(curr, 'humanPath') || '';
      const group = prev.findBy('humanPath', humanPath);
      if (group) {
        get(group, 'options').pushObject(curr);
      } else {
        prev.pushObject(
          {humanPath, options: A([curr]),
          nodeName: get(A(humanPath.split(' > ')), 'lastObject')});
      }

      return prev;
    }, A()).sortBy('humanPath');
  }),

  init() {
    this._super(...arguments);

    if (!get(this, 'labelOpt')) {
      set(this, 'labelOpt', get(this, 'defaultLabelOpt'));
    }

    this._setSelectedOptions();
  },

  didReceiveAttrs() {
    this._super(...arguments);
    if (!isBlank(get(this, 'selectedOptions'))) {
      this._setSelectedOptions();
    }
  },

  _setSelectedOptions() {
    const selectedOptions = A(get(this, 'selectedOptions'));
    let leaves = get(this, 'advancedTreeOptions')
      .map(o => this._treeTraverse(o, (node) => this._setChecked(node, selectedOptions)))
      .map(o => this._getLeaves(o));
    let node;
    let filteredOptions = selectedOptions.map(opt => {
      node = [].concat(...leaves).find(
        leaf => get(opt, 'key') === get(leaf, 'key') && get(opt, 'type') === get(leaf, 'type')
      );

      if (node) {
        return node;
      }

      set(opt, 'humanPath', get(opt, 'path').join(' > '));
      return opt;
    });
    set(this, '__selectedOptions', isBlank(selectedOptions) ? A() : filteredOptions);
  },

  _setChecked(o, __selectedOptions, isChecked = true) {
    if (A(__selectedOptions).find(
      opt => get(opt, 'key') === get(o, 'key') && get(opt, 'type') === get(o, 'type')
    )) {
      set(o, 'isChecked', isChecked);
    }
  },

  _buildPath(node, currPath = A()) {
    let newNode = Ember.$.extend(true, {}, node);
    const path = get(node, 'path');
    if (path && path.length) {
      set(newNode, 'humanPath', path.join(' > '));
      return newNode;
    }

    if (!get(node, 'nodeName') && currPath.length) {
      set(newNode, 'humanPath', currPath.join(' > '));
      set(newNode, 'path', currPath);
    } else {
      currPath.push(get(node, 'nodeName'));
      set(newNode, 'options', A(get(node, 'options')).map(
        o => this._buildPath(o, [].concat(...currPath)))
      );
      currPath = A();
    }

    return newNode;
  },

  _collapsableOption(opt) {
    const isSelectable = get(opt, 'isSelectable');
    const isChecked = leaf => get(leaf, 'isChecked');
    const isOptChecked = get(opt, 'isChecked');
    const groupName = get(opt, 'groupName');
    const options = get(opt, 'options') || [];
    const isCollapsed = get(opt, 'isCollapsed') || true;
    if (groupName) {
      return {
        isSelectable,
        isCollapsed,
        isChecked: options.some(isChecked) || isOptChecked || false,
        nodeName: groupName,
        options: options.map(o => this._collapsableOption(o))
      };
    }

    set(opt, 'isSelectable', true);
    set(opt, 'isChecked', !!isOptChecked);
    return opt;
  },

  _getLeaves(root, leaves = A()) {
    (get(root, 'options') || A()).forEach(
      o => !o.nodeName ? leaves.pushObject(o) : this._getLeaves(o, leaves)
    );
    return leaves;
  },

  _treeTraverse(root, visit) {
    visit(root);
    const options = A(get(root, 'options'));
    if (options.length) {
      options.forEach(o => this._treeTraverse(o, visit));
    }

    return root;
  },

  _findInternalNode(root, nameOrPath) {
    if (get(root, 'nodeName') === nameOrPath || get(root, 'humanPath') === nameOrPath) {
      return root;
    }
    let tmp, node;
    A(get(root, 'options')).forEach(o => {
      tmp = this._findInternalNode(o, nameOrPath);
      if (tmp) {
        node = tmp;
      }
    });

    return node;
  },

  onTreeSelectionChange(opts) {
    return get(this, 'onTreeSelectionChange')(opts);
  },

  scrollDropdownToSelected(el) {
    const container = $('.ember-power-select-tree-list').first();
    const scrollTop = $(el).offset().top - container.offset().top + container.scrollTop();
    return container.animate({ scrollTop }, 500);
  },

  actions: {
    handleSearch() {
      get(this, 'handleSearch')(...arguments);
      return false; // prevents default searching behaviour
    },
    onToggleGroup(group, evt) {
      // Check if checkbox or container is clicked
      const tagName = get(evt, 'target.tagName').toLowerCase();
      if (tagName === 'label' || tagName === 'input') {
        return;
      }
      set(group, 'isCollapsed', !get(group, 'isCollapsed'));

      return this.scrollDropdownToSelected(get(evt, 'target'));
    },
    removeNodeOrLeaf(nodeOrLeaf) {
      const __selectedOptions = get(this, '__selectedOptions');
      const isNode = !get(nodeOrLeaf, 'key');
      const key = isNode ? 'humanPath' : 'key';
      __selectedOptions.removeObjects(
        __selectedOptions.filterBy(key, get(nodeOrLeaf, key))
      );
      this._treeTraverse(nodeOrLeaf, o => set(o, 'isChecked', false));
      if (isNode) { // unchecks the group itself
        set(
          this._findInternalNode(
            {options: get(this, 'currentOptions')},
            get(nodeOrLeaf, 'nodeName') || get(nodeOrLeaf, 'humanPath')), 'isChecked', false
        );
      }
      set(this, '__selectedOptions', __selectedOptions);
    },
    handleChecked(nodeOrLeaf) {
      const newVal = !get(nodeOrLeaf, 'isChecked');
      const _setChecked = node => set(node, 'isChecked', newVal);
      const __selectedOptions = A(get(this, '__selectedOptions'));
      const __selectedOptionsKeys = __selectedOptions.map(o => get(o, 'key'));
      const nodeKey = get(nodeOrLeaf, 'key');
      const leaves = this._getLeaves(nodeOrLeaf);

      this._treeTraverse(nodeOrLeaf, _setChecked);

      if (get(nodeOrLeaf, 'nodeName')) {
        !newVal ?
          leaves.forEach(l => __selectedOptions.removeObject(__selectedOptions.findBy('key', get(l, 'key')))) :
          __selectedOptions.pushObjects(leaves.filter(l => !__selectedOptionsKeys.includes(get(l, 'key'))));
      } else {
        !newVal ?
          __selectedOptions.removeObject(__selectedOptions.findBy('key', nodeKey)) :
          __selectedOptions.pushObject(nodeOrLeaf);
      }

      set(this, '__selectedOptions', __selectedOptions);
      this.onTreeSelectionChange(__selectedOptions);
    }
  }
});
<commit_msg>FIX: better alignment<commit_after>/* jshint expr: true */
import Ember from 'ember';
import layout from '../templates/components/power-select-tree';
const { get, set, isBlank, computed, A, Component, $ } = Ember;

export default Component.extend({
  layout,
  classNames: ['ember-power-select-tree'],
  defaultLabelOpt: 'label',
  __selectedOptions: null,
  advancedTreeOptions: computed('treeOptions.[]', function() {
    return A(get(this, 'treeOptions'))
      .map(o => this._collapsableOption(o))
      .map(o => this._buildPath(o));
  }),
  currentOptions: computed('advancedTreeOptions.[]', '__selectedOptions.[]', function() {
    const __selectedOptions = get(this, '__selectedOptions');
    return get(this, 'advancedTreeOptions')
      .map(o => this._treeTraverse(o, (node) => this._setChecked(node, __selectedOptions)));
  }),

  groupedSelectedOptions: computed('__selectedOptions.[]', function() {
    return A(get(this, '__selectedOptions')).reduce((prev, curr) => {
      const humanPath = get(curr, 'humanPath') || '';
      const group = prev.findBy('humanPath', humanPath);
      if (group) {
        get(group, 'options').pushObject(curr);
      } else {
        prev.pushObject({
          humanPath,
          options: A([curr]),
          nodeName: get(A(humanPath.split(' > ')), 'lastObject')
        });
      }

      return prev;
    }, A()).sortBy('humanPath');
  }),

  init() {
    this._super(...arguments);

    if (!get(this, 'labelOpt')) {
      set(this, 'labelOpt', get(this, 'defaultLabelOpt'));
    }

    this._setSelectedOptions();
  },

  didReceiveAttrs() {
    this._super(...arguments);
    if (!isBlank(get(this, 'selectedOptions'))) {
      this._setSelectedOptions();
    }
  },

  _setSelectedOptions() {
    const selectedOptions = A(get(this, 'selectedOptions'));
    let leaves = get(this, 'advancedTreeOptions')
      .map(o => this._treeTraverse(o, (node) => this._setChecked(node, selectedOptions)))
      .map(o => this._getLeaves(o));
    let node;
    let filteredOptions = selectedOptions.map(opt => {
      node = [].concat(...leaves).find(
        leaf => get(opt, 'key') === get(leaf, 'key') && get(opt, 'type') === get(leaf, 'type')
      );

      if (node) {
        return node;
      }

      set(opt, 'humanPath', get(opt, 'path').join(' > '));
      return opt;
    });
    set(this, '__selectedOptions', isBlank(selectedOptions) ? A() : filteredOptions);
  },

  _setChecked(o, __selectedOptions, isChecked = true) {
    if (A(__selectedOptions).find(
      opt => get(opt, 'key') === get(o, 'key') && get(opt, 'type') === get(o, 'type')
    )) {
      set(o, 'isChecked', isChecked);
    }
  },

  _buildPath(node, currPath = A()) {
    let newNode = Ember.$.extend(true, {}, node);
    const path = get(node, 'path');
    if (path && path.length) {
      set(newNode, 'humanPath', path.join(' > '));
      return newNode;
    }

    if (!get(node, 'nodeName') && currPath.length) {
      set(newNode, 'humanPath', currPath.join(' > '));
      set(newNode, 'path', currPath);
    } else {
      currPath.push(get(node, 'nodeName'));
      set(newNode, 'options', A(get(node, 'options')).map(
        o => this._buildPath(o, [].concat(...currPath)))
      );
      currPath = A();
    }

    return newNode;
  },

  _collapsableOption(opt) {
    const isSelectable = get(opt, 'isSelectable');
    const isChecked = leaf => get(leaf, 'isChecked');
    const isOptChecked = get(opt, 'isChecked');
    const groupName = get(opt, 'groupName');
    const options = get(opt, 'options') || [];
    const isCollapsed = get(opt, 'isCollapsed') || true;
    if (groupName) {
      return {
        isSelectable,
        isCollapsed,
        isChecked: options.some(isChecked) || isOptChecked || false,
        nodeName: groupName,
        options: options.map(o => this._collapsableOption(o))
      };
    }

    set(opt, 'isSelectable', true);
    set(opt, 'isChecked', !!isOptChecked);
    return opt;
  },

  _getLeaves(root, leaves = A()) {
    (get(root, 'options') || A()).forEach(
      o => !o.nodeName ? leaves.pushObject(o) : this._getLeaves(o, leaves)
    );
    return leaves;
  },

  _treeTraverse(root, visit) {
    visit(root);
    const options = A(get(root, 'options'));
    if (options.length) {
      options.forEach(o => this._treeTraverse(o, visit));
    }

    return root;
  },

  _findInternalNode(root, nameOrPath) {
    if (get(root, 'nodeName') === nameOrPath || get(root, 'humanPath') === nameOrPath) {
      return root;
    }
    let tmp, node;
    A(get(root, 'options')).forEach(o => {
      tmp = this._findInternalNode(o, nameOrPath);
      if (tmp) {
        node = tmp;
      }
    });

    return node;
  },

  onTreeSelectionChange(opts) {
    return get(this, 'onTreeSelectionChange')(opts);
  },

  scrollDropdownToSelected(el) {
    const container = $('.ember-power-select-tree-list').first();
    const scrollTop = $(el).offset().top - container.offset().top + container.scrollTop();
    return container.animate({ scrollTop }, 500);
  },

  actions: {
    handleSearch() {
      get(this, 'handleSearch')(...arguments);
      return false; // prevents default searching behaviour
    },
    onToggleGroup(group, evt) {
      // Check if checkbox or container is clicked
      const tagName = get(evt, 'target.tagName').toLowerCase();
      if (tagName === 'label' || tagName === 'input') {
        return;
      }
      set(group, 'isCollapsed', !get(group, 'isCollapsed'));

      return this.scrollDropdownToSelected(get(evt, 'target'));
    },
    removeNodeOrLeaf(nodeOrLeaf) {
      const __selectedOptions = get(this, '__selectedOptions');
      const isNode = !get(nodeOrLeaf, 'key');
      const key = isNode ? 'humanPath' : 'key';
      __selectedOptions.removeObjects(
        __selectedOptions.filterBy(key, get(nodeOrLeaf, key))
      );
      this._treeTraverse(nodeOrLeaf, o => set(o, 'isChecked', false));
      if (isNode) { // unchecks the group itself
        set(
          this._findInternalNode(
            {options: get(this, 'currentOptions')},
            get(nodeOrLeaf, 'nodeName') || get(nodeOrLeaf, 'humanPath')), 'isChecked', false
        );
      }
      set(this, '__selectedOptions', __selectedOptions);
    },
    handleChecked(nodeOrLeaf) {
      const newVal = !get(nodeOrLeaf, 'isChecked');
      const _setChecked = node => set(node, 'isChecked', newVal);
      const __selectedOptions = A(get(this, '__selectedOptions'));
      const __selectedOptionsKeys = __selectedOptions.map(o => get(o, 'key'));
      const nodeKey = get(nodeOrLeaf, 'key');
      const leaves = this._getLeaves(nodeOrLeaf);

      this._treeTraverse(nodeOrLeaf, _setChecked);

      if (get(nodeOrLeaf, 'nodeName')) {
        !newVal ?
          leaves.forEach(l => __selectedOptions.removeObject(__selectedOptions.findBy('key', get(l, 'key')))) :
          __selectedOptions.pushObjects(leaves.filter(l => !__selectedOptionsKeys.includes(get(l, 'key'))));
      } else {
        !newVal ?
          __selectedOptions.removeObject(__selectedOptions.findBy('key', nodeKey)) :
          __selectedOptions.pushObject(nodeOrLeaf);
      }

      set(this, '__selectedOptions', __selectedOptions);
      this.onTreeSelectionChange(__selectedOptions);
    }
  }
});
<|endoftext|>


<commit_before>/* jshint expr: true */
import Ember from 'ember';
import layout from '../templates/components/power-select-tree';
const { get, set, computed, A, Component } = Ember;

export default Component.extend({
  layout,
  currentOptions: computed('treeOptions.[]'/*, 'selectedOptions.[]'*/, function() {
    // TODO check selected items
    // TODO if all leaf of a tree are selected check the parent node
    const treeOptions = get(this, 'treeOptions');
    // const selectedOptions = A(get(this, 'selectedOptions'));
    return treeOptions
      .map(o => this._collapsableOption(o/*, selectedOptions*/))
      .map(o => this._buildPath(o));
  }),

  selectedOptionsWithPath: computed('selectedOptions', function() {
    return get(this, 'selectedOptions').map(o => this._buildPath(o));
  }),

  // old code
  // init() {
  //   this._super(...arguments);
  //   set(this, 'currentOptions', get(this, 'treeOptions').map(o => this._collapsableOption(o)));
  //   // TODO if all leaf of a tree are selected check the parent node
  // }
  // TODO: property that groups selectedOptions by path

  _buildPath(node, currPath = []) {
    if (!get(node, 'nodeName')) {
      return set(node, 'path', currPath.join(' > '));
    }

    currPath.push(node.nodeName);
    get(node, 'options').forEach(o => {
      this._buildPath(o, currPath);
    });
    currPath = [];
    return node;
  },

  _collapsableOption(opt/*, selectedOptions = A()*/) {
    const isSelectable = get(opt, 'isSelectable');
    const isChecked = get(opt, 'isChecked')/* || selectedOptions.isAny('key', get(opt, 'key'))*/;
    const groupName = get(opt, 'groupName');
    const options = get(opt, 'options') || [];
    const isCollapsed = get(opt, 'isCollapsed') || true;
    if (groupName) {
      return {
        isSelectable,
        isCollapsed,
        isChecked,
        nodeName: groupName,
        options: options.map(o => this._collapsableOption(o/*, selectedOptions*/))
      };
    }

    set(opt, 'isSelectable', true);
    return opt;
  },

  _getLeaves(root, leaves = A()) {
    get(root, 'options').forEach(
      o => !o.nodeName ? leaves.pushObject(o) : this._getLeaves(o, leaves)
    );
    return leaves;
  },

  _traverseTree(root, func) {
    func(root);
    const options = A(get(root, 'options'));
    if (options.length) {
      options.forEach(o => this._traverseTree(o, func));
    }
  },

  actions: {
    onToggleGroup(nodeOrLeaf) {
      const selectedOptions = A(get(this, 'selectedOptions'));
      if (nodeOrLeaf.nodeName) {
        return set(nodeOrLeaf, 'isCollapsed', !get(nodeOrLeaf, 'isCollapsed'));
      }

      const isLeafChecked = get(nodeOrLeaf, 'isChecked');
      if (isLeafChecked) {
        selectedOptions.removeObject(nodeOrLeaf);
      } else {
        selectedOptions.pushObject(nodeOrLeaf);
      }
      set(nodeOrLeaf, 'isChecked', !isLeafChecked);
      set(this, 'selectedOptions', selectedOptions);
    },
    handleChecked(nodeOrLeaf) {
      const newVal = !get(nodeOrLeaf, 'isChecked');
      const setChecked = node => set(node, 'isChecked', newVal);
      const selectedOptions = A(get(this, 'selectedOptions'));
      this._traverseTree(nodeOrLeaf, setChecked);
      if (nodeOrLeaf.nodeName) {
        const leaves = this._getLeaves(nodeOrLeaf);
        !newVal ?
          selectedOptions.removeObjects(leaves) :
          selectedOptions.pushObjects(leaves);
      } else {
        !newVal ?
          selectedOptions.removeObject(nodeOrLeaf) :
          selectedOptions.pushObject(nodeOrLeaf);
      }
      set(this, 'selectedOptions', selectedOptions);
    }
  }
});
<commit_msg>FIX: minor fix for buildPath<commit_after>/* jshint expr: true */
import Ember from 'ember';
import layout from '../templates/components/power-select-tree';
const { get, set, computed, A, Component } = Ember;

export default Component.extend({
  layout,
  currentOptions: computed('treeOptions.[]'/*, 'selectedOptions.[]'*/, function() {
    // TODO check selected items
    // TODO if all leaf of a tree are selected check the parent node
    const treeOptions = get(this, 'treeOptions');
    // const selectedOptions = A(get(this, 'selectedOptions'));
    return treeOptions
      .map(o => this._collapsableOption(o/*, selectedOptions*/))
      .map(o => this._buildPath(o));
  }),

  selectedOptionsWithPath: computed('selectedOptions.[]', function() {
    return A(get(this, 'selectedOptions')).map(o => this._buildPath(o));
  }),

  // old code
  // init() {
  //   this._super(...arguments);
  //   set(this, 'currentOptions', get(this, 'treeOptions').map(o => this._collapsableOption(o)));
  //   // TODO if all leaf of a tree are selected check the parent node
  // }
  // TODO: property that groups selectedOptions by path

  _buildPath(node, currPath = []) {
    if (!get(node, 'nodeName')) {
      set(node, 'path', currPath.join(' > '));
    } else {
      currPath.push(node.nodeName);
      get(node, 'options').forEach(o => {
        this._buildPath(o, currPath);
      });
      currPath = [];
    }

    return node;
  },

  _collapsableOption(opt/*, selectedOptions = A()*/) {
    const isSelectable = get(opt, 'isSelectable');
    const isChecked = get(opt, 'isChecked')/* || selectedOptions.isAny('key', get(opt, 'key'))*/;
    const groupName = get(opt, 'groupName');
    const options = get(opt, 'options') || [];
    const isCollapsed = get(opt, 'isCollapsed') || true;
    if (groupName) {
      return {
        isSelectable,
        isCollapsed,
        isChecked,
        nodeName: groupName,
        options: options.map(o => this._collapsableOption(o/*, selectedOptions*/))
      };
    }

    set(opt, 'isSelectable', true);
    return opt;
  },

  _getLeaves(root, leaves = A()) {
    get(root, 'options').forEach(
      o => !o.nodeName ? leaves.pushObject(o) : this._getLeaves(o, leaves)
    );
    return leaves;
  },

  _traverseTree(root, func) {
    func(root);
    const options = A(get(root, 'options'));
    if (options.length) {
      options.forEach(o => this._traverseTree(o, func));
    }
  },

  actions: {
    onToggleGroup(nodeOrLeaf) {
      const selectedOptions = A(get(this, 'selectedOptions'));
      if (nodeOrLeaf.nodeName) {
        return set(nodeOrLeaf, 'isCollapsed', !get(nodeOrLeaf, 'isCollapsed'));
      }

      const isLeafChecked = get(nodeOrLeaf, 'isChecked');
      if (isLeafChecked) {
        selectedOptions.removeObject(nodeOrLeaf);
      } else {
        selectedOptions.pushObject(nodeOrLeaf);
      }
      set(nodeOrLeaf, 'isChecked', !isLeafChecked);
      set(this, 'selectedOptions', selectedOptions);
    },
    handleChecked(nodeOrLeaf) {
      const newVal = !get(nodeOrLeaf, 'isChecked');
      const setChecked = node => set(node, 'isChecked', newVal);
      const selectedOptions = A(get(this, 'selectedOptions'));
      this._traverseTree(nodeOrLeaf, setChecked);
      if (nodeOrLeaf.nodeName) {
        const leaves = this._getLeaves(nodeOrLeaf);
        !newVal ?
          selectedOptions.removeObjects(leaves) :
          selectedOptions.pushObjects(leaves);
      } else {
        !newVal ?
          selectedOptions.removeObject(nodeOrLeaf) :
          selectedOptions.pushObject(nodeOrLeaf);
      }
      set(this, 'selectedOptions', selectedOptions);
    }
  }
});
<|endoftext|>