<commit_before>(function() {

  // Space optimisations
  var doc = document;
  var elem = doc.querySelector.bind(doc);
  var create = doc.createElement.bind(doc);

  // Run callback when DOM is ready
  function DOMReady(fn) {

    // Run now if DOM has already loaded as we're loading async
    if(['interactive', 'complete'].indexOf(doc.readyState) >= 0) {
      fn();

    // Otherwise wait for DOM
    } else {
      doc.addEventListener('DOMContentLoaded', fn);
    }
  }

  // Feature tester
  function FeatureTester(tests) {
    var self = this;

    self.tests = tests;

    self.test = function(features) {
      if(!features || !features.length) {
        return false;
      }
      return features.every(function(feature) {
        return self.tests[feature];
      });
    }
  }

  // Init once, don't re-detect features each time
  var supports = new FeatureTester({
    localStorage: (function() {
      try {
        localStorage.setItem('test', 'test');
        localStorage.removeItem('test');
        return true;
      } catch (e) {
        return false;
      }
    })(),
    inlineSVG: (function() {
      var div = create('div');
      div.innerHTML = '<svg/>';
      return (
        typeof SVGRect != 'undefined'
        && div.firstChild
        && div.firstChild.namespaceURI
      ) == 'http://www.w3.org/2000/svg';
    })(),
    querySelector: typeof doc.querySelector === 'function',
    classList: (function() {
      var div = create('div');
      div.innerHTML = '<svg/>';
      return 'classList' in div.firstChild;
    })(),
  });

  // Favourite nodes
  var favouriteNodes = {

    // Key used in localStorage
    storageKey: 'heartedNodes',

    // Url to heart SVG
    heartPath: '/assets/heart.svg',

    // Class added to heart SVG element when active
    activeClass: 'hearted',

    // Gets current node hash
    getCurrentNode: function() {
      var node = /^\/node\/([a-zA-Z0-9]+)/.exec(window.location.pathname);
      return node ? node[1] : node;
    },

    // Gets current node title
    getCurrentNodeTitle: function() {
      return elem('h2.node-title .name').innerText;
    },

    // Gets hearted nodes
    getHeartedNodes: function() {
      return JSON.parse(localStorage.getItem(favouriteNodes.storageKey)) || {};
    },

    // Saves hearted nodes
    saveHeartedNodes: function(heartedNodes) {
      return localStorage.setItem(favouriteNodes.storageKey, JSON.stringify(heartedNodes));
    },

    // Checks if node is hearted
    isHearted: function(node) {
      return typeof favouriteNodes.getHeartedNodes()[node] !== 'undefined';
    },

    // Heart node
    heart: function(node) {
      var heartedNodes = favouriteNodes.getHeartedNodes();
      heartedNodes[node] = favouriteNodes.getCurrentNodeTitle();
      return favouriteNodes.saveHeartedNodes(heartedNodes);
    },

    // Unheart node
    unHeart: function(node) {
      var heartedNodes = favouriteNodes.getHeartedNodes();
      delete heartedNodes[node];
      return favouriteNodes.saveHeartedNodes(heartedNodes);
    },

    // Load SVG, run callback when loaded
    loadSVG: function(cb) {

      // Get heart SVG
      var xhr = new XMLHttpRequest();
      xhr.open('GET', favouriteNodes.heartPath);
      xhr.addEventListener('load', function() {

        // Create heart SVG elem
        var div = create('div');
        div.innerHTML = xhr.responseText;
        var heartEl = div.firstChild;

        // Show heart as active if we've already hearted this node
        var node = favouriteNodes.getCurrentNode();
        if(favouriteNodes.isHearted(node)) {
          heartEl.classList.add(favouriteNodes.activeClass);
        }

        // Add click handler
        heartEl.addEventListener('click', function() {

          // Heart/unheart node
          var node = favouriteNodes.getCurrentNode();
          if(favouriteNodes.isHearted(node)) {
            heartEl.classList.remove(favouriteNodes.activeClass);
            favouriteNodes.unHeart(node);
          } else {
            heartEl.classList.add(favouriteNodes.activeClass);
            favouriteNodes.heart(node);
          }
        });

        // Run callback
        cb(heartEl);
      });
      xhr.send();
    },

    // Initiate node favouriting
    init: function() {

      // Start loading heart SVG before DOM
      favouriteNodes.loadSVG(function(heartEl) {

        // Then inject into DOM when it's ready
        DOMReady(function() {
          var titleEl = elem('h2.node-title');
          if(titleEl) {
            titleEl.insertBefore(heartEl, titleEl.firstChild);
          }
        });
      });

      // Inject elems into DOM
      DOMReady(function() {
        var headerHeight = elem('.title').offsetHeight;
        var headerBoxShadow = 3;

        // Menu button
        var menuButton = create('div');
        menuButton.classList.add('menu-button');
        menuButton.style.height = headerHeight + 'px';
        elem('header .wrapper').appendChild(menuButton);

        // Menu
        var menu = create('div');
        menu.classList.add('menu');
        menu.style.top = (headerHeight + headerBoxShadow) + 'px';
        menu.style.height = 'calc(100% - ' + (headerHeight + headerBoxShadow) + 'px)';
        document.body.appendChild(menu);
      });

      // If current node is hearted
      var node = favouriteNodes.getCurrentNode();
      if(favouriteNodes.isHearted(node)) {

        // Heart it again so we get the new name if it's updated
        favouriteNodes.heart(node);
      }
    }
  };

  // Init favourite nodes
  if(supports.test(['localStorage', 'inlineSVG', 'querySelector', 'classList'])) {
    favouriteNodes.init();
  }

  // Add ios class to body on iOS devices
  if(supports.test(['classList'])) {
    DOMReady(function() {
      if(
        /iPad|iPhone|iPod/.test(navigator.userAgent)
        && !window.MSStream
        && doc.body.classList
      ) {
        doc.body.classList.add('ios');
      }
    });
  }

})();
<commit_msg>Populate hearted nodes list<commit_after>(function() {

  // Space optimisations
  var doc = document;
  var elem = doc.querySelector.bind(doc);
  var create = doc.createElement.bind(doc);

  // Run callback when DOM is ready
  function DOMReady(fn) {

    // Run now if DOM has already loaded as we're loading async
    if(['interactive', 'complete'].indexOf(doc.readyState) >= 0) {
      fn();

    // Otherwise wait for DOM
    } else {
      doc.addEventListener('DOMContentLoaded', fn);
    }
  }

  // Feature tester
  function FeatureTester(tests) {
    var self = this;

    self.tests = tests;

    self.test = function(features) {
      if(!features || !features.length) {
        return false;
      }
      return features.every(function(feature) {
        return self.tests[feature];
      });
    }
  }

  // Init once, don't re-detect features each time
  var supports = new FeatureTester({
    localStorage: (function() {
      try {
        localStorage.setItem('test', 'test');
        localStorage.removeItem('test');
        return true;
      } catch (e) {
        return false;
      }
    })(),
    inlineSVG: (function() {
      var div = create('div');
      div.innerHTML = '<svg/>';
      return (
        typeof SVGRect != 'undefined'
        && div.firstChild
        && div.firstChild.namespaceURI
      ) == 'http://www.w3.org/2000/svg';
    })(),
    querySelector: typeof doc.querySelector === 'function',
    classList: (function() {
      var div = create('div');
      div.innerHTML = '<svg/>';
      return 'classList' in div.firstChild;
    })(),
  });

  // Favourite nodes
  var favouriteNodes = {

    // Key used in localStorage
    storageKey: 'heartedNodes',

    // Url to heart SVG
    heartPath: '/assets/heart.svg',

    // Class added to heart SVG element when active
    activeClass: 'hearted',

    // Gets current node hash
    getCurrentNode: function() {
      var node = /^\/node\/([a-zA-Z0-9]+)/.exec(window.location.pathname);
      return node ? node[1] : node;
    },

    // Gets current node title
    getCurrentNodeTitle: function() {
      return elem('h2.node-title .name').innerText;
    },

    // Gets hearted nodes
    getHeartedNodes: function() {
      return JSON.parse(localStorage.getItem(favouriteNodes.storageKey)) || {};
    },

    // Saves hearted nodes
    saveHeartedNodes: function(heartedNodes) {
      return localStorage.setItem(favouriteNodes.storageKey, JSON.stringify(heartedNodes));
    },

    // Checks if node is hearted
    isHearted: function(node) {
      return typeof favouriteNodes.getHeartedNodes()[node] !== 'undefined';
    },

    // Heart node
    heart: function(node) {
      var heartedNodes = favouriteNodes.getHeartedNodes();
      heartedNodes[node] = favouriteNodes.getCurrentNodeTitle();
      return favouriteNodes.saveHeartedNodes(heartedNodes);
    },

    // Unheart node
    unHeart: function(node) {
      var heartedNodes = favouriteNodes.getHeartedNodes();
      delete heartedNodes[node];
      return favouriteNodes.saveHeartedNodes(heartedNodes);
    },

    // Get list of hearted nodes
    updateHeartedNodesList: function() {
      var menu = elem('.menu');
      if(!menu) {
        return false;
      }
      var list = '
';
      var heartedNodes = favouriteNodes.getHeartedNodes();
      Object.keys(heartedNodes).forEach(function(node) {
        list += '
' + heartedNodes[node] + '
';
      });
      list += '
';
      return menu.innerHTML = list;
    },

    // Load SVG, run callback when loaded
    loadSVG: function(cb) {

      // Get heart SVG
      var xhr = new XMLHttpRequest();
      xhr.open('GET', favouriteNodes.heartPath);
      xhr.addEventListener('load', function() {

        // Create heart SVG elem
        var div = create('div');
        div.innerHTML = xhr.responseText;
        var heartEl = div.firstChild;

        // Show heart as active if we've already hearted this node
        var node = favouriteNodes.getCurrentNode();
        if(favouriteNodes.isHearted(node)) {
          heartEl.classList.add(favouriteNodes.activeClass);
        }

        // Add click handler
        heartEl.addEventListener('click', function() {

          // Heart/unheart node
          var node = favouriteNodes.getCurrentNode();
          if(favouriteNodes.isHearted(node)) {
            heartEl.classList.remove(favouriteNodes.activeClass);
            favouriteNodes.unHeart(node);
          } else {
            heartEl.classList.add(favouriteNodes.activeClass);
            favouriteNodes.heart(node);
          }
        });

        // Run callback
        cb(heartEl);
      });
      xhr.send();
    },

    // Initiate node favouriting
    init: function() {

      // Start loading heart SVG before DOM
      favouriteNodes.loadSVG(function(heartEl) {

        // Then inject into DOM when it's ready
        DOMReady(function() {
          var titleEl = elem('h2.node-title');
          if(titleEl) {
            titleEl.insertBefore(heartEl, titleEl.firstChild);
          }
        });
      });

      // Inject elems into DOM
      DOMReady(function() {
        var headerHeight = elem('.title').offsetHeight;
        var headerBoxShadow = 3;

        // Menu button
        var menuButton = create('div');
        menuButton.classList.add('menu-button');
        menuButton.style.height = headerHeight + 'px';
        elem('header .wrapper').appendChild(menuButton);

        // Menu
        var menu = create('div');
        menu.classList.add('menu');
        menu.style.top = (headerHeight + headerBoxShadow) + 'px';
        menu.style.height = 'calc(100% - ' + (headerHeight + headerBoxShadow) + 'px)';
        document.body.appendChild(menu);
        favouriteNodes.updateHeartedNodesList();
      });

      // If current node is hearted
      var node = favouriteNodes.getCurrentNode();
      if(favouriteNodes.isHearted(node)) {

        // Heart it again so we get the new name if it's updated
        favouriteNodes.heart(node);
      }
    }
  };

  // Init favourite nodes
  if(supports.test(['localStorage', 'inlineSVG', 'querySelector', 'classList'])) {
    favouriteNodes.init();
  }

  // Add ios class to body on iOS devices
  if(supports.test(['classList'])) {
    DOMReady(function() {
      if(
        /iPad|iPhone|iPod/.test(navigator.userAgent)
        && !window.MSStream
        && doc.body.classList
      ) {
        doc.body.classList.add('ios');
      }
    });
  }

})();
<|endoftext|>


<commit_before>/*
 * Methods for fetching pasted html before it gets inserted into content
**/

/* Modern event.clipboardData driven approach.
 * Advantage is that it does not have to loose selection or modify dom to catch the data.
 * IE does not support though.
**/
wysihtml5.dom.getPastedHtml = function(event) {
  var html;
  if (event.clipboardData) {
    if (wysihtml5.lang.array(event.clipboardData.types).contains('text/html')) {
      html = event.clipboardData.getData('text/html');
    } else if (wysihtml5.lang.array(event.clipboardData.types).contains('text/plain')) {
      html = wysihtml5.lang.string(event.clipboardData.getData('text/plain')).escapeHTML(true, true);
    }
  }
  return html;
};

/* Older temprorary contenteditable as paste source catcher method for fallbacks */
wysihtml5.dom.getPastedHtmlWithDiv = function (composer, f) {
  var selBookmark = composer.selection.getBookmark(),
      cleanerDiv = document.createElement('DIV'),
      doc = composer.element.ownerDocument;

  cleanerDiv.setAttribute('contenteditable', 'true');
  doc.body.appendChild(cleanerDiv);
  cleanerDiv.focus();

  setTimeout(function () {
    composer.selection.setBookmark(selBookmark);
    f(cleanerDiv.innerHTML);
    cleanerDiv.parentNode.removeChild(cleanerDiv);
  }, 0);
};<commit_msg>Make fallback paste catcher a bit less obtrusive.<commit_after>/*
 * Methods for fetching pasted html before it gets inserted into content
**/

/* Modern event.clipboardData driven approach.
 * Advantage is that it does not have to loose selection or modify dom to catch the data.
 * IE does not support though.
**/
wysihtml5.dom.getPastedHtml = function(event) {
  var html;
  if (event.clipboardData) {
    if (wysihtml5.lang.array(event.clipboardData.types).contains('text/html')) {
      html = event.clipboardData.getData('text/html');
    } else if (wysihtml5.lang.array(event.clipboardData.types).contains('text/plain')) {
      html = wysihtml5.lang.string(event.clipboardData.getData('text/plain')).escapeHTML(true, true);
    }
  }
  return html;
};

/* Older temprorary contenteditable as paste source catcher method for fallbacks */
wysihtml5.dom.getPastedHtmlWithDiv = function (composer, f) {
  var selBookmark = composer.selection.getBookmark(),
      doc = composer.element.ownerDocument,
      cleanerDiv = coc.createElement('DIV');

  cleanerDiv.style.width = "1px";
  cleanerDiv.style.height = "1px";
  cleanerDiv.style.visibility = "hidden";
  cleanerDiv.style.overflow = "hidden";

  cleanerDiv.setAttribute('contenteditable', 'true');
  doc.body.appendChild(cleanerDiv);
  cleanerDiv.focus();

  setTimeout(function () {
    composer.selection.setBookmark(selBookmark);
    f(cleanerDiv.innerHTML);
    cleanerDiv.parentNode.removeChild(cleanerDiv);
  }, 0);
};<|endoftext|>


<commit_before>import React from 'react'
import { Route } from 'react-router'
import { Application, Mobilizations, Mobilization } from '../../app/scripts/containers'
import { TopMenu, MobilizationMenu } from '../../app/scripts/components'

import {
  Login,
  Logout,
  ListMobilizations,
  NewMobilization,
  ShowMobilization,
  EditMobilization,
  MobilizationBasics,
  MobilizationCity,
  MobilizationAnalytics,
  NewBlock,
  FormWidgetFields,
  FormWidgetForm,
  MobilizationFonts,
  RequireLogin
} from '../../app/scripts/pages'

export default function(store) {
  return (
    <Route component={Application}>
      <Route path="/login" component={Login} />
      <Route path="/logout" component={Logout} />
      <Route component={Mobilizations}>
        <Route component={Mobilization} >
          <Route path="/mobilizations/:mobilization_id" components={{main: ShowMobilization}} />
        </Route>
      </Route>
      <Route component={RequireLogin} onEnter={RequireLogin.onEnter(store)}>
        <Route component={Mobilizations}>
          <Route path="/" components={{main: ListMobilizations, topMenu: TopMenu}} />
          <Route path="/mobilizations/new" components={{main: NewMobilization, topMenu: TopMenu}} />
          <Route component={Mobilization} >
            <Route path="/mobilizations/:mobilization_id/edit" components={{main: EditMobilization, sidebar: MobilizationMenu, topMenu: TopMenu}} />
            <Route path="/mobilizations/:mobilization_id/basics" components={{main: MobilizationBasics, sidebar: MobilizationMenu, topMenu: TopMenu}} />
            <Route path="/mobilizations/:mobilization_id/city" components={{main: MobilizationCity, sidebar: MobilizationMenu, topMenu: TopMenu}} />
            <Route path="/mobilizations/:mobilization_id/cityNew" components={{main: MobilizationCity, topMenu: TopMenu}} />
            <Route path="/mobilizations/:mobilization_id/analytics" components={{main: MobilizationAnalytics, sidebar: MobilizationMenu, topMenu: TopMenu}} />
            <Route path="/mobilizations/:mobilization_id/fonts" components={{main: MobilizationFonts, sidebar: MobilizationMenu, topMenu: TopMenu}} />
            <Route path="/mobilizations/:mobilization_id/blocks/new" components={{main: NewBlock, sidebar: MobilizationMenu, topMenu: TopMenu}} />
            <Route path="/mobilizations/:mobilization_id/widgets/:widget_id/fields" components={{main: FormWidgetFields, sidebar: MobilizationMenu, topMenu: TopMenu}} />
            <Route path="/mobilizations/:mobilization_id/widgets/:widget_id/form" components={{main: FormWidgetForm, sidebar: MobilizationMenu, topMenu: TopMenu}} />
          </Route>
        </Route>
      </Route>
    </Route>
  )
}
<commit_msg>Fix routes<commit_after>import React from 'react'
import { Route } from 'react-router'
import { Application, Mobilizations, Mobilization } from '../../app/scripts/containers'
import { TopMenu, MobilizationMenu } from '../../app/scripts/components'

import {
  Login,
  Logout,
  ListMobilizations,
  NewMobilization,
  ShowMobilization,
  EditMobilization,
  MobilizationBasics,
  MobilizationCity,
  MobilizationAnalytics,
  NewBlock,
  FormWidgetFields,
  FormWidgetForm,
  MobilizationFonts,
  RequireLogin
} from '../../app/scripts/pages'

export default function(store) {
  return (
    <Route component={Application}>
      <Route path="/login" component={Login} />
      <Route path="/logout" component={Logout} />
      <Route component={RequireLogin} onEnter={RequireLogin.onEnter(store)}>
        <Route component={Mobilizations}>
          <Route path="/" components={{main: ListMobilizations, topMenu: TopMenu}} />
          <Route path="/mobilizations/new" components={{main: NewMobilization, topMenu: TopMenu}} />
          <Route component={Mobilization} >
            <Route path="/mobilizations/:mobilization_id/edit" components={{main: EditMobilization, sidebar: MobilizationMenu, topMenu: TopMenu}} />
            <Route path="/mobilizations/:mobilization_id/basics" components={{main: MobilizationBasics, sidebar: MobilizationMenu, topMenu: TopMenu}} />
            <Route path="/mobilizations/:mobilization_id/city" components={{main: MobilizationCity, sidebar: MobilizationMenu, topMenu: TopMenu}} />
            <Route path="/mobilizations/:mobilization_id/cityNew" components={{main: MobilizationCity, topMenu: TopMenu}} />
            <Route path="/mobilizations/:mobilization_id/analytics" components={{main: MobilizationAnalytics, sidebar: MobilizationMenu, topMenu: TopMenu}} />
            <Route path="/mobilizations/:mobilization_id/fonts" components={{main: MobilizationFonts, sidebar: MobilizationMenu, topMenu: TopMenu}} />
            <Route path="/mobilizations/:mobilization_id/blocks/new" components={{main: NewBlock, sidebar: MobilizationMenu, topMenu: TopMenu}} />
            <Route path="/mobilizations/:mobilization_id/widgets/:widget_id/fields" components={{main: FormWidgetFields, sidebar: MobilizationMenu, topMenu: TopMenu}} />
            <Route path="/mobilizations/:mobilization_id/widgets/:widget_id/form" components={{main: FormWidgetForm, sidebar: MobilizationMenu, topMenu: TopMenu}} />
          </Route>
        </Route>
      </Route>
      <Route component={Mobilizations}>
        <Route component={Mobilization} >
          <Route path="/mobilizations/:mobilization_id" components={{main: ShowMobilization}} />
        </Route>
      </Route>
    </Route>
  )
}
<|endoftext|>


<commit_before>var http = require('http');
var sys = require('sys');
var url = require('url');
var wsc = require('websocket').client;

var port = 9092;
var spacebrewHost = 'localhost';
var spacebrewPort = 9000;
var clients = {};

// TODO add per-client timeout interval at config time
// TODO handle timeout

function clientHolder(name, connetion) {
    this.name = name;
    this.connection = connection;
}

// TODO handle websocket disconnect

function configureClient(name, value) {

    nameObj = {"name" : [ { "name" : name } ] };

    // TODO add dynamic config not just "value"
    configObj = {"config" : { "name" : name,
                            "description" : "Pass through http client for electric imp",
                            "publish" : { "messages" : [ { "name" : "value", "type": "range", "default" : "0"} ] },
                            "subscribe" : { "messages" : [] }
                            }
                };

    jsonName = JSON.stringify(nameObj);
    sys.puts("jsonName: " + jsonName);

    jsonConfig = JSON.stringify(configObj);
    sys.puts("jsonConfig: " + jsonConfig);

    client = new wsc();
    client.on("connect", function(conn){
        this.connection = conn;
        this.name = name;
        this.initialValue = value;
        sys.puts("Websocket connected\n");

        this.connection.send(jsonName);
        this.connection.send(jsonConfig);

        clients[this.name] = this;

        processMessage(this.name, this.initValue);

        // untested
        this.connection.on("message", function(message) {
            sys.puts("Message: " + this.name + " : received message : " + message + "\n");
        });
    });
    var url = "ws://" + spacebrewHost + ":" + String(spacebrewPort);
    sys.puts("url: " + url);
    client.connect(url);
}

function processMessage(name, value) {
    var targetClient = false;

    if( clients.hasOwnProperty(name) ) {
        targetClient = clients[name];
    }

    if(targetClient == false) {
        sys.puts("ERROR: Can't find client for " + name + "\n");
        return;
    }

    msgObj = { "message" : {
                             "clientName" : name,
                             "name" : "value",      // TODO build this out
                             "type" : "range",
                             "value" : value }
              };
    jsonMsg = JSON.stringify(msgObj)
    //sys.puts(sys.inspect(targetClient));
    targetClient.connection.send(jsonMsg);
}

http.createServer(function (req, res) {

    // TODO figure out why we get a blank request
    sys.puts("request: " + sys.inspect(url.parse(req.url, true).query));
    var vals = url.parse(req.url, true).query;

    sys.puts(vals);
    if(!vals.hasOwnProperty("name")) {
        sys.puts("Detected blank request.");
        res.writeHead(200, {"Content-Type": "text/plain"});
        res.end("OK");
        return;
    }

    var name = vals.name;
    var value = vals.value;

    if( !clients.hasOwnProperty(name) ) {
        configureClient(name, value);
    } else {
        processMessage(name, value);
    }

    res.writeHead(200, {"Content-Type": "text/plain"});
    res.end("OK");

}).listen(port);

<commit_msg>added comment<commit_after>var http = require('http');
var sys = require('sys');
var url = require('url');
var wsc = require('websocket').client;

var port = 9092;
var spacebrewHost = 'localhost';
var spacebrewPort = 9000;
var clients = {};

/*

Node.js server that accepts pure HTTP requests and pipes the requests through websockets.
The server keeps track of different clients and maintains a websocket connection with spacebrew to pass along future messages.
The main driving force behind this is that electric imp only allows HTTP requests in and out (no websockets), but this generally opens up the capabilities of spacebrew to work with pure HTTP clients.

Next steps:
- Accept configuration message from HTTP client.
- Complete the loop and allow responses to be sent to HTTP client
- Check for client timeouts (right now clients are persistent)

HTTP request:

http://localhost:9092/?value=512&name=imp

name = client name
value = sensor value

 */

// TODO add per-client timeout interval at config time
// TODO handle timeout

function clientHolder(name, connetion) {
    this.name = name;
    this.connection = connection;
}

// TODO handle websocket disconnect

function configureClient(name, value) {

    nameObj = {"name" : [ { "name" : name } ] };

    // TODO add dynamic config not just "value"
    configObj = {"config" : { "name" : name,
                            "description" : "Pass through http client for electric imp",
                            "publish" : { "messages" : [ { "name" : "value", "type": "range", "default" : "0"} ] },
                            "subscribe" : { "messages" : [] }
                            }
                };

    jsonName = JSON.stringify(nameObj);
    sys.puts("jsonName: " + jsonName);

    jsonConfig = JSON.stringify(configObj);
    sys.puts("jsonConfig: " + jsonConfig);

    client = new wsc();
    client.on("connect", function(conn){
        this.connection = conn;
        this.name = name;
        this.initialValue = value;
        sys.puts("Websocket connected\n");

        this.connection.send(jsonName);
        this.connection.send(jsonConfig);

        clients[this.name] = this;

        processMessage(this.name, this.initValue);

        // untested
        this.connection.on("message", function(message) {
            sys.puts("Message: " + this.name + " : received message : " + message + "\n");
        });
    });
    var url = "ws://" + spacebrewHost + ":" + String(spacebrewPort);
    sys.puts("url: " + url);
    client.connect(url);
}

function processMessage(name, value) {
    var targetClient = false;

    if( clients.hasOwnProperty(name) ) {
        targetClient = clients[name];
    }

    if(targetClient == false) {
        sys.puts("ERROR: Can't find client for " + name + "\n");
        return;
    }

    msgObj = { "message" : {
                             "clientName" : name,
                             "name" : "value",      // TODO build this out
                             "type" : "range",
                             "value" : value }
              };
    jsonMsg = JSON.stringify(msgObj)
    //sys.puts(sys.inspect(targetClient));
    targetClient.connection.send(jsonMsg);
}

http.createServer(function (req, res) {

    sys.puts("request: " + sys.inspect(url.parse(req.url, true).query));
    var vals = url.parse(req.url, true).query;

    // TODO figure out why we get a blank request
    sys.puts(vals);
    if(!vals.hasOwnProperty("name")) {
        sys.puts("Detected blank request.");
        res.writeHead(200, {"Content-Type": "text/plain"});
        res.end("OK");
        return;
    }

    var name = vals.name;
    var value = vals.value;

    if( !clients.hasOwnProperty(name) ) {
        configureClient(name, value);
    } else {
        processMessage(name, value);
    }

    res.writeHead(200, {"Content-Type": "text/plain"});
    res.end("OK");

}).listen(port);

<|endoftext|>


<commit_before>// enumFromTo(x,y) = [x,x+1,x+2...y]
// only guarantee to work on increasing sequences
const enumFromTo = (frm,to,succ=(x => x+1)) => {
  const arr = []
  for (let i=frm; i<=to; i=succ(i))
    arr.push( i )
  return arr
}

function warn(...args) {
  return console.warn.apply(this, args)
}

function error(...args) {
  return console.error.apply(this, args)
}

// usage: "ignore(a,b,c)" to fool eslint to believe that "a", "b" and "c"
// are somehow being used, it serves as an explicit annotation to say that they actually don't
const ignore = () => undefined

const identity = x => x

const not = x => !x

// "modifyArray(index,f)(xs)" keeps "xs" intact and returns a new array
// whose element on "index" is modified by feeding original value to "f".
// if "index" is out of range, "xs" itself is returned.
const modifyArray = (index, f) => {
  if (typeof index !== 'number')
    console.error('index is not a number')
  if (typeof f !== 'function')
    console.error('modifier is not a function')
  return xs => {
    if (index < 0 || index >= xs.length)
      return xs
    const ys = [...xs]
    const v = ys[index]
    ys[index] = f(v)
    return ys
  }
}

const mkErrorRecorder = () => {
  const errMsgLog = []
  return {
    recordError: msg => errMsgLog.push(msg),
    get: () => errMsgLog,
  }
}

const saturate = (min,max) => v =>
  v < min ? min : (v > max ? max : v)

const shallowObjectEqual = (obj1,obj2) => {
  if (obj1 === obj2)
    return true

  // know: obj1 & obj2 are not strictly equal
  if (typeof obj1 !== typeof obj2 ||
      // NOTE: `typeof null`  returns 'object',
      // we need this extra check to prevent dealing with nulls
      // in following parts.
      // since we've know obj1 !== obj2, having either object being
      // `null` means they are definitely different.
      (obj1 === null || obj2 === null) ||
      /*
         know: obj1 and obj2 are of the same type
       */
      typeof obj1 !== 'object')
    return false

  const keys1 = Object.keys(obj1)
  const keys2 = Object.keys(obj2)
  if (keys1.length !== keys2.length)
    return false
  return keys1.every(key => {
    const val1 = obj1[key]
    const val2 = obj2[key]
    return val1 === val2
  })
}

const precompose = prj => f => (...args) =>
  f(...args.map(prj))

const mergeResults = (...funcs) => (...args) =>
  funcs.map(f => f.call(null,...args)).reduce((acc,x) => ({
    ...acc, ...x}), {})

export {
  enumFromTo,
  ignore,
  identity,
  not,

  warn,
  error,

  modifyArray,
  mkErrorRecorder,

  saturate,

  shallowObjectEqual,
  precompose,
  mergeResults,
}
<commit_msg>adding some utils for Maps<commit_after>// enumFromTo(x,y) = [x,x+1,x+2...y]
// only guarantee to work on increasing sequences
const enumFromTo = (frm,to,succ=(x => x+1)) => {
  const arr = []
  for (let i=frm; i<=to; i=succ(i))
    arr.push( i )
  return arr
}

function warn(...args) {
  return console.warn.apply(this, args)
}

function error(...args) {
  return console.error.apply(this, args)
}

// usage: "ignore(a,b,c)" to fool eslint to believe that "a", "b" and "c"
// are somehow being used, it serves as an explicit annotation to say that they actually don't
const ignore = () => undefined

const identity = x => x

const not = x => !x

// "modifyArray(index,f)(xs)" keeps "xs" intact and returns a new array
// whose element on "index" is modified by feeding original value to "f".
// if "index" is out of range, "xs" itself is returned.
const modifyArray = (index, f) => {
  if (typeof index !== 'number')
    console.error('index is not a number')
  if (typeof f !== 'function')
    console.error('modifier is not a function')
  return xs => {
    if (index < 0 || index >= xs.length)
      return xs
    const ys = [...xs]
    const v = ys[index]
    ys[index] = f(v)
    return ys
  }
}

const mkErrorRecorder = () => {
  const errMsgLog = []
  return {
    recordError: msg => errMsgLog.push(msg),
    get: () => errMsgLog,
  }
}

const saturate = (min,max) => v =>
  v < min ? min : (v > max ? max : v)

const shallowObjectEqual = (obj1,obj2) => {
  if (obj1 === obj2)
    return true

  // know: obj1 & obj2 are not strictly equal
  if (typeof obj1 !== typeof obj2 ||
      // NOTE: `typeof null`  returns 'object',
      // we need this extra check to prevent dealing with nulls
      // in following parts.
      // since we've know obj1 !== obj2, having either object being
      // `null` means they are definitely different.
      (obj1 === null || obj2 === null) ||
      /*
         know: obj1 and obj2 are of the same type
       */
      typeof obj1 !== 'object')
    return false

  const keys1 = Object.keys(obj1)
  const keys2 = Object.keys(obj2)
  if (keys1.length !== keys2.length)
    return false
  return keys1.every(key => {
    const val1 = obj1[key]
    const val2 = obj2[key]
    return val1 === val2
  })
}

const precompose = prj => f => (...args) =>
  f(...args.map(prj))

const mergeResults = (...funcs) => (...args) =>
  funcs.map(f => f.call(null,...args)).reduce((acc,x) => ({
    ...acc, ...x}), {})

// TODO: guess we need some testing

// `deepWrite(map)([k1,k2,k3...])(value)`
// - assigns `value` to `map.get(k1).get(k2).get(k3)...`.
// - new Map objects are created if some key is missing along the path.
// - INVARIANT: keys.length >= 1
const deepWrite = map => keys => value => {
  if (keys.length === 0) {
    console.error(`invariant violation: empty key array`)
    return undefined
  }
  if (keys.length === 1) {
    const [key] = keys
    map.set(key,value)
    return map
  } else {
    const [key, ...ks] = keys
    const subMap = map.has(key) ? map.get(key) : new Map()
    const subMapAfter = deepWrite(subMap)(ks)(value)
    map.set(key,subMapAfter)
    return map
  }
}

const deepLookup = map => keys => {
  if (keys.length === 0) {
    return map
  }

  const [key, ...restKeys] = keys
  return map.has(key) ?
    deepLookup(map.get(key))(restKeys) :
    undefined
}

const deepMapToObject = map => {
  if (map instanceof Map) {
    const obj = {}
    map.forEach((v,k) => {
      obj[k] = deepMapToObject(v)
    })
    return obj
  } else {
    return map
  }
}

export {
  enumFromTo,
  ignore,
  identity,
  not,

  warn,
  error,

  modifyArray,
  mkErrorRecorder,

  saturate,

  shallowObjectEqual,
  precompose,
  mergeResults,

  deepWrite,
  deepLookup,
  deepMapToObject,
}
<|endoftext|>


<commit_before>var util      = require('util');
var webutil   = require('../util/web');
var Tab       = require('../client/tab').Tab;
var id        = require('../client/id').Id.singleton;

var ContactsTab = function ()
{
  Tab.call(this);
};

util.inherits(ContactsTab, Tab);

ContactsTab.prototype.mainMenu = 'wallet';

// /contact is the way it appears in Ripple URIs
ContactsTab.prototype.aliases = ['contact'];

ContactsTab.prototype.generateHtml = function ()
{
  return require('../../jade/tabs/contacts.jade')();
};

ContactsTab.prototype.angular = function (module) {
  var app = this.app;

  module.controller('ContactsCtrl', ['$scope', 'rpId',
    function ($scope, $id)
    {
      if (!$id.loginStatus) return $id.goId();

      $scope.reset_form = function ()
      {
        $scope.contact = {
          name: '',
          address: '',
          dt: ''
        };
        if ($scope.addForm) $scope.addForm.$setPristine();
      };

      $scope.reset_form();

      /**
       * Toggle "add contact" form
       */
      $scope.toggle_form = function ()
      {
        $scope.addform_visible = !$scope.addform_visible;
        $scope.reset_form();

        // Focus on first input
        setImmediate(function() {
          $('#addForm').find('input:first').focus();
        });
      };

      /**
       * Create contact
       */
      $scope.create = function ()
      {
        var contact = {
          name: $scope.contact.name,
          address: $scope.contact.address,
          dt: $scope.contact.dt,
          // Used for animation
          justAdded: true
        };

        // Enable the animation
        $scope.enable_highlight = true;

        // Add an element
        $scope.userBlob.data.contacts.unshift(contact);

        // Hide the form
        $scope.toggle_form();

        // Clear form
        $scope.reset_form();
      };
    }]);

  module.controller('ContactRowCtrl', ['$scope', '$location',
    function ($scope, $location) {
      $scope.editing = false;

      /**
       * Switch to edit mode
       *
       * @param index
       */
      $scope.edit = function (index)
      {
        $scope.editing = true;
        $scope.editname = $scope.entry.name;
        $scope.editaddress = $scope.entry.address;
        $scope.editdt = $scope.entry.dt;
      };

      /**
       * Update contact
       *
       * @param index
       */
      $scope.update = function (index)
      {
        if (!$scope.inlineAddress.editaddress.$error.rpUnique
            && !$scope.inlineAddress.editaddress.$error.rpAddress
            && !$scope.inlineName.editname.$error.rpUnique) {
          // Update blob
          $scope.entry.name = $scope.editname;
          $scope.entry.address = $scope.editaddress;
          $scope.entry.dt = $scope.editdt;
          $scope.editing = false;
        }
      };

      /**
       * Remove contact
       *
       * @param index
       */
      $scope.remove = function (index) {
        // Update blob
        $scope.userBlob.data.contacts.splice(index,1);
      };

      /**
       * Cancel contact edit
       *
       * @param index
       */
      $scope.cancel = function (index)
      {
        $scope.editing = false;
      };

      $scope.send = function (index)
      {
        $location.path('/send');
        $location.search({to: $scope.entry.name});
      };
    }]);
};

module.exports = ContactsTab;
<commit_msg>Contacts tab: Send button url should also include dt if specified<commit_after>var util      = require('util');
var webutil   = require('../util/web');
var Tab       = require('../client/tab').Tab;
var id        = require('../client/id').Id.singleton;

var ContactsTab = function ()
{
  Tab.call(this);
};

util.inherits(ContactsTab, Tab);

ContactsTab.prototype.mainMenu = 'wallet';

// /contact is the way it appears in Ripple URIs
ContactsTab.prototype.aliases = ['contact'];

ContactsTab.prototype.generateHtml = function ()
{
  return require('../../jade/tabs/contacts.jade')();
};

ContactsTab.prototype.angular = function (module) {
  var app = this.app;

  module.controller('ContactsCtrl', ['$scope', 'rpId',
    function ($scope, $id)
    {
      if (!$id.loginStatus) return $id.goId();

      $scope.reset_form = function ()
      {
        $scope.contact = {
          name: '',
          address: '',
          dt: ''
        };
        if ($scope.addForm) $scope.addForm.$setPristine();
      };

      $scope.reset_form();

      /**
       * Toggle "add contact" form
       */
      $scope.toggle_form = function ()
      {
        $scope.addform_visible = !$scope.addform_visible;
        $scope.reset_form();

        // Focus on first input
        setImmediate(function() {
          $('#addForm').find('input:first').focus();
        });
      };

      /**
       * Create contact
       */
      $scope.create = function ()
      {
        var contact = {
          name: $scope.contact.name,
          address: $scope.contact.address,
          dt: $scope.contact.dt,
          // Used for animation
          justAdded: true
        };

        // Enable the animation
        $scope.enable_highlight = true;

        // Add an element
        $scope.userBlob.data.contacts.unshift(contact);

        // Hide the form
        $scope.toggle_form();

        // Clear form
        $scope.reset_form();
      };
    }]);

  module.controller('ContactRowCtrl', ['$scope', '$location',
    function ($scope, $location) {
      $scope.editing = false;

      /**
       * Switch to edit mode
       *
       * @param index
       */
      $scope.edit = function (index)
      {
        $scope.editing = true;
        $scope.editname = $scope.entry.name;
        $scope.editaddress = $scope.entry.address;
        $scope.editdt = $scope.entry.dt;
      };

      /**
       * Update contact
       *
       * @param index
       */
      $scope.update = function (index)
      {
        if (!$scope.inlineAddress.editaddress.$error.rpUnique
            && !$scope.inlineAddress.editaddress.$error.rpAddress
            && !$scope.inlineName.editname.$error.rpUnique) {
          // Update blob
          $scope.entry.name = $scope.editname;
          $scope.entry.address = $scope.editaddress;
          $scope.entry.dt = $scope.editdt;
          $scope.editing = false;
        }
      };

      /**
       * Remove contact
       *
       * @param index
       */
      $scope.remove = function (index) {
        // Update blob
        $scope.userBlob.data.contacts.splice(index,1);
      };

      /**
       * Cancel contact edit
       *
       * @param index
       */
      $scope.cancel = function (index)
      {
        $scope.editing = false;
      };

      $scope.send = function (index)
      {
        var search = {to: $scope.entry.name};

        if ($scope.entry.dt) {
          search.dt = $scope.entry.dt;
        }

        $location.path('/send');
        $location.search(search);
      };
    }]);
};

module.exports = ContactsTab;
<|endoftext|>


<commit_before>describe("About Arrays", function() {

  //We shall contemplate truth by testing reality, via spec expectations.
  it("should create arrays", function() {
    var emptyArray = [];
    expect(typeof(emptyArray)).toBe('object'); //A mistake? - http:javascript.crockford.com/remedial.html
    expect(emptyArray.length).toBe(0);

    var multiTypeArray = [0, 1, "two", function () { return 3; }, {value1: 4, value2: 5}, [6, 7]];
    expect(multiTypeArray[0]).toBe(0);
    expect(multiTypeArray[2]).toBe("two");
    expect(multiTypeArray[3]()).toBe(3);
    expect(multiTypeArray[4].value1).toBe(4);
    expect(multiTypeArray[4]["value2"]).toBe(5);
    expect(multiTypeArray[5][0]).toBe(6);
  });

  it("should understand array literals", function () {
    var array = [];
    expect(array).toEqual([]);

    array[0] = 1;
    expect(array).toEqual([1]);

    array[1] = 2;
    expect(array).toEqual([1, 2]);

    array.push(3);
    expect(array).toEqual([1,2,3]);
  });

  it("should understand array length", function () {
    var fourNumberArray = [1, 2, 3, 4];

    expect(fourNumberArray.length).toBe(4);
    fourNumberArray.push(5, 6);
    expect(fourNumberArray.length).toBe(6);

    var tenEmptyElementArray = new Array(10);
    expect(tenEmptyElementArray.length).toBe(10);

    tenEmptyElementArray.length = 5;
    expect(tenEmptyElementArray.length).toBe(5);
  });

  it("should slice arrays", function () {
    var array = ["peanut", "butter", "and", "jelly"];

    expect(array.slice(0, 1)).toEqual(["peanut"]);
    expect(array.slice(0, 2)).toEqual(["peanut", "butter"]);
    expect(array.slice(2, 2)).toEqual([]);
    expect(array.slice(2, 20)).toEqual(["and", "jelly"]);
    expect(array.slice(3, 0)).toEqual([]);
    expect(array.slice(3, 100)).toEqual(["jelly"]);
    expect(array.slice(5, 1)).toEqual([]);
  });

  it("should know array references", function () {
    var array = [ "zero", "one", "two", "three", "four", "five" ];

    function passedByReference(refArray) {
      refArray[1] = "changed in function";
    }
    passedByReference(array);
    expect(array[1]).toBe("changed in function");

    var assignedArray = array;
    assignedArray[5] = "changed in assignedArray";
    expect(array[5]).toBe("changed in assignedArray");

    var copyOfArray = array.slice();
    copyOfArray[3] = "changed in copyOfArray";
    expect(array[3]).toBe("three");
  });

  it("should push and pop", function () {
    var array = [1, 2];
    array.push(3);

    expect(array).toEqual(FILL_ME_IN);

    var poppedValue = array.pop();
    expect(poppedValue).toBe(FILL_ME_IN);
    expect(array).toEqual(FILL_ME_IN);
  });

  it("should know about shifting arrays", function () {
    var array = [1, 2];

    array.unshift(3);
    expect(array).toEqual(FILL_ME_IN);

    var shiftedValue = array.shift();
    expect(shiftedValue).toEqual(FILL_ME_IN);
    expect(array).toEqual(FILL_ME_IN);
  });
});
<commit_msg>completed push and pop<commit_after>describe("About Arrays", function() {

  //We shall contemplate truth by testing reality, via spec expectations.
  it("should create arrays", function() {
    var emptyArray = [];
    expect(typeof(emptyArray)).toBe('object'); //A mistake? - http:javascript.crockford.com/remedial.html
    expect(emptyArray.length).toBe(0);

    var multiTypeArray = [0, 1, "two", function () { return 3; }, {value1: 4, value2: 5}, [6, 7]];
    expect(multiTypeArray[0]).toBe(0);
    expect(multiTypeArray[2]).toBe("two");
    expect(multiTypeArray[3]()).toBe(3);
    expect(multiTypeArray[4].value1).toBe(4);
    expect(multiTypeArray[4]["value2"]).toBe(5);
    expect(multiTypeArray[5][0]).toBe(6);
  });

  it("should understand array literals", function () {
    var array = [];
    expect(array).toEqual([]);

    array[0] = 1;
    expect(array).toEqual([1]);

    array[1] = 2;
    expect(array).toEqual([1, 2]);

    array.push(3);
    expect(array).toEqual([1,2,3]);
  });

  it("should understand array length", function () {
    var fourNumberArray = [1, 2, 3, 4];

    expect(fourNumberArray.length).toBe(4);
    fourNumberArray.push(5, 6);
    expect(fourNumberArray.length).toBe(6);

    var tenEmptyElementArray = new Array(10);
    expect(tenEmptyElementArray.length).toBe(10);

    tenEmptyElementArray.length = 5;
    expect(tenEmptyElementArray.length).toBe(5);
  });

  it("should slice arrays", function () {
    var array = ["peanut", "butter", "and", "jelly"];

    expect(array.slice(0, 1)).toEqual(["peanut"]);
    expect(array.slice(0, 2)).toEqual(["peanut", "butter"]);
    expect(array.slice(2, 2)).toEqual([]);
    expect(array.slice(2, 20)).toEqual(["and", "jelly"]);
    expect(array.slice(3, 0)).toEqual([]);
    expect(array.slice(3, 100)).toEqual(["jelly"]);
    expect(array.slice(5, 1)).toEqual([]);
  });

  it("should know array references", function () {
    var array = [ "zero", "one", "two", "three", "four", "five" ];

    function passedByReference(refArray) {
      refArray[1] = "changed in function";
    }
    passedByReference(array);
    expect(array[1]).toBe("changed in function");

    var assignedArray = array;
    assignedArray[5] = "changed in assignedArray";
    expect(array[5]).toBe("changed in assignedArray");

    var copyOfArray = array.slice();
    copyOfArray[3] = "changed in copyOfArray";
    expect(array[3]).toBe("three");
  });

  it("should push and pop", function () {
    var array = [1, 2];
    array.push(3);

    expect(array).toEqual([1,2,3]);

    var poppedValue = array.pop();
    expect(poppedValue).toBe(3);
    expect(array).toEqual([1,2]);
  });

  it("should know about shifting arrays", function () {
    var array = [1, 2];

    array.unshift(3);
    expect(array).toEqual(FILL_ME_IN);

    var shiftedValue = array.shift();
    expect(shiftedValue).toEqual(FILL_ME_IN);
    expect(array).toEqual(FILL_ME_IN);
  });
});
<|endoftext|>


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

    let footer = document.querySelector('.footer'),
        welcome = document.querySelector('.welcome'),
        sendButton = document.querySelector('.voice-button'),
        textarea = document.querySelector('.textarea');

    init();
    /***
     * init
     */
    function init() {
        addToHomeScreen();
        connectToSocketIO();
        subscribeServiceWorker();

        var howLaunched = window.location.search.substring(1).split('=')[0];
        if (howLaunched === 'homescreen' || (window.navigator.standalone == true) || (window.matchMedia('(display-mode: standalone)').matches)) {
            welcome.classList.remove('-active');
            toroTimeline.classList.add('-active');
            footer.classList.add('-active');
        }
    }

    /***
     * connectToSocketIO
     */
    function connectToSocketIO() {
        let socket;
            socket = io.connect('https://huge-trigger.herokuapp.com:19713', {
                'path': '/socket.io'
            });

        sendButton.addEventListener('click', function () {
            console.log('blau')
            if (textarea.innerText != '') {
                socket.emit('message1', textarea.innerText);
                textarea.innerText = '';
            }
        });

        socket.on('floatingNotification', function (resp) {
            navigator.serviceWorker.register('./service-worker.js',{ scope: './' });
            let listItemArray = document.querySelectorAll('.update'),
                html = '
' +
                            '
' +
                                '
' + resp.time + '
' +
                                '
' + resp.title +'
' +
                                '
' + resp.description +'
' +
                            '
' +
                        '
' + resp.icon +'' + resp.actionTitle + '' +
                        '
' +
                    '
';

            listItemArray[listItemArray.length - 1].insertAdjacentHTML('beforebegin', html);

            navigator.serviceWorker.ready.then(function(registration) {
                registration.showNotification(resp.title, {
                    body: resp.description,
                    icon: './assets/images/icon192.png',
                    vibrate: [200, 100, 200, 100, 200, 100, 200],
                    tag: 'vibration-sample',
                });
            });
        });

        socket.on('mainCard', (resp) => {
            navigator.serviceWorker.register('./service-worker.js',{ scope: './' });
        });
    }

    /***
     * addToHomeScreen
     */
    function addToHomeScreen() {
        window.addEventListener('beforeinstallprompt', function(e) {
            e.userChoice.then((choiceResult) => {

                console.log(choiceResult.outcome);

                if(choiceResult.outcome == 'dismissed') {
                    console.log('User cancelled home screen install');
                }
                else {
                    console.log('User added to home screen');
                    welcome.classList.remove('-active');
                    toroTimeline.classList.add('-active');
                }
            });
        });
    }

    /***
     * subscribeServiceWorker
     */
    function subscribeServiceWorker() {
        if ('serviceWorker' in navigator) {
            let outputElement = document.getElementById('output');

            window.addEventListener('load', function() {
                navigator.serviceWorker.register('./service-worker.js',{ scope: './' })
                    .then(function(registration) {
                        console.log('ServiceWorker registration successful with scope: ', registration.scope);
                        Notification.requestPermission()
                            .then(function(permission) {
                        });
                    })
                    .catch(function(err) {
                        console.log('ServiceWorker registration failed: ', err);
                    });
                    window.addEventListener('beforeinstallprompt', function(e) {
                        outputElement.textContent = 'beforeinstallprompt Event fired';
                    });
                });
        }
    }
})();

<commit_msg>issue #000 | Add new anonymous page<commit_after>(function () {
    'use strict';

    let footer = document.querySelector('.footer'),
        welcome = document.querySelector('.welcome'),
        sendButton = document.querySelector('.voice-button'),
        textarea = document.querySelector('.textarea');

    init();
    /***
     * init
     */
    function init() {
        addToHomeScreen();
        connectToSocketIO();
        subscribeServiceWorker();

        var howLaunched = window.location.search.substring(1).split('=')[0];
        if (howLaunched === 'homescreen' || (window.navigator.standalone == true) || (window.matchMedia('(display-mode: standalone)').matches)) {
            welcome.classList.remove('-active');
            toroTimeline.classList.add('-active');
            footer.classList.add('-active');
        }
    }

    /***
     * connectToSocketIO
     */
    function connectToSocketIO() {
        let socket;
            socket = io.connect('https://huge-trigger.herokuapp.com:49223', {
                'path': '/socket.io'
            });

        sendButton.addEventListener('click', function () {
            console.log('blau')
            if (textarea.innerText != '') {
                socket.emit('message1', textarea.innerText);
                textarea.innerText = '';
            }
        });

        socket.on('floatingNotification', function (resp) {
            navigator.serviceWorker.register('./service-worker.js',{ scope: './' });
            let listItemArray = document.querySelectorAll('.update'),
                html = '
' +
                            '
' +
                                '
' + resp.time + '
' +
                                '
' + resp.title +'
' +
                                '
' + resp.description +'
' +
                            '
' +
                        '
' + resp.icon +'' + resp.actionTitle + '' +
                        '
' +
                    '
';

            listItemArray[listItemArray.length - 1].insertAdjacentHTML('beforebegin', html);

            navigator.serviceWorker.ready.then(function(registration) {
                registration.showNotification(resp.title, {
                    body: resp.description,
                    icon: './assets/images/icon192.png',
                    vibrate: [200, 100, 200, 100, 200, 100, 200],
                    tag: 'vibration-sample',
                });
            });
        });

        socket.on('mainCard', (resp) => {
            navigator.serviceWorker.register('./service-worker.js',{ scope: './' });
        });
    }

    /***
     * addToHomeScreen
     */
    function addToHomeScreen() {
        window.addEventListener('beforeinstallprompt', function(e) {
            e.userChoice.then((choiceResult) => {

                console.log(choiceResult.outcome);

                if(choiceResult.outcome == 'dismissed') {
                    console.log('User cancelled home screen install');
                }
                else {
                    console.log('User added to home screen');
                    welcome.classList.remove('-active');
                    toroTimeline.classList.add('-active');
                }
            });
        });
    }

    /***
     * subscribeServiceWorker
     */
    function subscribeServiceWorker() {
        if ('serviceWorker' in navigator) {
            let outputElement = document.getElementById('output');

            window.addEventListener('load', function() {
                navigator.serviceWorker.register('./service-worker.js',{ scope: './' })
                    .then(function(registration) {
                        console.log('ServiceWorker registration successful with scope: ', registration.scope);
                        Notification.requestPermission()
                            .then(function(permission) {
                        });
                    })
                    .catch(function(err) {
                        console.log('ServiceWorker registration failed: ', err);
                    });
                    window.addEventListener('beforeinstallprompt', function(e) {
                        outputElement.textContent = 'beforeinstallprompt Event fired';
                    });
                });
        }
    }
})();

<|endoftext|>


<commit_before>describe('distance', function() {
  var $rootScope = null,
      wsStub = {
        search: function(){}
      };

  var cmWS = null;

  beforeEach(function() {
    module('ngCloudMine');
  });

  beforeEach(function() {
    inject(function($injector) {
      window.ws = wsStub;
      $rootScope = $injector.get('$rootScope');
      cmWS = $injector.get('cmWS');
    });
  });

  afterEach(function() {
    if (wsStub.search.restore) {
      wsStub.search.restore();
    }
  });

  describe('query', function() {

    it('requires query, options, and vars', function() {
      var errorResponse = null;

      expect(cmWS.getDistanceCount).to.be.ok;

      sinon.stub(wsStub, 'search', setCloudmineSuccessResponse([{}, {count: 4}]));

      cmWS.getDistanceCount().catch(function(err) {
        errorResponse = err;
      });
      $rootScope.$apply();
      expect(errorResponse).to.equal('Missing query');

      cmWS.getDistanceCount('query').catch(function(err) {
        errorResponse = err;
      });
      $rootScope.$apply();
      expect(errorResponse).to.equal('Missing options');

      cmWS.getDistanceCount('query', {}).catch(function(err) {
        errorResponse = err;
      });
      $rootScope.$apply();
      expect(errorResponse).to.equal('Missing distance');

      cmWS.getDistanceCount('query', {}, .1).catch(function(err) {
        errorResponse = err;
      });
      $rootScope.$apply();
      expect(errorResponse).to.equal('Missing latitude');

      cmWS.getDistanceCount('query', {}, .1, 1.23).catch(function(err) {
        errorResponse = err;
      });
      $rootScope.$apply();
      expect(errorResponse).to.equal('Missing longitude');

      cmWS.getDistanceCount('query', {}, .1, 1.23, 2.34).catch(function(err) {
        errorResponse = err;
      });
      $rootScope.$apply();
      expect(errorResponse).to.equal('Missing distance variable in query');

      cmWS.getDistanceCount('[query, #{distance}mi]', {}, .1, 1.23, 2.34).catch(function(err) {
        errorResponse = err;
      });
      $rootScope.$apply();
      expect(errorResponse).to.equal('Missing latitude variable in query');

      cmWS.getDistanceCount('[query, location near (#{lat})#{distance}mi]', {}, .1, 1.23, 2.34).catch(function(err) {
        errorResponse = err;
      });
      $rootScope.$apply();
      expect(errorResponse).to.equal('Missing longitude variable in query');

    });

    it('gets the count', function() {
      sinon.stub(wsStub, 'search', setCloudmineSuccessResponse([{}, {count: 4}]));

      var results = null;
      cmWS.getDistanceCount('[query, location near (#{long}, #{lat}), #{distance}mi]', {applevel: true}, 0.1, 1.23, 4.56).then(function(data) {
        results = data;
      });
      $rootScope.$apply();

      expect(wsStub.search.callCount).to.equal(1);
      expect(wsStub.search.getCall(0).args[0]).to.equal('[query, location near (4.56, 1.23), 0.1mi]');
      expect(wsStub.search.getCall(0).args[1]).to.deep.equal({
        applevel: true,
        limit: 0,
        count: true
      });
      expect(results).to.equal(4);
    });

    it('does the query', function() {
      expect(cmWS.getDistance).to.be.ok;

      sinon.stub(wsStub, 'search', setCloudmineSuccessResponse([
          {
            biz1: {name: 'biz1'},
            biz2: {name: 'biz2'},
            biz3: {name: 'biz3'},
            biz4: {name: 'biz4'}
          },
          {
            biz1: {geo: {distance: 0.1}},
            biz2: {geo: {distance: 0.2}},
            biz3: {geo: {distance: 0.3}},
            biz4: {geo: {distance: 0.4}}
          }
      ]));

      var results = null;
      cmWS.getDistance(
        '[query, location near (#{long}, #{lat}), #{distance}mi]',
        {applevel: true}, 0.1, 1.23, 4.56
      ).then(function(data) {
        results = data;
      });
      $rootScope.$apply();

      expect(wsStub.search.callCount).to.equal(1);
      expect(wsStub.search.getCall(0).args[0]).to.equal('[query, location near (4.56, 1.23), 0.1mi]');
      expect(wsStub.search.getCall(0).args[1]).to.deep.equal({applevel: true, distance: true});
      expect(results[0]).to.deep.equal({name: 'biz1', distance: 0.1});
      expect(results.biz1).to.deep.equal({name: 'biz1', distance: 0.1});
      expect(results[1]).to.deep.equal({name: 'biz2', distance: 0.2});
      expect(results.biz2).to.deep.equal({name: 'biz2', distance: 0.2});
      expect(results[2]).to.deep.equal({name: 'biz3', distance: 0.3});
      expect(results.biz3).to.deep.equal({name: 'biz3', distance: 0.3});
      expect(results[3]).to.deep.equal({name: 'biz4', distance: 0.4});
      expect(results.biz4).to.deep.equal({name: 'biz4', distance: 0.4});
    });

  });

  describe('object', function() {

    it('creates', function() {
      expect(cmWS.getDistancePager).to.be.ok;

      sinon.stub(wsStub, 'search', setCloudmineSuccessResponse([{}, {count: 6}]));

      var pager = null;
      cmWS.getDistancePager(2, '[query, location near (#{long}, #{lat}), #{distance}mi]', .2, 2.34, 5.67, {applevel: true}).then(function(data) {
        pager = data;
      });
      $rootScope.$apply();

      expect(wsStub.search.callCount).to.equal(1);
      expect(wsStub.search.getCall(0).args[0]).to.equal('[query, location near (5.67, 2.34), 0.2mi]');
      expect(wsStub.search.getCall(0).args[1]).to.deep.equal({
        applevel: true,
        limit: 0,
        count: true
      });

      expect(pager.query).to.equal('[query, location near (5.67, 2.34), 0.2mi]');
      expect(pager.countPerPage).to.equal(2);
      expect(pager.page).to.equal(0);
      expect(pager.total).to.equal(6);
      expect(pager.totalPages).to.equal(3);
    });

  });

});
<commit_msg>Refactor<commit_after>describe('distance', function() {
  var $rootScope = null,
      wsStub = {
        search: function(){}
      };

  var cmWS = null;

  beforeEach(function() {
    module('ngCloudMine');
  });

  beforeEach(function() {
    inject(function($injector) {
      window.ws = wsStub;
      $rootScope = $injector.get('$rootScope');
      cmWS = $injector.get('cmWS');
    });
  });

  afterEach(function() {
    if (wsStub.search.restore) {
      wsStub.search.restore();
    }
  });

  describe('query', function() {

    it('requires query, options, and vars', function() {
      var errorResponse = null;

      expect(cmWS.getDistanceCount).to.be.ok;

      sinon.stub(wsStub, 'search', setCloudmineSuccessResponse([{}, {count: 4}]));

      cmWS.getDistanceCount().catch(function(err) {
        errorResponse = err;
      });
      $rootScope.$apply();
      expect(errorResponse).to.equal('Missing query');

      cmWS.getDistanceCount('query').catch(function(err) {
        errorResponse = err;
      });
      $rootScope.$apply();
      expect(errorResponse).to.equal('Missing options');

      cmWS.getDistanceCount('query', {}).catch(function(err) {
        errorResponse = err;
      });
      $rootScope.$apply();
      expect(errorResponse).to.equal('Missing distance');

      cmWS.getDistanceCount('query', {}, .1).catch(function(err) {
        errorResponse = err;
      });
      $rootScope.$apply();
      expect(errorResponse).to.equal('Missing latitude');

      cmWS.getDistanceCount('query', {}, .1, 1.23).catch(function(err) {
        errorResponse = err;
      });
      $rootScope.$apply();
      expect(errorResponse).to.equal('Missing longitude');

      cmWS.getDistanceCount('query', {}, .1, 1.23, 2.34).catch(function(err) {
        errorResponse = err;
      });
      $rootScope.$apply();
      expect(errorResponse).to.equal('Missing distance variable in query');

      cmWS.getDistanceCount('[query, #{distance}mi]', {}, .1, 1.23, 2.34).catch(function(err) {
        errorResponse = err;
      });
      $rootScope.$apply();
      expect(errorResponse).to.equal('Missing latitude variable in query');

      cmWS.getDistanceCount('[query, location near (#{lat})#{distance}mi]', {}, .1, 1.23, 2.34).catch(function(err) {
        errorResponse = err;
      });
      $rootScope.$apply();
      expect(errorResponse).to.equal('Missing longitude variable in query');

    });

    it('gets the count', function() {
      sinon.stub(wsStub, 'search', setCloudmineSuccessResponse([{}, {count: 4}]));

      var results = null;
      cmWS.getDistanceCount('[query, location near (#{long}, #{lat}), #{distance}mi]', {applevel: true}, 0.1, 1.23, 4.56).then(function(data) {
        results = data;
      });
      $rootScope.$apply();

      expect(wsStub.search.callCount).to.equal(1);
      expect(wsStub.search.getCall(0).args[0]).to.equal('[query, location near (4.56, 1.23), 0.1mi]');
      expect(wsStub.search.getCall(0).args[1]).to.deep.equal({
        applevel: true,
        limit: 0,
        count: true
      });
      expect(results).to.equal(4);
    });

    it('does the query', function() {
      expect(cmWS.getDistance).to.be.ok;

      sinon.stub(wsStub, 'search', setCloudmineSuccessResponse([
        {
          biz1: {name: 'biz1'},
          biz2: {name: 'biz2'},
          biz3: {name: 'biz3'},
          biz4: {name: 'biz4'}
        },
        {
          biz1: {geo: {distance: 0.1}},
          biz2: {geo: {distance: 0.2}},
          biz3: {geo: {distance: 0.3}},
          biz4: {geo: {distance: 0.4}}
        }
      ]));

      var results = null;
      cmWS.getDistance(
        '[query, location near (#{long}, #{lat}), #{distance}mi]',
        {applevel: true}, 0.1, 1.23, 4.56
      ).then(function(data) {
        results = data;
      });
      $rootScope.$apply();

      expect(wsStub.search.callCount).to.equal(1);
      expect(wsStub.search.getCall(0).args[0]).to.equal('[query, location near (4.56, 1.23), 0.1mi]');
      expect(wsStub.search.getCall(0).args[1]).to.deep.equal({applevel: true, distance: true});
      expect(results[0]).to.deep.equal({name: 'biz1', distance: 0.1});
      expect(results.biz1).to.deep.equal({name: 'biz1', distance: 0.1});
      expect(results[1]).to.deep.equal({name: 'biz2', distance: 0.2});
      expect(results.biz2).to.deep.equal({name: 'biz2', distance: 0.2});
      expect(results[2]).to.deep.equal({name: 'biz3', distance: 0.3});
      expect(results.biz3).to.deep.equal({name: 'biz3', distance: 0.3});
      expect(results[3]).to.deep.equal({name: 'biz4', distance: 0.4});
      expect(results.biz4).to.deep.equal({name: 'biz4', distance: 0.4});
    });

  });

  describe('object', function() {

    it('creates', function() {
      expect(cmWS.getDistancePager).to.be.ok;

      sinon.stub(wsStub, 'search', setCloudmineSuccessResponse([{}, {count: 6}]));

      var pager = null;
      cmWS.getDistancePager(2, '[query, location near (#{long}, #{lat}), #{distance}mi]', .2, 2.34, 5.67, {applevel: true}).then(function(data) {
        pager = data;
      });
      $rootScope.$apply();

      expect(wsStub.search.callCount).to.equal(1);
      expect(wsStub.search.getCall(0).args[0]).to.equal('[query, location near (5.67, 2.34), 0.2mi]');
      expect(wsStub.search.getCall(0).args[1]).to.deep.equal({
        applevel: true,
        limit: 0,
        count: true
      });

      expect(pager.query).to.equal('[query, location near (5.67, 2.34), 0.2mi]');
      expect(pager.countPerPage).to.equal(2);
      expect(pager.page).to.equal(0);
      expect(pager.total).to.equal(6);
      expect(pager.totalPages).to.equal(3);
    });

  });

});
<|endoftext|>


<commit_before>/**
 *
 *  Copyright 2016 Netflix, Inc.
 *
 *     Licensed under the Apache License, Version 2.0 (the "License");
 *     you may not use this file except in compliance with the License.
 *     You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *     Unless required by applicable law or agreed to in writing, software
 *     distributed under the License is distributed on an "AS IS" BASIS,
 *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *     See the License for the specific language governing permissions and
 *     limitations under the License.
 *
 */
import _ from 'lodash';

import GlobalConnection from './globalConnection';
import GlobalNode from './globalNode';
import RendererUtils from '../rendererUtils';
import RingCenterLayout from '../layouts/ringCenterLayout';
import TrafficGraph from '../base/trafficGraph';

class GlobalTrafficGraph extends TrafficGraph {
  constructor (name, mainView, parentGraph, graphWidth, graphHeight, Layout = RingCenterLayout) {
    super(name, mainView, parentGraph, graphWidth, graphHeight, GlobalNode, GlobalConnection, Layout);
    this.type = 'global';

    this.maxDimension = Math.min(graphWidth, graphHeight);

    this.linePrecision = 50;
    this.state = {
      nodes: [],
      connections: []
    };
    this.contextDivs = {};

    this.hasPositionData = true;
  }

  setState (state, force) {
    _.each(state.nodes, (node) => {
      const existingNodeIndex = _.findIndex(this.state.nodes, { name: node.name });
      if (existingNodeIndex !== -1) {
        this.state.nodes[existingNodeIndex] = node;
      } else {
        this.layoutValid = false;
        this.state.nodes.push(node);
        if (!this.contextDivs[node.name]) {
          const parentDiv = RendererUtils.getParent();
          if (parentDiv) {
            this.contextDivs[node.name] = document.createElement('div');
            this.contextDivs[node.name].style.position = 'absolute';
            this.contextDivs[node.name].className = `context ${node.name}`;
            parentDiv.appendChild(this.contextDivs[node.name]);
          }
        }
      }
    });

    _.each(state.connections, (newConnection) => {
      const existingConnectionIndex = _.findIndex(this.state.connections, { source: newConnection.source, target: newConnection.target });
      if (existingConnectionIndex !== -1) {
        this.state.connections[existingConnectionIndex] = newConnection;
      } else {
        this.state.connections.push(newConnection);
      }
    });

    // update maxVolume
    // depending on how the data gets fed, we might not have a global max volume.
    // If we do not, calculate it based on all the second level nodes max volume.
    //
    // Just for visual sake, we set the max volume to 150% of the greatest
    // connection volume. This allows for buffer room for failover traffic to be
    // more visually dense.
    let maxVolume = state.maxVolume || 0;
    if (!maxVolume) {
      _.each(this.state.nodes, (node) => {
        maxVolume = Math.max(maxVolume, node.maxVolume || 0);
      });
    }
    this.state.maxVolume = maxVolume * 1.5;

    super.setState(this.state, force);
    this.validateLayout();
  }

  setFilters () {
    // no-op
  }

  handleIntersectedObjectClick () {
    if (this.intersectedObject && this.intersectedObject.graphRenderer === 'global') {
      this.emit('setView', [this.intersectedObject.getName()]);
    }
  }

  handleIntersectedObjectDoubleClick () {
    if (this.intersectedObject && this.intersectedObject.graphRenderer === 'global') {
      this.emit('setView', [this.intersectedObject.getName()]);
    }
  }

  updateLabelScreenDimensions (force) {
    let changed = false;
    const dimensions = {};
    _.each(this.nodes, (node, key) => {
      const labelView = node.getView().nameView ? node.getView().nameView.container : undefined;
      const newDimensions = RendererUtils.toScreenPosition(labelView, 'BL');
      if (newDimensions) {
        const oldDimensions = node.getView().getLabelScreenDimensions();
        if (!_.isEqual(newDimensions, oldDimensions) || force) {
          changed = true;
          node.getView().setLabelScreenDimensions(newDimensions);
          dimensions[key] = newDimensions;
          if (this.contextDivs[key]) {
            this.contextDivs[key].style.width = `${newDimensions.width}px`;
            this.contextDivs[key].style.top = `${newDimensions.y}px`;
            this.contextDivs[key].style.left = `${newDimensions.x}px`;
            this.contextDivs[key].style.height = `${0.65 * newDimensions.width}px`;
          }
        }
      }
    });

    if (changed) {
      this.emit('nodeContextSizeChanged', dimensions);
    }
  }

  setCurrent (current) {
    super.setCurrent(current);
    _.each(this.contextDivs, (div) => {
      div.style.display = current ? 'block' : 'none';
    });
    this.updateLabelScreenDimensions(true);
  }

  highlightObject () {
    // no-op
  }

  update (time) {
    super.update(time);
    this.updateLabelScreenDimensions(false);
  }
}

export default GlobalTrafficGraph;
<commit_msg>Actually remove nodes and connections that are in the updated global graph.<commit_after>/**
 *
 *  Copyright 2016 Netflix, Inc.
 *
 *     Licensed under the Apache License, Version 2.0 (the "License");
 *     you may not use this file except in compliance with the License.
 *     You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *     Unless required by applicable law or agreed to in writing, software
 *     distributed under the License is distributed on an "AS IS" BASIS,
 *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *     See the License for the specific language governing permissions and
 *     limitations under the License.
 *
 */
import _ from 'lodash';

import GlobalConnection from './globalConnection';
import GlobalNode from './globalNode';
import RendererUtils from '../rendererUtils';
import RingCenterLayout from '../layouts/ringCenterLayout';
import TrafficGraph from '../base/trafficGraph';

class GlobalTrafficGraph extends TrafficGraph {
  constructor (name, mainView, parentGraph, graphWidth, graphHeight, Layout = RingCenterLayout) {
    super(name, mainView, parentGraph, graphWidth, graphHeight, GlobalNode, GlobalConnection, Layout);
    this.type = 'global';

    this.maxDimension = Math.min(graphWidth, graphHeight);

    this.linePrecision = 50;
    this.state = {
      nodes: [],
      connections: []
    };
    this.contextDivs = {};

    this.hasPositionData = true;
  }

  validateContextDiv (name) {
    if (!this.contextDivs[name]) {
      const parentDiv = RendererUtils.getParent();
      if (parentDiv) {
        this.contextDivs[name] = document.createElement('div');
        this.contextDivs[name].style.position = 'absolute';
        this.contextDivs[name].className = `context ${name}`;
        parentDiv.appendChild(this.contextDivs[name]);
      }
    }
  }

  removeContextDiv (name) {
    if (this.contextDivs[name]) {
      const parentDiv = RendererUtils.getParent();
      if (parentDiv) {
        parentDiv.removeChild(this.contextDivs[name]);
        this.contextDivs[name] = undefined;
      }
    }
  }

  setState (state, force) {
    // Remove old nodes
    for (let i = this.state.nodes.length - 1; i >= 0; i--) {
      const newNodeIndex = _.findIndex(state.nodes, { name: this.state.nodes[i].name });
      if (newNodeIndex === -1) {
        this.removeContextDiv(this.state.nodes[i].name);
        this.state.nodes.splice(i, 1);
      }
    }

    // Add new nodes and update existing nodes
    _.each(state.nodes, (node) => {
      const existingNodeIndex = _.findIndex(this.state.nodes, { name: node.name });
      if (existingNodeIndex !== -1) {
        // If the node already exists, replace the node
        this.state.nodes[existingNodeIndex] = node;
      } else {
        // Add new node
        this.layoutValid = false;
        this.state.nodes.push(node);
        this.validateContextDiv(node.name);
      }
    });

    // Remove old connections
    for (let i = this.state.connections.length - 1; i >= 0; i--) {
      const newConnectionIndex = _.findIndex(state.connections, { source: this.state.connections[i].source, target: this.state.connections[i].target });
      if (newConnectionIndex === -1) {
        this.state.connections.splice(i, 1);
      }
    }

    // Add new connection and update existing connectiond
    _.each(state.connections, (newConnection) => {
      const existingConnectionIndex = _.findIndex(this.state.connections, { source: newConnection.source, target: newConnection.target });
      if (existingConnectionIndex !== -1) {
        this.state.connections[existingConnectionIndex] = newConnection;
      } else {
        this.state.connections.push(newConnection);
      }
    });

    // update maxVolume
    // depending on how the data gets fed, we might not have a global max volume.
    // If we do not, calculate it based on all the second level nodes max volume.
    //
    // Just for visual sake, we set the max volume to 150% of the greatest
    // connection volume. This allows for buffer room for failover traffic to be
    // more visually dense.
    let maxVolume = state.maxVolume || 0;
    if (!maxVolume) {
      _.each(this.state.nodes, (node) => {
        maxVolume = Math.max(maxVolume, node.maxVolume || 0);
      });
    }
    this.state.maxVolume = maxVolume * 1.5;

    super.setState(this.state, force);
    this.validateLayout();
  }

  setFilters () {
    // no-op
  }

  handleIntersectedObjectClick () {
    if (this.intersectedObject && this.intersectedObject.graphRenderer === 'global') {
      this.emit('setView', [this.intersectedObject.getName()]);
    }
  }

  handleIntersectedObjectDoubleClick () {
    if (this.intersectedObject && this.intersectedObject.graphRenderer === 'global') {
      this.emit('setView', [this.intersectedObject.getName()]);
    }
  }

  updateLabelScreenDimensions (force) {
    let changed = false;
    const dimensions = {};
    _.each(this.nodes, (node, key) => {
      const labelView = node.getView().nameView ? node.getView().nameView.container : undefined;
      const newDimensions = RendererUtils.toScreenPosition(labelView, 'BL');
      if (newDimensions) {
        const oldDimensions = node.getView().getLabelScreenDimensions();
        if (!_.isEqual(newDimensions, oldDimensions) || force) {
          changed = true;
          node.getView().setLabelScreenDimensions(newDimensions);
          dimensions[key] = newDimensions;
          if (this.contextDivs[key]) {
            this.contextDivs[key].style.width = `${newDimensions.width}px`;
            this.contextDivs[key].style.top = `${newDimensions.y}px`;
            this.contextDivs[key].style.left = `${newDimensions.x}px`;
            this.contextDivs[key].style.height = `${0.65 * newDimensions.width}px`;
          }
        }
      }
    });

    if (changed) {
      this.emit('nodeContextSizeChanged', dimensions);
    }
  }

  setCurrent (current) {
    super.setCurrent(current);
    _.each(this.contextDivs, (div) => {
      div.style.display = current ? 'block' : 'none';
    });
    this.updateLabelScreenDimensions(true);
  }

  highlightObject () {
    // no-op
  }

  update (time) {
    super.update(time);
    this.updateLabelScreenDimensions(false);
  }
}

export default GlobalTrafficGraph;
<|endoftext|>