<commit_before>import { isDesktop, AUTOCOMPLETE_DEFAULTS } from 'lib/shared'
import Turbolinks from 'turbolinks'
import 'tipsy-1a'
import 'devbridge-autocomplete'
import 'sticky-kit/dist/sticky-kit.js'
import { VisTreemap, VisSlider, VisBubbles, VisBubbleLegend } from 'lib/visualizations'
import { getBudgetLevelData } from './getBudgetLevelData.js'
// flight components
import './budgetLineBreadcrumb.js'
import './featuredBudgetLine.js'
import './intelligenceBudgetLines.js'
import './intelligenceBudgetLinesMeans.js'
import './visLine.js'

$(document).on('turbolinks:load ajax:complete ajaxSuccess', function() {
  if($('#expense-treemap').length && !$('#expense-treemap svg').length){
    let expenseTreemap = new VisTreemap('#expense-treemap', 'big', true);
    expenseTreemap.render($('#expense-treemap').data('functional-url'));

    window.addEventListener("resize", _.debounce(function () {
      expenseTreemap.render($('#expense-treemap').data('functional-url'));
    }, 250));
  }

  if($('#treemap').length && !$('#treemap svg').length){
    let expenseTreemap = new VisTreemap('#treemap', 'big', true);
    expenseTreemap.render($('#treemap').data('url'));

    window.addEventListener("resize", _.debounce(function () {
      expenseTreemap.render($('#treemap').data('url'));
    }, 250));
  }
})

$(document).on('turbolinks:load', function() {

  if(!isDesktop()) {
    $('.open_line_browser').hide();
  }

  if($('.vis-bubbles-expense').length && $('.vis-bubbles-income').length && !$('.vis-bubbles-expense svg').length && !$('.vis-bubbles-income svg').length) {
    var getBubbleData = new getBudgetLevelData();

    getBubbleData.getData(function() {
      new VisSlider('.timeline', window.budgetLevels);

      var visBubblesExpense = new VisBubbles('.vis-bubbles-expense', 'expense', window.budgetLevels);
      visBubblesExpense.render();

      var visBubblesIncome = new VisBubbles('.vis-bubbles-income', 'income', window.budgetLevels);
      visBubblesIncome.render();

      window.addEventListener("resize", _.debounce(function () {
        new VisSlider('.timeline', window.budgetLevels);

        visBubblesExpense.resize();
        visBubblesIncome.resize();

        if (window.innerWidth >= 1024) {
          new VisBubbleLegend('.bubble_legend');
        } else {
          $('.bubble_legend svg').remove();
        }
      }, 250));

      $(document).on('visSlider:yearChanged', function(e, year) {
        visBubblesIncome.update(year);
        visBubblesExpense.update(year);
      });
    });

    if (window.innerWidth >= 1024) {
      new VisBubbleLegend('.bubble_legend');
    }
  }

  var $autocomplete = $('[data-autocomplete]');

  var searchOptions = {
    serviceUrl: $autocomplete.data('autocomplete'),
    onSelect: function(suggestion) {
      Turbolinks.visit(suggestion.data.url);
    },
    groupBy: 'category'
  };

  $autocomplete.devbridgeAutocomplete($.extend({}, AUTOCOMPLETE_DEFAULTS, searchOptions));

  $(".stick_ip").stick_in_parent()
    .on("sticky_kit:stick", function() {
      if($('.bread_links span').length)
        return;
      var title = $('h1').text();
      var breadLinksHtml = $('.bread_links').html();
      $('.bread_links').html(breadLinksHtml + ' ' + title + '');
    })
    .on("sticky_kit:unstick", function() {
      var sep = ' » ';
      var breadLinksHtml = $('.bread_links').html();
      var arr = breadLinksHtml.split(sep);
      arr.pop();
      $('.bread_links').html(arr.join(sep) + sep);
    });

  $('.bread_hover').hover(function() {
    $('.bread_links a').attr('aria-expanded', true);
    $('.line_browser').velocity("fadeIn", { duration: 50 });
  }, function() {
    $('.bread_links a').attr('aria-expanded', false);
    $('.line_browser').velocity("fadeOut", { duration: 50 });
  });

  $('.open_line_browser').click(function(e) {
    e.preventDefault();
    e.stopPropagation();
    $('.line_browser').velocity("fadeIn", { duration: 250 });
  });

  $('.close_line_browser').click(function(e) {
    e.preventDefault();
    e.stopPropagation();
    $('.line_browser').velocity("fadeOut", { duration: 150 });
  });

  $(window).click(function(){
    $('.line_browser').velocity("fadeOut", { duration: 150 });
  });

  $('.tooltiped-budget-lines').tipsy({
    gravity: 'se',
    trigger: 'manual',
    html: true,
    className: 'tipsy-lines'
  });

  $('.tooltiped-budget-lines').on('click', function() {
    $(this).tipsy("show");
  })

  $('.tooltiped').tipsy({
    gravity: 's',
    trigger: 'hover',
    html: true
  });
});
<commit_msg>fix tipsy on treemap<commit_after>import { isDesktop, AUTOCOMPLETE_DEFAULTS } from 'lib/shared'
import Turbolinks from 'turbolinks'
import 'tipsy-1a'
import 'devbridge-autocomplete'
import 'sticky-kit/dist/sticky-kit.js'
import { VisTreemap, VisSlider, VisBubbles, VisBubbleLegend } from 'lib/visualizations'
import { getBudgetLevelData } from './getBudgetLevelData.js'
// flight components
import './budgetLineBreadcrumb.js'
import './featuredBudgetLine.js'
import './intelligenceBudgetLines.js'
import './intelligenceBudgetLinesMeans.js'
import './visLine.js'

$(document).on('turbolinks:load', function() {

  if(!isDesktop()) {
    $('.open_line_browser').hide();
  }

  if($('#expense-treemap').length && !$('#expense-treemap svg').length){
    let expenseTreemap = new VisTreemap('#expense-treemap', 'big', true);
    expenseTreemap.render($('#expense-treemap').data('functional-url'));

    window.addEventListener("resize", _.debounce(function () {
      expenseTreemap.render($('#expense-treemap').data('functional-url'));
    }, 250));
  }

  if($('#treemap').length && !$('#treemap svg').length){
    let expenseTreemap = new VisTreemap('#treemap', 'big', true);
    expenseTreemap.render($('#treemap').data('url'));

    window.addEventListener("resize", _.debounce(function () {
      expenseTreemap.render($('#treemap').data('url'));
    }, 250));
  }

  if($('.vis-bubbles-expense').length && $('.vis-bubbles-income').length && !$('.vis-bubbles-expense svg').length && !$('.vis-bubbles-income svg').length) {
    var getBubbleData = new getBudgetLevelData();

    getBubbleData.getData(function() {
      new VisSlider('.timeline', window.budgetLevels);

      var visBubblesExpense = new VisBubbles('.vis-bubbles-expense', 'expense', window.budgetLevels);
      visBubblesExpense.render();

      var visBubblesIncome = new VisBubbles('.vis-bubbles-income', 'income', window.budgetLevels);
      visBubblesIncome.render();

      window.addEventListener("resize", _.debounce(function () {
        new VisSlider('.timeline', window.budgetLevels);

        visBubblesExpense.resize();
        visBubblesIncome.resize();

        if (window.innerWidth >= 1024) {
          new VisBubbleLegend('.bubble_legend');
        } else {
          $('.bubble_legend svg').remove();
        }
      }, 250));

      $(document).on('visSlider:yearChanged', function(e, year) {
        visBubblesIncome.update(year);
        visBubblesExpense.update(year);
      });
    });

    if (window.innerWidth >= 1024) {
      new VisBubbleLegend('.bubble_legend');
    }
  }

  var $autocomplete = $('[data-autocomplete]');

  var searchOptions = {
    serviceUrl: $autocomplete.data('autocomplete'),
    onSelect: function(suggestion) {
      Turbolinks.visit(suggestion.data.url);
    },
    groupBy: 'category'
  };

  $autocomplete.devbridgeAutocomplete($.extend({}, AUTOCOMPLETE_DEFAULTS, searchOptions));

  $(".stick_ip").stick_in_parent()
    .on("sticky_kit:stick", function() {
      if($('.bread_links span').length)
        return;
      var title = $('h1').text();
      var breadLinksHtml = $('.bread_links').html();
      $('.bread_links').html(breadLinksHtml + ' ' + title + '');
    })
    .on("sticky_kit:unstick", function() {
      var sep = ' » ';
      var breadLinksHtml = $('.bread_links').html();
      var arr = breadLinksHtml.split(sep);
      arr.pop();
      $('.bread_links').html(arr.join(sep) + sep);
    });

  $('.bread_hover').hover(function() {
    $('.bread_links a').attr('aria-expanded', true);
    $('.line_browser').velocity("fadeIn", { duration: 50 });
  }, function() {
    $('.bread_links a').attr('aria-expanded', false);
    $('.line_browser').velocity("fadeOut", { duration: 50 });
  });

  $('.open_line_browser').click(function(e) {
    e.preventDefault();
    e.stopPropagation();
    $('.line_browser').velocity("fadeIn", { duration: 250 });
  });

  $('.close_line_browser').click(function(e) {
    e.preventDefault();
    e.stopPropagation();
    $('.line_browser').velocity("fadeOut", { duration: 150 });
  });

  $(window).click(function(){
    $('.line_browser').velocity("fadeOut", { duration: 150 });
  });

  $('.tooltiped-budget-lines').tipsy({
    gravity: 'se',
    trigger: 'manual',
    html: true,
    className: 'tipsy-lines'
  });

  $('.tooltiped-budget-lines').on('click', function() {
    $(this).tipsy("show");
  })

  $('.tooltiped').tipsy({
    gravity: 's',
    trigger: 'hover',
    html: true
  });
});
<|endoftext|>


<commit_before>define([], function() {

    return ["$timeout", "$rootScope", "api", function($timeout, $rootScope, api) {

        return {
            scope: {
                state: "=",
                questionDoc: "=",
                editorMode: "=",
            },
            restrict: "A",
            templateUrl: "/partials/equation_editor/equation_input.html",
            link: function(scope, element, attrs) {
                scope.textEntryError = '';
                if (scope.questionDoc && scope.questionDoc.availableSymbols) {
                    try {
                        scope.symbolList = scope.questionDoc.availableSymbols.map(function (str) {return str.trim().replace(';', ',')}).join(", ");
                    } catch (err) {
                        // Do not let invalid availableSymbols prevent anyone from answering the question!
                        scope.symbolList = null;
                    }
                }

                var timer = null;
                scope.textEdit = function() {
                    // This is on a keyUp event so it should not fire when showEquationEditor returns (see below)
                    if (timer) {
                        $timeout.cancel(timer);
                        timer = null;
                    }
                    timer = $timeout(function() {
                        var pycode = element.find(".eqn-text-input")[0].value;
                        var openBracketsCount = pycode.split('(').length;
                        var closeBracketsCount = pycode.split(')').length;

                        scope.state = {result: {python: pycode}, textEntry: true};
                        var badCharacters = /[^ (-)*-/0-9<->A-Z^-_a-z±²-³¼-¾×÷]+/;
                        if (/\\/.test(pycode)) {
                            scope.textEntryError = 'LaTeX syntax is not allowed.';
                        } else if (badCharacters.test(pycode)) {
                            scope.textEntryError = 'Some of the characters you are using are not allowed: ' + _.uniq(pycode.replace(RegExp(_.uniq(pycode.split(badCharacters)).join('|'), 'g'), '')).join(', ')
                        } else if (openBracketsCount != closeBracketsCount) {
                            scope.textEntryError = 'You are missing some ' + (closeBracketsCount > openBracketsCount ? 'opening' : 'closing') + ' brackets.';
                        } else {
                            scope.textEntryError = '';
                        }

                        // scope.textEntryError = pycode;
                    }, 250);
                };

                scope.edit = function() {

                    history.pushState({'null':'is null'}, "A Fake Title", window.location.href);
                    window.onpopstate = function(e) {
                        e.preventDefault();
                        $("#equationModal").foundation("reveal", "close");
                    };

                    $rootScope.showEquationEditor(scope.state, scope.questionDoc, scope.editorMode).then(function(finalState) {
                        scope.state = finalState;
                        if (finalState.hasOwnProperty("result") && finalState.result.hasOwnProperty("python")) {
                            element.find(".eqn-text-input")[0].value = finalState.result.python;
                        }
                        scope.$apply();
                    });
                };

                scope.$watch("state", function(s) {
                    if (s && s.result) {
                        // We have an existing answer to the question.
                        // If we have the LaTeX form, render it; else answer was typed:
                        if (s.result.tex) {
                            katex.render(s.result.tex, element.find(".eqn-preview")[0]);
                        } else {
                            element.find(".eqn-preview").html("Click to replace your typed answer");
                        }
                        // If we have the python form, add it to the text entry box (unless we're currently typing in the box; Safari bug!):
                        if (s.result.python && !(element.find(".eqn-text-input")[0] === document.activeElement)) {
                            element.find(".eqn-text-input")[0].value = s.result.python;
                        }
                    } else if (scope.questionDoc) {
                        // This is a question part not yet attempted:
                        element.find(".eqn-preview").html("Click to enter your answer");
                    } else {
                        // This is probably the /equality page:
                        element.find(".eqn-preview").html("Click to enter a formula!");
                    }
                })
            }
        };
    }];
});
<commit_msg>Fix the regexing filtering business of good and bad characters.<commit_after>define([], function() {

    return ["$timeout", "$rootScope", "api", function($timeout, $rootScope, api) {

        return {
            scope: {
                state: "=",
                questionDoc: "=",
                editorMode: "=",
            },
            restrict: "A",
            templateUrl: "/partials/equation_editor/equation_input.html",
            link: function(scope, element, attrs) {
                scope.textEntryError = '';
                if (scope.questionDoc && scope.questionDoc.availableSymbols) {
                    try {
                        scope.symbolList = scope.questionDoc.availableSymbols.map(function (str) {return str.trim().replace(';', ',')}).join(", ");
                    } catch (err) {
                        // Do not let invalid availableSymbols prevent anyone from answering the question!
                        scope.symbolList = null;
                    }
                }

                var timer = null;
                scope.textEdit = function() {
                    // This is on a keyUp event so it should not fire when showEquationEditor returns (see below)
                    if (timer) {
                        $timeout.cancel(timer);
                        timer = null;
                    }
                    timer = $timeout(function() {
                        var pycode = element.find(".eqn-text-input")[0].value;
                        var openBracketsCount = pycode.split('(').length;
                        var closeBracketsCount = pycode.split(')').length;

                        scope.state = {result: {python: pycode}, textEntry: true};
                        var regexStr = "[^ (-)*-/0-9<->A-Z^-_a-z±²-³¼-¾×÷]+";
                        var badCharacters = RegExp(regexStr);
                        var goodCharacters = RegExp(regexStr.replace("^", ""), 'g');
                        if (/[{}\\]/.test(pycode)) {
                            scope.textEntryError = 'LaTeX syntax is not allowed.';
                        } else if (badCharacters.test(pycode)) {
                            scope.textEntryError = 'Some of the characters you are using are not allowed: ' + _.uniq(pycode.replace(goodCharacters, '')).join(', ')
                        } else if (openBracketsCount != closeBracketsCount) {
                            scope.textEntryError = 'You are missing some ' + (closeBracketsCount > openBracketsCount ? 'opening' : 'closing') + ' brackets.';
                        } else {
                            scope.textEntryError = '';
                        }

                        // scope.textEntryError = pycode;
                    }, 250);
                };

                scope.edit = function() {

                    history.pushState({'null':'is null'}, "A Fake Title", window.location.href);
                    window.onpopstate = function(e) {
                        e.preventDefault();
                        $("#equationModal").foundation("reveal", "close");
                    };

                    $rootScope.showEquationEditor(scope.state, scope.questionDoc, scope.editorMode).then(function(finalState) {
                        scope.state = finalState;
                        if (finalState.hasOwnProperty("result") && finalState.result.hasOwnProperty("python")) {
                            element.find(".eqn-text-input")[0].value = finalState.result.python;
                        }
                        scope.$apply();
                    });
                };

                scope.$watch("state", function(s) {
                    if (s && s.result) {
                        // We have an existing answer to the question.
                        // If we have the LaTeX form, render it; else answer was typed:
                        if (s.result.tex) {
                            katex.render(s.result.tex, element.find(".eqn-preview")[0]);
                        } else {
                            element.find(".eqn-preview").html("Click to replace your typed answer");
                        }
                        // If we have the python form, add it to the text entry box (unless we're currently typing in the box; Safari bug!):
                        if (s.result.python && !(element.find(".eqn-text-input")[0] === document.activeElement)) {
                            element.find(".eqn-text-input")[0].value = s.result.python;
                        }
                    } else if (scope.questionDoc) {
                        // This is a question part not yet attempted:
                        element.find(".eqn-preview").html("Click to enter your answer");
                    } else {
                        // This is probably the /equality page:
                        element.find(".eqn-preview").html("Click to enter a formula!");
                    }
                })
            }
        };
    }];
});
<|endoftext|>


<commit_before>'use strict';
/* Draws a dependencyTree
 *
 * Can be used in isolation and awaits tokens passed into it, which have
 * a head.id property.
 *
 * The directive needs to be set on an svg element as attribute.
 *
 * Styling of the tree can be customized by passing a styles object as
 * attribute.
 * This object should be a dictionary of token ids with style information
 * in three categories: edge, label and token.
 * These properties should hold regular css style information. Example
 *
 *   {
 *     '0001' : {
 *       edge: { stroke: 'blue' },
 *       token: { color: 'white' }
 *     }
 *   }
 *
 * This would draw the edge of the token 0001 one blue and the textual
 * representation of the token itself in white.
 *
 * Tokens are rendered by the token directive. If no styles object has
 * been passed to the dependencyTree directive, the token itself will
 * decide its styling.
 * Hover and click events for tokens are activated. An option to customize
 * this will follow.
 *
 * Watches are in effect for changes of a tokens head.id value, changes
 * in the styles object, as well as in the tokens object.
 *
 * Example, given a tokens and a styles object in the current scope:
 *
 *   <svg dependency-tree tokens="tokens" styles="styles/>
 *
 */
/* global dagreD3 */
angular.module('arethusa.depTree').directive('dependencyTree', [
  '$compile',
  function ($compile) {
    return {
      restrict: 'A',
      scope: {
        tokens: '=',
        styles: '='
      },
      link: function (scope, element, attrs) {
        var rootText= "[ROOT]";

        function rootPlaceholder() {
          return '
' + rootText + '
';
        }

        function tokenPlaceholder(token) {
          return '
' + token.string + '
';
        }
        function labelPlaceholder(token) {
          var label = generateLabel(token);
          label = 'x   ' + label + '   x';
          var id = token.id;
          var classes = 'text-center tree-label';
          return '
' + label + '
';
        }
        function generateLabel(token) {
          return (token.relation || {}).label;
        }
        function tokenHasCustomStyling(token) {
          var t = scope.styles[token.id] || {};
          return t.token;
        }
        function applyTokenStyling(childScope, token) {
          childScope.style = scope.styles[token.id].token;
        }
        // Right now this function is responsible for managing the label and
        // edge colors when a custom styling is available.
        //
        // Once the relation plugin is ready, the label will be handled by
        // a directive that is coming from there.
        //
        // The directive will only stay responsible for the edges.
        //
        // If an edge style is overridden, we safe the old value in the
        // styleResets object. the resetEdgeStyling() function will now
        // how to operate with this then.
        var styleResets = {};
        function applyCustomStyling() {
          var edges = vis.selectAll('g.edgePath path');
          angular.forEach(scope.styles, function (style, id) {
            var labelStyle = style.label;
            var edgeStyle = style.edge;
            if (labelStyle) {
              label(id).style(labelStyle);
            }
            if (edgeStyle) {
              saveOldEdgeStyles(id, edgeStyle);
              edge(id).style(edgeStyle);
            }
          });
        }
        function saveOldEdgeStyles(id, properties) {
          if (properties) {
            var e = edge(id);
            var style = {};
            angular.forEach(properties, function (_, property) {
              style[property] = e.style(property);
            });
            styleResets[id] = style;
          }
        }
        function compiledEdgeLabel(token) {
          var template = '';
          var childScope = scope.$new();
          childScope.obj = token.relation;
          return $compile(template)(childScope)[0];
        }
        function compiledToken(token) {
          var childScope = scope.$new();
          childScope.token = token;
          // Ugly but working...
          // We replace the colorize value in our token template string.
          // If custom styles are given, we check if one is available for
          // this token. If yes, we use it, otherwise we just pass one
          // undefined which leaves the token unstyled.
          //
          // Without custom styles we let the token itself decide what color
          // it has.
          var style;
          if (scope.styles) {
            if (tokenHasCustomStyling(token)) {
              applyTokenStyling(childScope, token);
            }
            // else we just stay undefined
            style = 'style';
          } else {
            style = 'true';
          }
          return $compile(tokenHtml.replace('STYLE', style))(childScope)[0];
        }
        var tokenHtml ='';
        var rootTokenHtml = '' + rootText + '';

        // Creating the node set
        // g will hold the graph and be set when new tokens are loaded,
        // vis will be it's d3 representation
        var g;
        var vis;
        function createRootNode() {
          g.addNode('0000', { label: rootPlaceholder() });
        }
        function createNode(token) {
          g.addNode(token.id, { label: tokenPlaceholder(token) });
        }
        function nodePresent(id) {
          return g._nodes[id];
        }
        function hasHead(token) {
          return (token.head || {}).id;
        }
        function createEdges() {
          angular.forEach(scope.tokens, function (token, index) {
            if (hasHead(token)) {
              drawEdge(token);
            }
          });
        }
        function edges() {
          return vis.selectAll('g.edgePath path');
        }
        function edge(id) {
          return vis.select('#' + edgeId(id));
        }
        function edgePresent(id) {
          return edge(id)[0][0];  // yes, that's valid d3 syntax
        }
        function edgeId(id) {
          return 'tep' + id;
        }
        function label(id) {
          return vis.select('#' + labelId(id));
        }
        function labelId(id) {
          return 'tel' + id;
        }
        function nodeId(id) {
          return 'tph' + id;
        }
        function node(id) {
          return vis.select('#' + nodeId(id));
        }
        function nodes() {
          return vis.selectAll('div.node');
        }
        function drawEdge(token) {
          if (!nodePresent(token.id)) {
            createNode(token);
          }
          if (!nodePresent(token.head.id)) {
            createNode(scope.tokens[token.head.id]);
          }
          g.addEdge(token.id, token.id, token.head.id, { label: labelPlaceholder(token) });
        }
        function updateEdge(token) {
          if (edgePresent(token.id)) {
            g.delEdge(token.id);
          }
          drawEdge(token);
        }
        function resetEdgeStyling() {
          angular.forEach(styleResets, function (style, id) {
            edge(id).style(style);
          });
          styleResets = {};  // clean up, to avoid constant resetting
        }
        function createGraph(subtrees) {
          g = new dagreD3.Digraph();
          createRootNode();
          createEdges();
          render();
        }
        // Initialize the graph
        scope.compactTree = function() {
          scope.nodeSep = 30;
          scope.edgeSep = 10;
          scope.rankSep = 30;
        };

        scope.wideTree = function() {
          scope.nodeSep = 80;
          scope.edgeSep = 5;
          scope.rankSep = 40;
        };
        scope.changeDir = function() {
          scope.rankDir = scope.rankDir === "BT" ? "RL" : "BT";
        };

        scope.rankDir = 'BT';
        scope.compactTree();
        scope.layout = dagreD3.layout()
          .rankDir(scope.rankDir)
          .nodeSep(scope.nodeSep)
          .edgeSep(scope.edgeSep)
          .rankSep(scope.rankSep);

        var svg = d3.select(element[0]);
        svg.call(d3.behavior.zoom().on('zoom', function () {
          var ev = d3.event;
          svg.select('g').attr('transform', 'translate(' + ev.translate + ') scale(' + ev.scale + ')');
        }));
        var renderer = new dagreD3.Renderer();

        function transition(selection) {
          return selection.transition().duration(700);
        }
        renderer.transition(transition);

        // Prepend Tree settings panel
        scope.settingOn = false;
        element.wrap('

');
        var wrapper = element.parent();
        var panel = '\

*
\

\
             \
             \
             \
            compact \
            wide \
            direction\

\
        ';
        wrapper.prepend($compile(panel)(scope));

        function insertRootDirective() {
          node('0000').append(function() {
            this.textContent = '';
            return $compile(rootTokenHtml)(scope)[0];
          });
        }
        function insertTokenDirectives() {
          nodes().append(function () {
            // This is the element we append to and we created as a placeholder
            // We clear out its text content so that we can display the content
            // of our compiled token directive.
            // The placholder has an id in the format of tphXXXX where XXXX is the id.
            this.textContent = '';
            return compiledToken(scope.tokens[this.id.slice(3)]);
          });
        }
        function insertEdgeDirectives() {
          angular.forEach(scope.tokens, function (token, id) {
            label(id).append(function () {
              this.textContent = '';
              return compiledEdgeLabel(token);
            });
          });
        }
        function render() {
          vis = svg.select('g');
          renderer.layout(scope.layout).run(g, vis);
          // Customize the graph so that it holds our directives
          insertRootDirective();
          insertTokenDirectives();
          insertEdgeDirectives();

          // Not very elegant, but we don't want marker-end arrowheads right now
          // We also place an token edge path (tep) id on these elements, so that
          // we can access them more easily later on.
          edges().each(function (id) {
            angular.element(this).attr('id', edgeId(id));
          }).attr('marker-end', '');

          // A bug in webkit makes it impossible to select camelCase tags...
          // We work around by using a function.
          // http://stackoverflow.com/questions/11742812/cannot-select-svg-foreignobject-element-in-d3
          vis.selectAll(function () {
            return this.getElementsByTagName('foreignObject');
          }).each(function () {
            angular.element(this.children[0]).attr('style', 'float: center;');
          });
        }

        angular.forEach(scope.tokens, function (token, id) {
          var childScope = scope.$new();
          childScope.token = token.id;
          childScope.head = token.head;
          childScope.$watch('head.id', function (newVal, oldVal) {
            // Very important to do here, otherwise the tree will
            // be render a little often on startup...
            if (newVal !== oldVal) {
              updateEdge(token);
              render();
            }
          });
        });
        scope.$watch('tokens', function (newVal, oldVal) {
          createGraph();
        });
        scope.$watch('styles', function (newVal, oldVal) {
          if (newVal !== oldVal) {
            render();
            if (newVal) {
              applyCustomStyling();
            } else {
              resetEdgeStyling();
            }
          }
        });

        // Settings watches
        scope.$watch('nodeSep', function(newVal, oldVal) {
          if (newVal !== oldVal) {
            scope.layout.nodeSep(newVal);
            render();
          }
        });
        scope.$watch('edgeSep', function(newVal, oldVal) {
          if (newVal !== oldVal) {
            scope.layout.edgeSep(newVal);
            render();
          }
        });
        scope.$watch('rankSep', function(newVal, oldVal) {
          if (newVal !== oldVal) {
            scope.layout.rankSep(newVal);
            render();
          }
        });
        scope.$watch('rankDir', function(newVal, oldVal) {
          if (newVal !== oldVal) {
            scope.layout.rankDir(newVal);
            render();
          }
        });
      },
      template: '<g/>'
    };
  }
]);
<commit_msg>Styling in dependencyTree<commit_after>'use strict';
/* Draws a dependencyTree
 *
 * Can be used in isolation and awaits tokens passed into it, which have
 * a head.id property.
 *
 * The directive needs to be set on an svg element as attribute.
 *
 * Styling of the tree can be customized by passing a styles object as
 * attribute.
 * This object should be a dictionary of token ids with style information
 * in three categories: edge, label and token.
 * These properties should hold regular css style information. Example
 *
 *   {
 *     '0001' : {
 *       edge: { stroke: 'blue' },
 *       token: { color: 'white' }
 *     }
 *   }
 *
 * This would draw the edge of the token 0001 one blue and the textual
 * representation of the token itself in white.
 *
 * Tokens are rendered by the token directive. If no styles object has
 * been passed to the dependencyTree directive, the token itself will
 * decide its styling.
 * Hover and click events for tokens are activated. An option to customize
 * this will follow.
 *
 * Watches are in effect for changes of a tokens head.id value, changes
 * in the styles object, as well as in the tokens object.
 *
 * Example, given a tokens and a styles object in the current scope:
 *
 *   <svg dependency-tree tokens="tokens" styles="styles/>
 *
 */
/* global dagreD3 */
angular.module('arethusa.depTree').directive('dependencyTree', [
  '$compile',
  function ($compile) {
    return {
      restrict: 'A',
      scope: {
        tokens: '=',
        styles: '='
      },
      link: function (scope, element, attrs) {
        var rootText= "[ROOT]";

        function rootPlaceholder() {
          return '
' + rootText + '
';
        }

        function tokenPlaceholder(token) {
          return '
' + token.string + '
';
        }
        function labelPlaceholder(token) {
          var label = generateLabel(token);
          label = 'x   ' + label + '   x';
          var id = token.id;
          var classes = 'text-center tree-label';
          return '
' + label + '
';
        }
        function generateLabel(token) {
          return (token.relation || {}).label;
        }
        function tokenHasCustomStyling(token) {
          var t = scope.styles[token.id] || {};
          return t.token;
        }
        function applyTokenStyling(childScope, token) {
          childScope.style = scope.styles[token.id].token;
        }
        // Right now this function is responsible for managing the label and
        // edge colors when a custom styling is available.
        //
        // Once the relation plugin is ready, the label will be handled by
        // a directive that is coming from there.
        //
        // The directive will only stay responsible for the edges.
        //
        // If an edge style is overridden, we safe the old value in the
        // styleResets object. the resetEdgeStyling() function will now
        // how to operate with this then.
        var styleResets = {};
        function applyCustomStyling() {
          var edges = vis.selectAll('g.edgePath path');
          angular.forEach(scope.styles, function (style, id) {
            var labelStyle = style.label;
            var edgeStyle = style.edge;
            if (labelStyle) {
              label(id).style(labelStyle);
            }
            if (edgeStyle) {
              saveOldEdgeStyles(id, edgeStyle);
              edge(id).style(edgeStyle);
            }
          });
        }
        function saveOldEdgeStyles(id, properties) {
          if (properties) {
            var e = edge(id);
            var style = {};
            angular.forEach(properties, function (_, property) {
              style[property] = e.style(property);
            });
            styleResets[id] = style;
          }
        }
        function compiledEdgeLabel(token) {
          var template = '';
          var childScope = scope.$new();
          childScope.obj = token.relation;
          return $compile(template)(childScope)[0];
        }
        function compiledToken(token) {
          var childScope = scope.$new();
          childScope.token = token;
          // Ugly but working...
          // We replace the colorize value in our token template string.
          // If custom styles are given, we check if one is available for
          // this token. If yes, we use it, otherwise we just pass one
          // undefined which leaves the token unstyled.
          //
          // Without custom styles we let the token itself decide what color
          // it has.
          var style;
          if (scope.styles) {
            if (tokenHasCustomStyling(token)) {
              applyTokenStyling(childScope, token);
            }
            // else we just stay undefined
            style = 'style';
          } else {
            style = 'true';
          }
          return $compile(tokenHtml.replace('STYLE', style))(childScope)[0];
        }
        var tokenHtml ='';
        var rootTokenHtml = '' + rootText + '';

        // Creating the node set
        // g will hold the graph and be set when new tokens are loaded,
        // vis will be it's d3 representation
        var g;
        var vis;
        function createRootNode() {
          g.addNode('0000', { label: rootPlaceholder() });
        }
        function createNode(token) {
          g.addNode(token.id, { label: tokenPlaceholder(token) });
        }
        function nodePresent(id) {
          return g._nodes[id];
        }
        function hasHead(token) {
          return (token.head || {}).id;
        }
        function createEdges() {
          angular.forEach(scope.tokens, function (token, index) {
            if (hasHead(token)) {
              drawEdge(token);
            }
          });
        }
        function edges() {
          return vis.selectAll('g.edgePath path');
        }
        function edge(id) {
          return vis.select('#' + edgeId(id));
        }
        function edgePresent(id) {
          return edge(id)[0][0];  // yes, that's valid d3 syntax
        }
        function edgeId(id) {
          return 'tep' + id;
        }
        function label(id) {
          return vis.select('#' + labelId(id));
        }
        function labelId(id) {
          return 'tel' + id;
        }
        function nodeId(id) {
          return 'tph' + id;
        }
        function node(id) {
          return vis.select('#' + nodeId(id));
        }
        function nodes() {
          return vis.selectAll('div.node');
        }
        function drawEdge(token) {
          if (!nodePresent(token.id)) {
            createNode(token);
          }
          if (!nodePresent(token.head.id)) {
            createNode(scope.tokens[token.head.id]);
          }
          g.addEdge(token.id, token.id, token.head.id, { label: labelPlaceholder(token) });
        }
        function updateEdge(token) {
          if (edgePresent(token.id)) {
            g.delEdge(token.id);
          }
          drawEdge(token);
        }
        function resetEdgeStyling() {
          angular.forEach(styleResets, function (style, id) {
            edge(id).style(style);
          });
          styleResets = {};  // clean up, to avoid constant resetting
        }
        function createGraph(subtrees) {
          g = new dagreD3.Digraph();
          createRootNode();
          createEdges();
          render();
        }
        // Initialize the graph
        scope.compactTree = function() {
          scope.nodeSep = 30;
          scope.edgeSep = 10;
          scope.rankSep = 30;
        };

        scope.wideTree = function() {
          scope.nodeSep = 80;
          scope.edgeSep = 5;
          scope.rankSep = 40;
        };
        scope.changeDir = function() {
          scope.rankDir = scope.rankDir === "BT" ? "RL" : "BT";
        };

        scope.rankDir = 'BT';
        scope.compactTree();
        scope.layout = dagreD3.layout()
          .rankDir(scope.rankDir)
          .nodeSep(scope.nodeSep)
          .edgeSep(scope.edgeSep)
          .rankSep(scope.rankSep);

        var svg = d3.select(element[0]);
        svg.call(d3.behavior.zoom().on('zoom', function () {
          var ev = d3.event;
          svg.select('g').attr('transform', 'translate(' + ev.translate + ') scale(' + ev.scale + ')');
        }));
        var renderer = new dagreD3.Renderer();

        function transition(selection) {
          return selection.transition().duration(700);
        }
        renderer.transition(transition);

        // Prepend Tree settings panel
        scope.settingOn = false;
        element.wrap('

');
        var wrapper = element.parent();
        var panel = '\

*
\

\
             \
             \
             \
            compact \
            wide \
            change direction\

\
        ';
        wrapper.prepend($compile(panel)(scope));

        function insertRootDirective() {
          node('0000').append(function() {
            this.textContent = '';
            return $compile(rootTokenHtml)(scope)[0];
          });
        }
        function insertTokenDirectives() {
          nodes().append(function () {
            // This is the element we append to and we created as a placeholder
            // We clear out its text content so that we can display the content
            // of our compiled token directive.
            // The placholder has an id in the format of tphXXXX where XXXX is the id.
            this.textContent = '';
            return compiledToken(scope.tokens[this.id.slice(3)]);
          });
        }
        function insertEdgeDirectives() {
          angular.forEach(scope.tokens, function (token, id) {
            label(id).append(function () {
              this.textContent = '';
              return compiledEdgeLabel(token);
            });
          });
        }
        function render() {
          vis = svg.select('g');
          renderer.layout(scope.layout).run(g, vis);
          // Customize the graph so that it holds our directives
          insertRootDirective();
          insertTokenDirectives();
          insertEdgeDirectives();

          // Not very elegant, but we don't want marker-end arrowheads right now
          // We also place an token edge path (tep) id on these elements, so that
          // we can access them more easily later on.
          edges().each(function (id) {
            angular.element(this).attr('id', edgeId(id));
          }).attr('marker-end', '');

          // A bug in webkit makes it impossible to select camelCase tags...
          // We work around by using a function.
          // http://stackoverflow.com/questions/11742812/cannot-select-svg-foreignobject-element-in-d3
          vis.selectAll(function () {
            return this.getElementsByTagName('foreignObject');
          }).each(function () {
            angular.element(this.children[0]).attr('style', 'float: center;');
          });
        }

        angular.forEach(scope.tokens, function (token, id) {
          var childScope = scope.$new();
          childScope.token = token.id;
          childScope.head = token.head;
          childScope.$watch('head.id', function (newVal, oldVal) {
            // Very important to do here, otherwise the tree will
            // be render a little often on startup...
            if (newVal !== oldVal) {
              updateEdge(token);
              render();
            }
          });
        });
        scope.$watch('tokens', function (newVal, oldVal) {
          createGraph();
        });
        scope.$watch('styles', function (newVal, oldVal) {
          if (newVal !== oldVal) {
            render();
            if (newVal) {
              applyCustomStyling();
            } else {
              resetEdgeStyling();
            }
          }
        });

        // Settings watches
        scope.$watch('nodeSep', function(newVal, oldVal) {
          if (newVal !== oldVal) {
            scope.layout.nodeSep(newVal);
            render();
          }
        });
        scope.$watch('edgeSep', function(newVal, oldVal) {
          if (newVal !== oldVal) {
            scope.layout.edgeSep(newVal);
            render();
          }
        });
        scope.$watch('rankSep', function(newVal, oldVal) {
          if (newVal !== oldVal) {
            scope.layout.rankSep(newVal);
            render();
          }
        });
        scope.$watch('rankDir', function(newVal, oldVal) {
          if (newVal !== oldVal) {
            scope.layout.rankDir(newVal);
            render();
          }
        });
      },
      template: '<g/>'
    };
  }
]);
<|endoftext|>


<commit_before>'use strict';
/* Draws a dependencyTree
 *
 * Can be used in isolation and awaits tokens passed into it, which have
 * a head.id property.
 *
 * The directive needs to be set on an svg element as attribute.
 *
 * Styling of the tree can be customized by passing a styles object as
 * attribute.
 * This object should be a dictionary of token ids with style information
 * in three categories: edge, label and token.
 * These properties should hold regular css style information. Example
 *
 *   {
 *     '0001' : {
 *       edge: { stroke: 'blue' },
 *       token: { color: 'white' }
 *     }
 *   }
 *
 * This would draw the edge of the token 0001 one blue and the textual
 * representation of the token itself in white.
 *
 * Tokens are rendered by the token directive. If no styles object has
 * been passed to the dependencyTree directive, the token itself will
 * decide its styling.
 * Hover and click events for tokens are activated. An option to customize
 * this will follow.
 *
 * Watches are in effect for changes of a tokens head.id value, changes
 * in the styles object, as well as in the tokens object.
 *
 * Example, given a tokens and a styles object in the current scope:
 *
 *   <svg dependency-tree tokens="tokens" styles="styles/>
 *
 */
/* global dagreD3 */
angular.module('arethusa.depTree').directive('dependencyTree', [
  '$compile',
  function ($compile) {
    return {
      restrict: 'A',
      scope: {
        tokens: '=',
        styles: '='
      },
      link: function (scope, element, attrs) {
        var rootText= "[ROOT]";

        function rootPlaceholder() {
          return '
' + rootText + '
';
        }

        function tokenPlaceholder(token) {
          return '
' + token.string + '
';
        }
        function labelPlaceholder(token) {
          //var label = generateLabel(token);
          var label = 'xxxxxxxxxxx';
          var id = token.id;
          var classes = 'text-center tree-label';
          return '
' + label + '
';
        }
        function generateLabel(token) {
          return (token.relation || {}).label;
        }
        function tokenHasCustomStyling(token) {
          var t = scope.styles[token.id] || {};
          return t.token;
        }
        function applyTokenStyling(childScope, token) {
          childScope.style = scope.styles[token.id].token;
        }
        // Right now this function is responsible for managing the label and
        // edge colors when a custom styling is available.
        //
        // Once the relation plugin is ready, the label will be handled by
        // a directive that is coming from there.
        //
        // The directive will only stay responsible for the edges.
        //
        // If an edge style is overridden, we safe the old value in the
        // styleResets object. the resetEdgeStyling() function will now
        // how to operate with this then.
        var styleResets = {};
        function applyCustomStyling() {
          var edges = vis.selectAll('g.edgePath path');
          angular.forEach(scope.styles, function (style, id) {
            var labelStyle = style.label;
            var edgeStyle = style.edge;
            if (labelStyle) {
              label(id).style(labelStyle);
            }
            if (edgeStyle) {
              saveOldEdgeStyles(id, edgeStyle);
              edge(id).style(edgeStyle);
            }
          });
        }
        function saveOldEdgeStyles(id, properties) {
          if (properties) {
            var e = edge(id);
            var style = {};
            angular.forEach(properties, function (_, property) {
              style[property] = e.style(property);
            });
            styleResets[id] = style;
          }
        }
        function compiledEdgeLabel(token) {
          var template = '';
          var childScope = scope.$new();
          childScope.obj = token.relation;
          return $compile(template)(childScope)[0];
        }
        function compiledToken(token) {
          var childScope = scope.$new();
          childScope.token = token;
          // Ugly but working...
          // We replace the colorize value in our token template string.
          // If custom styles are given, we check if one is available for
          // this token. If yes, we use it, otherwise we just pass one
          // undefined which leaves the token unstyled.
          //
          // Without custom styles we let the token itself decide what color
          // it has.
          var style;
          if (scope.styles) {
            if (tokenHasCustomStyling(token)) {
              applyTokenStyling(childScope, token);
            }
            // else we just stay undefined
            style = 'style';
          } else {
            style = 'true';
          }
          return $compile(tokenHtml.replace('STYLE', style))(childScope)[0];
        }
        var tokenHtml ='';
        var rootTokenHtml = '' + rootText + '';

        // Creating the node set
        // g will hold the graph and be set when new tokens are loaded,
        // vis will be it's d3 representation
        var g;
        var vis;
        function createRootNode() {
          g.addNode('0000', { label: rootPlaceholder() });
        }
        function createNode(token) {
          g.addNode(token.id, { label: tokenPlaceholder(token) });
        }
        function nodePresent(id) {
          return g._nodes[id];
        }
        function hasHead(token) {
          return (token.head || {}).id;
        }
        function createEdges() {
          angular.forEach(scope.tokens, function (token, index) {
            if (hasHead(token)) {
              drawEdge(token);
            }
          });
        }
        function edges() {
          return vis.selectAll('g.edgePath path');
        }
        function edge(id) {
          return vis.select('#' + edgeId(id));
        }
        function edgePresent(id) {
          return edge(id)[0][0];  // yes, that's valid d3 syntax
        }
        function edgeId(id) {
          return 'tep' + id;
        }
        function label(id) {
          return vis.select('#' + labelId(id));
        }
        function labelId(id) {
          return 'tel' + id;
        }
        function nodeId(id) {
          return 'tph' + id;
        }
        function node(id) {
          return vis.select('#' + nodeId(id));
        }
        function nodes() {
          return vis.selectAll('div.node');
        }
        function drawEdge(token) {
          if (!nodePresent(token.id)) {
            createNode(token);
          }
          if (!nodePresent(token.head.id)) {
            createNode(scope.tokens[token.head.id]);
          }
          g.addEdge(token.id, token.id, token.head.id, { label: labelPlaceholder(token) });
        }
        function updateEdge(token) {
          if (edgePresent(token.id)) {
            g.delEdge(token.id);
          }
          drawEdge(token);
        }
        function resetEdgeStyling() {
          angular.forEach(styleResets, function (style, id) {
            edge(id).style(style);
          });
          styleResets = {};  // clean up, to avoid constant resetting
        }
        function createGraph(subtrees) {
          g = new dagreD3.Digraph();
          createRootNode();
          createEdges();
          render();
        }
        // Initialize the graph
        scope.compactTree = function() {
          scope.nodeSep = 30;
          scope.edgeSep = 10;
          scope.rankSep = 30;
        };

        scope.wideTree = function() {
          scope.nodeSep = 80;
          scope.edgeSep = 5;
          scope.rankSep = 40;
        };
        scope.changeDir = function() {
          scope.rankDir = scope.rankDir === "BT" ? "RL" : "BT";
        };

        scope.rankDir = 'BT';
        scope.compactTree();
        scope.layout = dagreD3.layout()
          .rankDir(scope.rankDir)
          .nodeSep(scope.nodeSep)
          .edgeSep(scope.edgeSep)
          .rankSep(scope.rankSep);

        var svg = d3.select(element[0]);
        svg.call(d3.behavior.zoom().on('zoom', function () {
          var ev = d3.event;
          svg.select('g').attr('transform', 'translate(' + ev.translate + ') scale(' + ev.scale + ')');
        }).scaleExtent([0.3, 2.5]));
        var renderer = new dagreD3.Renderer();

        function transition(selection) {
          return selection.transition().duration(700);
        }
        renderer.transition(transition);

        // Prepend Tree settings panel
        scope.settingOn = false;
        element.wrap('

');
        var wrapper = element.parent();
        var panel = '\

*
\

\
             \
             \
             \
            compact \
            wide \
            change direction\

\
        ';
        wrapper.prepend($compile(panel)(scope));

        function insertRootDirective() {
          node('0000').append(function() {
            this.textContent = '';
            return $compile(rootTokenHtml)(scope)[0];
          });
        }
        function insertTokenDirectives() {
          nodes().append(function () {
            // This is the element we append to and we created as a placeholder
            // We clear out its text content so that we can display the content
            // of our compiled token directive.
            // The placholder has an id in the format of tphXXXX where XXXX is the id.
            this.textContent = '';
            return compiledToken(scope.tokens[this.id.slice(3)]);
          });
        }
        function insertEdgeDirectives() {
          angular.forEach(scope.tokens, function (token, id) {
            label(id).append(function () {
              this.textContent = '';
              return compiledEdgeLabel(token);
            });
          });
        }
        function render() {
          vis = svg.select('g');
          renderer.layout(scope.layout).run(g, vis);
          // Customize the graph so that it holds our directives
          insertRootDirective();
          insertTokenDirectives();
          insertEdgeDirectives();

          // Not very elegant, but we don't want marker-end arrowheads right now
          // We also place an token edge path (tep) id on these elements, so that
          // we can access them more easily later on.
          edges().each(function (id) {
            angular.element(this).attr('id', edgeId(id));
          }).attr('marker-end', '');

          // A bug in webkit makes it impossible to select camelCase tags...
          // We work around by using a function.
          // http://stackoverflow.com/questions/11742812/cannot-select-svg-foreignobject-element-in-d3
          vis.selectAll(function () {
            return this.getElementsByTagName('foreignObject');
          }).each(function () {
            angular.element(this.children[0]).attr('style', 'float: center;');
          });
        }

        function createHeadWatches() {
          angular.forEach(scope.tokens, function (token, id) {
            var childScope = scope.$new();
            childScope.token = token.id;
            childScope.head = token.head;
            childScope.$watch('head.id', function (newVal, oldVal) { // Very important to do here, otherwise the tree will
              // be render a little often on startup...
              if (newVal !== oldVal) {
                // If a disconnection has been requested, we just
                // have to delete the edge and do nothing else
                if (newVal === "") {
                  g.delEdge(token.id);
                } else {
                  updateEdge(token);
                }
                render();
              }
            });
          });
        }

        scope.$watch('tokens', function (newVal, oldVal) {
          createGraph();
          createHeadWatches();
        });
        scope.$watch('styles', function (newVal, oldVal) {
          if (newVal !== oldVal) {
            render();
            if (newVal) {
              applyCustomStyling();
            } else {
              resetEdgeStyling();
            }
          }
        });

        // Settings watches
        scope.$watch('nodeSep', function(newVal, oldVal) {
          if (newVal !== oldVal) {
            scope.layout.nodeSep(newVal);
            render();
          }
        });
        scope.$watch('edgeSep', function(newVal, oldVal) {
          if (newVal !== oldVal) {
            scope.layout.edgeSep(newVal);
            render();
          }
        });
        scope.$watch('rankSep', function(newVal, oldVal) {
          if (newVal !== oldVal) {
            scope.layout.rankSep(newVal);
            render();
          }
        });
        scope.$watch('rankDir', function(newVal, oldVal) {
          if (newVal !== oldVal) {
            scope.layout.rankDir(newVal);
            render();
          }
        });
      },
      template: '<svg class="full-height full-width"><g/></svg>'
    };
  }
]);
<commit_msg>Use languageSettings to set tree order<commit_after>'use strict';
/* Draws a dependencyTree
 *
 * Can be used in isolation and awaits tokens passed into it, which have
 * a head.id property.
 *
 * The directive needs to be set on an svg element as attribute.
 *
 * Styling of the tree can be customized by passing a styles object as
 * attribute.
 * This object should be a dictionary of token ids with style information
 * in three categories: edge, label and token.
 * These properties should hold regular css style information. Example
 *
 *   {
 *     '0001' : {
 *       edge: { stroke: 'blue' },
 *       token: { color: 'white' }
 *     }
 *   }
 *
 * This would draw the edge of the token 0001 one blue and the textual
 * representation of the token itself in white.
 *
 * Tokens are rendered by the token directive. If no styles object has
 * been passed to the dependencyTree directive, the token itself will
 * decide its styling.
 * Hover and click events for tokens are activated. An option to customize
 * this will follow.
 *
 * Watches are in effect for changes of a tokens head.id value, changes
 * in the styles object, as well as in the tokens object.
 *
 * Example, given a tokens and a styles object in the current scope:
 *
 *   <svg dependency-tree tokens="tokens" styles="styles/>
 *
 */
/* global dagreD3 */
angular.module('arethusa.depTree').directive('dependencyTree', [
  '$compile',
  'languageSettings',
  function ($compile, languageSettings) {
    return {
      restrict: 'A',
      scope: {
        tokens: '=',
        styles: '='
      },
      link: function (scope, element, attrs) {
        var rootText= "[ROOT]";

        function rootPlaceholder() {
          return '
' + rootText + '
';
        }

        function tokenPlaceholder(token) {
          return '
' + token.string + '
';
        }
        function labelPlaceholder(token) {
          //var label = generateLabel(token);
          var label = 'xxxxxxxxxxx';
          var id = token.id;
          var classes = 'text-center tree-label';
          return '
' + label + '
';
        }
        function generateLabel(token) {
          return (token.relation || {}).label;
        }
        function tokenHasCustomStyling(token) {
          var t = scope.styles[token.id] || {};
          return t.token;
        }
        function applyTokenStyling(childScope, token) {
          childScope.style = scope.styles[token.id].token;
        }
        // Right now this function is responsible for managing the label and
        // edge colors when a custom styling is available.
        //
        // Once the relation plugin is ready, the label will be handled by
        // a directive that is coming from there.
        //
        // The directive will only stay responsible for the edges.
        //
        // If an edge style is overridden, we safe the old value in the
        // styleResets object. the resetEdgeStyling() function will now
        // how to operate with this then.
        var styleResets = {};
        function applyCustomStyling() {
          var edges = vis.selectAll('g.edgePath path');
          angular.forEach(scope.styles, function (style, id) {
            var labelStyle = style.label;
            var edgeStyle = style.edge;
            if (labelStyle) {
              label(id).style(labelStyle);
            }
            if (edgeStyle) {
              saveOldEdgeStyles(id, edgeStyle);
              edge(id).style(edgeStyle);
            }
          });
        }
        function saveOldEdgeStyles(id, properties) {
          if (properties) {
            var e = edge(id);
            var style = {};
            angular.forEach(properties, function (_, property) {
              style[property] = e.style(property);
            });
            styleResets[id] = style;
          }
        }
        function compiledEdgeLabel(token) {
          var template = '';
          var childScope = scope.$new();
          childScope.obj = token.relation;
          return $compile(template)(childScope)[0];
        }
        function compiledToken(token) {
          var childScope = scope.$new();
          childScope.token = token;
          // Ugly but working...
          // We replace the colorize value in our token template string.
          // If custom styles are given, we check if one is available for
          // this token. If yes, we use it, otherwise we just pass one
          // undefined which leaves the token unstyled.
          //
          // Without custom styles we let the token itself decide what color
          // it has.
          var style;
          if (scope.styles) {
            if (tokenHasCustomStyling(token)) {
              applyTokenStyling(childScope, token);
            }
            // else we just stay undefined
            style = 'style';
          } else {
            style = 'true';
          }
          return $compile(tokenHtml.replace('STYLE', style))(childScope)[0];
        }
        var tokenHtml ='';
        var rootTokenHtml = '' + rootText + '';

        // Creating the node set
        // g will hold the graph and be set when new tokens are loaded,
        // vis will be it's d3 representation
        var g;
        var vis;
        function createRootNode() {
          g.addNode('0000', { label: rootPlaceholder() });
        }
        function createNode(token) {
          g.addNode(token.id, { label: tokenPlaceholder(token) });
        }
        function nodePresent(id) {
          return g._nodes[id];
        }
        function hasHead(token) {
          return (token.head || {}).id;
        }
        function createEdges() {
          angular.forEach(scope.tokens, function (token, index) {
            if (hasHead(token)) {
              drawEdge(token);
            }
          });
        }
        function edges() {
          return vis.selectAll('g.edgePath path');
        }
        function edge(id) {
          return vis.select('#' + edgeId(id));
        }
        function edgePresent(id) {
          return edge(id)[0][0];  // yes, that's valid d3 syntax
        }
        function edgeId(id) {
          return 'tep' + id;
        }
        function label(id) {
          return vis.select('#' + labelId(id));
        }
        function labelId(id) {
          return 'tel' + id;
        }
        function nodeId(id) {
          return 'tph' + id;
        }
        function node(id) {
          return vis.select('#' + nodeId(id));
        }
        function nodes() {
          return vis.selectAll('div.node');
        }
        function drawEdge(token) {
          if (!nodePresent(token.id)) {
            createNode(token);
          }
          if (!nodePresent(token.head.id)) {
            createNode(scope.tokens[token.head.id]);
          }
          g.addEdge(token.id, token.id, token.head.id, { label: labelPlaceholder(token) });
        }
        function updateEdge(token) {
          if (edgePresent(token.id)) {
            g.delEdge(token.id);
          }
          drawEdge(token);
        }
        function resetEdgeStyling() {
          angular.forEach(styleResets, function (style, id) {
            edge(id).style(style);
          });
          styleResets = {};  // clean up, to avoid constant resetting
        }
        function createGraph(subtrees) {
          g = new dagreD3.Digraph();
          createRootNode();
          createEdges();
          render();
        }
        // Initialize the graph
        scope.compactTree = function() {
          scope.nodeSep = 30;
          scope.edgeSep = 10;
          scope.rankSep = 30;
        };

        scope.wideTree = function() {
          scope.nodeSep = 80;
          scope.edgeSep = 5;
          scope.rankSep = 40;
        };
        scope.changeDir = function() {
          scope.rankDir = scope.rankDir === "BT" ? "RL" : "BT";
        };

        var langSettings = languageSettings.getFor('treebank');

        scope.rankDir = 'BT';
        scope.compactTree();
        scope.layout = dagreD3.layout()
          .invertOrder(langSettings ? !langSettings.leftToRight : false)
          .rankDir(scope.rankDir)
          .nodeSep(scope.nodeSep)
          .edgeSep(scope.edgeSep)
          .rankSep(scope.rankSep);

        var svg = d3.select(element[0]);
        svg.call(d3.behavior.zoom().on('zoom', function () {
          var ev = d3.event;
          svg.select('g').attr('transform', 'translate(' + ev.translate + ') scale(' + ev.scale + ')');
        }).scaleExtent([0.3, 2.5]));
        var renderer = new dagreD3.Renderer();

        function transition(selection) {
          return selection.transition().duration(700);
        }
        renderer.transition(transition);

        // Prepend Tree settings panel
        scope.settingOn = false;
        element.wrap('

');
        var wrapper = element.parent();
        var panel = '\

*
\

\
             \
             \
             \
            compact \
            wide \
            change direction\

\
        ';
        wrapper.prepend($compile(panel)(scope));

        function insertRootDirective() {
          node('0000').append(function() {
            this.textContent = '';
            return $compile(rootTokenHtml)(scope)[0];
          });
        }
        function insertTokenDirectives() {
          nodes().append(function () {
            // This is the element we append to and we created as a placeholder
            // We clear out its text content so that we can display the content
            // of our compiled token directive.
            // The placholder has an id in the format of tphXXXX where XXXX is the id.
            this.textContent = '';
            return compiledToken(scope.tokens[this.id.slice(3)]);
          });
        }
        function insertEdgeDirectives() {
          angular.forEach(scope.tokens, function (token, id) {
            label(id).append(function () {
              this.textContent = '';
              return compiledEdgeLabel(token);
            });
          });
        }
        function render() {
          vis = svg.select('g');
          renderer.layout(scope.layout).run(g, vis);
          // Customize the graph so that it holds our directives
          insertRootDirective();
          insertTokenDirectives();
          insertEdgeDirectives();

          // Not very elegant, but we don't want marker-end arrowheads right now
          // We also place an token edge path (tep) id on these elements, so that
          // we can access them more easily later on.
          edges().each(function (id) {
            angular.element(this).attr('id', edgeId(id));
          }).attr('marker-end', '');

          // A bug in webkit makes it impossible to select camelCase tags...
          // We work around by using a function.
          // http://stackoverflow.com/questions/11742812/cannot-select-svg-foreignobject-element-in-d3
          vis.selectAll(function () {
            return this.getElementsByTagName('foreignObject');
          }).each(function () {
            angular.element(this.children[0]).attr('style', 'float: center;');
          });
        }

        function createHeadWatches() {
          angular.forEach(scope.tokens, function (token, id) {
            var childScope = scope.$new();
            childScope.token = token.id;
            childScope.head = token.head;
            childScope.$watch('head.id', function (newVal, oldVal) { // Very important to do here, otherwise the tree will
              // be render a little often on startup...
              if (newVal !== oldVal) {
                // If a disconnection has been requested, we just
                // have to delete the edge and do nothing else
                if (newVal === "") {
                  g.delEdge(token.id);
                } else {
                  updateEdge(token);
                }
                render();
              }
            });
          });
        }

        scope.$watch('tokens', function (newVal, oldVal) {
          createGraph();
          createHeadWatches();
        });
        scope.$watch('styles', function (newVal, oldVal) {
          if (newVal !== oldVal) {
            render();
            if (newVal) {
              applyCustomStyling();
            } else {
              resetEdgeStyling();
            }
          }
        });

        // Settings watches
        scope.$watch('nodeSep', function(newVal, oldVal) {
          if (newVal !== oldVal) {
            scope.layout.nodeSep(newVal);
            render();
          }
        });
        scope.$watch('edgeSep', function(newVal, oldVal) {
          if (newVal !== oldVal) {
            scope.layout.edgeSep(newVal);
            render();
          }
        });
        scope.$watch('rankSep', function(newVal, oldVal) {
          if (newVal !== oldVal) {
            scope.layout.rankSep(newVal);
            render();
          }
        });
        scope.$watch('rankDir', function(newVal, oldVal) {
          if (newVal !== oldVal) {
            scope.layout.rankDir(newVal);
            render();
          }
        });
      },
      template: '<svg class="full-height full-width"><g/></svg>'
    };
  }
]);
<|endoftext|>


<commit_before>var and = require('join-component');

var doorways = function(pollingPlace) {

  var site = pollingPlace;
  var doorwaysData = site['1. Doorways'].root;
  var response = { summary: 'No doorways.', warnings: [] };

  if ( doorwaysData.qid_0.answer < 1 ) { return response; }

  if (   doorwaysData.qid_1.answer === 'No' || doorwaysData.qid_2.answer === 'No'
      || doorwaysData.qid_9.answer === 'No' ) {
    response.warnings.push('Some doorways may be narrow (less than 32").');
  }

  if ( doorwaysData.qid_3.answer === 'No' || doorwaysData.qid_4.answer === 'No' ) {
    response.warnings.push('Watch for high thresholds in doorways.');
  }

  if ( doorwaysData.qid_5.answer === 'No' ) {
    response.warnings.push('Door handles may require twisting, pinching, or grasping actions.');
  }

  if ( doorwaysData.qid_6.answer === 'No' ) {
    response.warnings.push('Door handles may be higher than normal.');
  }

  if ( doorwaysData.qid_7.answer === 'No' ) {
    response.warnings.push('Doorways may not have a smooth pushing surface.');
  }

  if ( doorwaysData.qid_8.answer === 'No' ) {
    response.warnings.push('Closed doors may be heavy (Door should be propped open on election day).');
  }

  if (   doorwaysData.qid_10.answer === 'No' || doorwaysData.qid_12.answer === 'No'
      || doorwaysData.qid_13.answer === 'No' || doorwaysData.qid_14.answer === 'No' ) {
    response.warnings.push('Take care for uneven or crowded spaces around the doorways');
  }

  if ( doorwaysData.qid_11.answer === 'No' || doorwaysData.qid_15.answer === 'No' ) {
    response.warnings.push('Narrow strike space in doorways.');
  }

  console.log( "warnings size: " + response.warnings.length );

  if ( response.warnings.length > 0 ) {
    response.summary = 'Some accessibility concerns with the doorways: ';
  } else {
    response.summary = 'Doorways are accessible to all.';
  }

  return response;
};

module.exports = doorways;
<commit_msg>Handled undefined questions for some sites.<commit_after>var and = require('join-component');

var doorways = function(pollingPlace) {

  var site = pollingPlace;
  var doorwaysData = site['1. Doorways'].root;
  var response = { summary: 'No doorways.', warnings: [] };

  if ( doorwaysData.qid_0.answer < 1 ) { return response; }

  if (   doorwaysData.qid_1.answer === 'No' || doorwaysData.qid_2.answer === 'No'
      || doorwaysData.qid_9.answer === 'No' ) {
    response.warnings.push('Some doorways may be narrow (less than 32").');
  }

  if ( doorwaysData.qid_3.answer === 'No' || doorwaysData.qid_4.answer === 'No' ) {
    response.warnings.push('Watch for high thresholds in doorways.');
  }

  if ( doorwaysData.qid_5.answer === 'No' ) {
    response.warnings.push('Door handles may require twisting, pinching, or grasping actions.');
  }

  if ( doorwaysData.qid_6.answer === 'No' ) {
    response.warnings.push('Door handles may be higher than normal.');
  }

  if ( doorwaysData.qid_7.answer === 'No' ) {
    response.warnings.push('Doorways may not have a smooth pushing surface.');
  }

  if ( doorwaysData.qid_8.answer === 'No' ) {
    response.warnings.push('Closed doors may be heavy (Door should be propped open on election day).');
  }

  if (   doorwaysData.qid_10.answer === 'No' || doorwaysData.qid_12.answer === 'No'
      || ( doorwaysData.qid_14 !== undefined  && doorwaysData.qid_14.answer  === 'No' )
      || doorwaysData.qid_13.answer === 'No' ) {
    response.warnings.push('Take care for uneven or crowded spaces around the doorways');
  }

  if ( doorwaysData.qid_11.answer === 'No' || ( doorwaysData.qid_15 !== undefined
                                               && doorwaysData.qid_15.answer  === 'No' ) ) {
    response.warnings.push('Narrow strike space in doorways.');
  }

  if ( response.warnings.length > 0 ) {
    response.summary = 'Some accessibility concerns with the doorways: ';
  } else {
    response.summary = 'Doorways are accessible to all.';
  }

  return response;
};

module.exports = doorways;
<|endoftext|>


<commit_before>function log (display) {
	return console.log(display);
}

function get(x){
	return document.getElementById(x);
}

function tagger(tag) {
	return document.getElementsByTagName(tag);
}

function classer(classy) {
	return document.getElementsByClassName(classy);
}

function create(el) {
	return document.createElement(el);
}

function tNode(text) {
	return document.createTextNode(text);
}

function makeImage(imgLink, imageId){
	return '';
}

function removeEl(elId){
	get(elID).parentNode.removeChild(get(elID));
}

//This is a function that will help us manipulate the DOM, while adding in a callback if we need some extra functionality
function domMan(elType, text, position, callback){
	var newEl = create(elType);
	var textInfo = text;
	newEl.appendChild(text);
	position.appendChild(newEl);

	if(callback !== undefined){
		callback(newEl);
	}
}

function updateFilmTable(filmResponse){

	//Getting the poster link to display...
	var posterLink = filmResponse.Poster;

	//Making sure the film came through
	if(filmResponse.Response === "True"){
		//we'll define a helpful variable to reference the move number we're working with
		var filmNumber = (data.filmData.length).toString();

		//This will add in the poster to our site. Pretty!
		domMan("figure", tNode(""), get('posterSection'), function(){
			//this callback function updates what would normally be a simple text node into an image of the film poster
			var number = get("posterSection").childNodes.length - 1;
			get("posterSection").childNodes[number].innerHTML = makeImage(filmResponse.Poster, "poster"+filmNumber);
		});

		get("poster"+filmNumber).parentNode.id = "film"+filmNumber;
		get("poster"+filmNumber).parentNode.class = "films";

	}

	/*else if(get("feedback").childNodes[1] === undefined){
		domMan("p", tNode("Hmm. We weren't able to find that film in the database... is there another that you like?"), get("feedback"), function(){
		});
		console.log(filmData);
		filmData.shift();
	}*/
}

function postMovie(e){

	//Get the 'target'; the element that the user clicks on
	resetFilmNumbers();
	var target = e.target;

	if(target.id === "generator" && data.genStory){
		data.dark = ageApp(data.filmData);
		explode();
		get("theButton").innerHTML = ""; // = false;
	}

	else if(target.id === "adder"){

		var yearInt = parseInt(elYear.value);

		if(elMovie.value !== "Movie" && elMovie.value && elYear.value !== "Year" && 2016 > yearInt && yearInt > 1890){

			var movieTitle = elMovie.value;
			var year = elYear.value;

			var urlToCall = urlBuild(titleSmoother(movieTitle), year);

			//mrSulu on the bridge
			mrSulu(urlToCall);

		}

		//With the logic of Spock, we can determine if the fields filled out in the form are okay or not.
		//Basically, this tests for acceptable data entered into the form field. If not, it will update the "feedback" tag right above the form, so the user can read it and act accordingly. Live long and prosper!

		else{

			if((elMovie.value === "Movie" || !elMovie.value) && (isNaN(parseInt(elYear.value)) || typeof parseInt(elYear.value) !== "number" || 2016 < parseInt(elYear.value) || parseInt(elYear.value) < 1890)){
				//clear the feedback paragraph
				get("feedback").innerHTML = "";
				//update with error
				domMan("p", tNode("Valid movie title and year required"), get("feedback"));
				get("movie").focus();

			}

			else if(isNaN(parseInt(elYear.value)) || typeof parseInt(elYear.value) !== "number" || 2016 < parseInt(elYear.value) || parseInt(elYear.value) < 1890){
				//clear the feedback paragraph
				get("feedback").innerHTML = "";
				//update with error
				domMan("p", tNode("Please enter valid year between 1890 and 2015"), get("feedback"));
				get("year").focus();
			}

			else{
				//clear the feedback paragraph
				get("feedback").innerHTML = "";
				//update with error
				domMan("p", tNode("Movie title required"), get("feedback"));
				get("movie").focus();
			}
		}
	}
};

//In this function, we'll take the target and display the film's contents, along with highlighting the film selected (by changing the CSS class)
function getFilmInfo(e){
	var target = e.target;

	//resetting any element that was previously highlighted

	var highlighted = document.querySelectorAll(".highlight");
		for(var i = 0; i<highlighted.length;i++){
			highlighted[i].className = "noHighlighted";
		}

	//check to see if the user has selected a movie image (instead of the loading .gif image)

	if(e.target.nodeName === "IMG" && e.target.id !== "loading"){
		var movieNumber = parseInt(target.id.split("poster")[1]);
		e.target.className = "highlight";
		get("movieFacts").innerHTML = "
\""+data.filmData[movieNumber]["Title"]
		+ "\"

"+data.filmData[movieNumber]["Year"]+"

"
		+data.filmData[movieNumber]["Plot"]+"
<button id=\"deleteMovie\" onclick=\"cancelFilm(this)\">Remove</button>";
	}
	else if(target.id === "plot"){
		return null;
	}
	else{
		get("movieFacts").innerHTML = "";
	}
}

function deleteArrEl(array, position){
	var front = array.slice(0,position);
	var back = array.slice(position + 1, array.length);

	return front.concat(back);
}

// this function needs to do a few things. First, we need to basically undo
// a call to mrSulu; reverting the changes back to whatever they were before
// the call. Second, we need to

function cancelFilm(e){
	var target = e.target;
	log(e.target);
	// Checking data.genStory to see if we're still free to generate a story (the default value is true)
	if(data.genStory){
			//change the add button to "add"

			get("movieInput").style.display = "inline";
			//we want to erase the instructions too, but to keep things from changing
			// too much, we want to keep the same space it took up and just have it invisible
			get("instructions").style.display = "inline";

			elButton.value = "Add";
			elYear.value = "2003";
			elMovie.value = "The Lord of the Rings: The Return of the King";
			get('option').style.display = "inline";

			//delete the figure passed through
			get("film1").parentNode.removeChild(get("film1"));
			get("generator").id = "adder";

			data.filmData = deleteArrEl(data.filmData, 1);

			//rename the ID's of the other elements
			//rename the ID's of their child nodes ()
			resetFilmNumbers();
	}
}

function resetFilmNumbers(){
	var figuratives = tagger("figure");
	for(var i = 0; i < figuratives.length; i++){
		figuratives[i].id = "film" + i.toString();
		figuratives[i].childNodes[0].id = "poster" + i.toString();
	}
}

<commit_msg>Add button on three films, discover 'incomplete' wipe of mrSulu when clicking 'remove' button (bug name:'Saruman')<commit_after>function log (display) {
	return console.log(display);
}

function get(x){
	return document.getElementById(x);
}

function tagger(tag) {
	return document.getElementsByTagName(tag);
}

function classer(classy) {
	return document.getElementsByClassName(classy);
}

function create(el) {
	return document.createElement(el);
}

function tNode(text) {
	return document.createTextNode(text);
}

function makeImage(imgLink, imageId){
	return '';
}

function removeEl(elId){
	get(elID).parentNode.removeChild(get(elID));
}

//This is a function that will help us manipulate the DOM, while adding in a callback if we need some extra functionality
function domMan(elType, text, position, callback){
	var newEl = create(elType);
	var textInfo = text;
	newEl.appendChild(text);
	position.appendChild(newEl);

	if(callback !== undefined){
		callback(newEl);
	}
}

function updateFilmTable(filmResponse){

	//Getting the poster link to display...
	var posterLink = filmResponse.Poster;

	//Making sure the film came through
	if(filmResponse.Response === "True"){
		//we'll define a helpful variable to reference the move number we're working with
		var filmNumber = (data.filmData.length).toString();

		//This will add in the poster to our site. Pretty!
		domMan("figure", tNode(""), get('posterSection'), function(){
			//this callback function updates what would normally be a simple text node into an image of the film poster
			var number = get("posterSection").childNodes.length - 1;
			get("posterSection").childNodes[number].innerHTML = makeImage(filmResponse.Poster, "poster"+filmNumber);
		});

		get("poster"+filmNumber).parentNode.id = "film"+filmNumber;
		get("poster"+filmNumber).parentNode.class = "films";

	}

	/*else if(get("feedback").childNodes[1] === undefined){
		domMan("p", tNode("Hmm. We weren't able to find that film in the database... is there another that you like?"), get("feedback"), function(){
		});
		console.log(filmData);
		filmData.shift();
	}*/
}

function postMovie(e){

	//Get the 'target'; the element that the user clicks on
	resetFilmNumbers();
	var target = e.target;

	if(target.id === "generator" && data.genStory){
		data.dark = ageApp(data.filmData);
		explode();
		get("theButton").innerHTML = ""; // = false;
	}

	else if(target.id === "adder"){

		var yearInt = parseInt(elYear.value);

		if(elMovie.value !== "Movie" && elMovie.value && elYear.value !== "Year" && 2016 > yearInt && yearInt > 1890){

			var movieTitle = elMovie.value;
			var year = elYear.value;

			var urlToCall = urlBuild(titleSmoother(movieTitle), year);

			//mrSulu on the bridge
			mrSulu(urlToCall);

		}

		//With the logic of Spock, we can determine if the fields filled out in the form are okay or not.
		//Basically, this tests for acceptable data entered into the form field. If not, it will update the "feedback" tag right above the form, so the user can read it and act accordingly. Live long and prosper!

		else{

			if((elMovie.value === "Movie" || !elMovie.value) && (isNaN(parseInt(elYear.value)) || typeof parseInt(elYear.value) !== "number" || 2016 < parseInt(elYear.value) || parseInt(elYear.value) < 1890)){
				//clear the feedback paragraph
				get("feedback").innerHTML = "";
				//update with error
				domMan("p", tNode("Valid movie title and year required"), get("feedback"));
				get("movie").focus();

			}

			else if(isNaN(parseInt(elYear.value)) || typeof parseInt(elYear.value) !== "number" || 2016 < parseInt(elYear.value) || parseInt(elYear.value) < 1890){
				//clear the feedback paragraph
				get("feedback").innerHTML = "";
				//update with error
				domMan("p", tNode("Please enter valid year between 1890 and 2015"), get("feedback"));
				get("year").focus();
			}

			else{
				//clear the feedback paragraph
				get("feedback").innerHTML = "";
				//update with error
				domMan("p", tNode("Movie title required"), get("feedback"));
				get("movie").focus();
			}
		}
	}
};

//In this function, we'll take the target and display the film's contents, along with highlighting the film selected (by changing the CSS class)
function getFilmInfo(e){
	var target = e.target;

	//resetting any element that was previously highlighted

	var highlighted = document.querySelectorAll(".highlight");
		for(var i = 0; i<highlighted.length;i++){
			highlighted[i].className = "noHighlighted";
		}

	//check to see if the user has selected a movie image (instead of the loading .gif image)

	if(e.target.nodeName === "IMG" && e.target.id !== "loading"){
		var movieNumber = parseInt(target.id.split("poster")[1]);
		e.target.className = "highlight";
		log(movieNumber, typeof movieNumber);
		get("movieFacts").innerHTML = "
\""+data.filmData[movieNumber]["Title"]
		+ "\"

"+data.filmData[movieNumber]["Year"]+"

"
		+data.filmData[movieNumber]["Plot"]+"
<button id=\"deleteMovie\" onclick=\"cancelFilm(["+movieNumber+"])\">Remove</button>";
	}
	else if(target.id === "plot"){
		return null;
	}
	else{
		get("movieFacts").innerHTML = "";
	}
}

function deleteArrEl(array, position){
	var front = array.slice(0,position);
	var back = array.slice(position + 1, array.length);

	return front.concat(back);
}

// this function needs to do a few things. First, we need to basically undo
// a call to mrSulu; reverting the changes back to whatever they were before
// the call. Second, we need to

function cancelFilm(movieNumber){
	// Checking data.genStory to see if we're still free to generate a story (the default value is true)
	if(data.genStory){
			//change the add button to "add"

			get("movieInput").style.display = "inline";
			//we want to erase the instructions too, but to keep things from changing
			// too much, we want to keep the same space it took up and just have it invisible
			get("instructions").style.display = "inline";

			elButton.value = "Add";
			elYear.value = "2003";
			elMovie.value = "The Lord of the Rings: The Return of the King";
			get('option').style.display = "inline";

			//delete the figure passed through
			get("film1").parentNode.removeChild(get("film"+movieNumber.toString()));
			get("generator").id = "adder";

			data.filmData = deleteArrEl(data.filmData, movieNumber);

			//rename the ID's of the other elements
			//rename the ID's of their child nodes ()
			resetFilmNumbers();
	}
}

function resetFilmNumbers(){
	var figuratives = tagger("figure");
	for(var i = 0; i < figuratives.length; i++){
		figuratives[i].id = "film" + i.toString();
		figuratives[i].childNodes[0].id = "poster" + i.toString();
	}
}

<|endoftext|>


<commit_before>var tinycolor = require("tinycolor2"),
    helper;

function parseRgb(rgb, type) {
    switch(type) {
        case "object":
            var re,
                tmp = helper.trimRgb(rgb);
            if (rgb.indexOf(",") > -1) {
                tmp = tmp.split(",");
            } else {
                tmp = tmp.split(" ");
            }
            return {
                r: tmp[0],
                g: tmp[1],
                b: tmp[2]
            };
            break;
        case "string":
            return rgb.r + "," + rgb.g + "," + rgb.b;
            break;
    }
};

function parseDecimal(dec) {
    if (dec > 1) {
        return Math.round(dec.toFixed(2));
    } else {
        return Math.round((dec.toFixed(2)) * 100);
    }
};

function objectifyHsl(data) {
    return {
        h: data.hue,
        s: data.saturation,
        l: data.lightness
    };
};

function convertRgb(data) {
    var rgb = parseRgb(data.rgb, "object");
    return {
        "rgb": parseRgb(rgb, "string"),
        "hex": tinycolor(rgb).toHex(),
        "hue": parseDecimal(tinycolor(rgb).toHsl()["h"]),
        "saturation": parseDecimal(tinycolor(rgb).toHsl()["s"]),
        "lightness": parseDecimal(tinycolor(rgb).toHsl()["l"]),
        "theme": tinycolor(rgb).isDark() ? "light" : "dark",
        "bgColour": tinycolor(rgb).toHex()
    };
};

function convertHex(data) {
    return {
        "rgb": parseRgb(tinycolor(data.hex).toRgb(), "string"),
        "hex": data.hex,
        "hue": parseDecimal(tinycolor(data.hex).toHsl()["h"]),
        "saturation": parseDecimal(tinycolor(data.hex).toHsl()["s"]),
        "lightness": parseDecimal(tinycolor(data.hex).toHsl()["l"]),
        "theme": tinycolor(data.hex).isDark() ? "light" : "dark",
        "bgColour": data.hex
    };
}

function convertHsl(data) {
    var hsl = objectifyHsl(data);
    return {
        "rgb": parseRgb(tinycolor(hsl).toRgb(), "string"),
        "hex": tinycolor(hsl).toHex(),
        "hue": data.hue,
        "saturation": data.saturation,
        "lightness": data.lightness,
        "theme": tinycolor(hsl).isDark() ? "light" : "dark",
        "bgColour": tinycolor(hsl).toHex()
    };
};

var helper = {

    validateRgb: function(rgb) {
        return rgb.match(/^(\d+\,\s*\d+\,\s*\d+)$|^(\s*\d{1,3}\s\d{1,3}\s\d{1,3})$/gim) !== null;
    },

    validateHex: function(hex) {
        if (hex.length === 3 || hex.length === 6) {
            return true;
        }
        return false;
    },

    validateColours: function(colour) {
        switch (colour.type) {
            case "rgb":
                return helper.validateRgb(colour.rgb);
                break;
            case "hex":
                return helper.validateHex(colour.hex);
                break;
            default:
                // hsl values will default
                return true;
        }
    },

    trimRgb: function(colour) {
        var tmp = JSON.stringify(colour).replace(/[^\w\s\,\.]|[rgb]/g, "");
        if (tmp.substring(0, 1) === " ") {
            tmp = tmp.substring(1);
        }
        /*
        * Needs to validate and set max on rgb value
        **/

        // if (tmp.length >= 10) {
        //     return tmp.substring(0, 9);
        // } else {
            return tmp;
        // }
    },

    trimHex: function(colour) {
        var tmp = JSON.stringify(colour).replace(/[^a-fA-F0-9\s]/g, "");
        if (tmp.substring(0, 1) === "#") {
            tmp = tmp.substring(1);
        }
        if (tmp.length >= 7) {
            return tmp.substring(0, 6);
        } else {
            return tmp;
        }
    },

    convertColours: function(data) {
        switch(data.type) {
            case 'rgb':
                return convertRgb(data);
                break;
            case 'hex':
                return convertHex(data);
                break;
            case 'hue':
            case 'saturation':
            case 'lightness':
                return convertHsl(data);
                break;
        }
    }

};
module.exports = helper;
<commit_msg>:package: converted to es6 and fixed max length for RGB<commit_after>const tinycolor = require("tinycolor2");
const helper;

parseRgb(rgb, type) => {
    switch(type) {
        case "object":
            var re,
                tmp = helper.trimRgb(rgb);
            if (rgb.indexOf(",") > -1) {
                tmp = tmp.split(",");
            } else {
                tmp = tmp.split(" ");
            }
            return {
                r: tmp[0],
                g: tmp[1],
                b: tmp[2]
            };
            break;
        case "string":
            return rgb.r + "," + rgb.g + "," + rgb.b;
            break;
    }
};

parseDecimal(dec) => {
    if (dec > 1) {
        return Math.round(dec.toFixed(2));
    } else {
        return Math.round((dec.toFixed(2)) * 100);
    }
};

objectifyHsl(data) => {
    return {
        h: data.hue,
        s: data.saturation,
        l: data.lightness
    };
};

convertRgb(data) => {
    let rgb = parseRgb(data.rgb, "object");
    return {
        "rgb": parseRgb(rgb, "string"),
        "hex": tinycolor(rgb).toHex(),
        "hue": parseDecimal(tinycolor(rgb).toHsl()["h"]),
        "saturation": parseDecimal(tinycolor(rgb).toHsl()["s"]),
        "lightness": parseDecimal(tinycolor(rgb).toHsl()["l"]),
        "theme": tinycolor(rgb).isDark() ? "light" : "dark",
        "bgColour": tinycolor(rgb).toHex()
    };
};

convertHex(data) => {
    return {
        "rgb": parseRgb(tinycolor(data.hex).toRgb(), "string"),
        "hex": data.hex,
        "hue": parseDecimal(tinycolor(data.hex).toHsl()["h"]),
        "saturation": parseDecimal(tinycolor(data.hex).toHsl()["s"]),
        "lightness": parseDecimal(tinycolor(data.hex).toHsl()["l"]),
        "theme": tinycolor(data.hex).isDark() ? "light" : "dark",
        "bgColour": data.hex
    };
}

convertHsl(data) => {
    let hsl = objectifyHsl(data);
    return {
        "rgb": parseRgb(tinycolor(hsl).toRgb(), "string"),
        "hex": tinycolor(hsl).toHex(),
        "hue": data.hue,
        "saturation": data.saturation,
        "lightness": data.lightness,
        "theme": tinycolor(hsl).isDark() ? "light" : "dark",
        "bgColour": tinycolor(hsl).toHex()
    };
};

helper = {

    validateRgb: (rgb) => {
        return rgb.match(/^(\d+\,\s*\d+\,\s*\d+)$|^(\s*\d{1,3}\s\d{1,3}\s\d{1,3})$/gim) !== null;
    },

    validateHex: (hex) => {
        if (hex.length === 3 || hex.length === 6) {
            return true;
        }
        return false;
    },

    validateColours: (colour) => {
        switch (colour.type) {
            case "rgb":
                return helper.validateRgb(colour.rgb);
                break;
            case "hex":
                return helper.validateHex(colour.hex);
                break;
            default:
                // hsl values will default
                return true;
        }
    },

    trimRgb: (colour) => {
        let tmp = JSON.stringify(colour).replace(/[^\w\s\,\.]|[rgb]/g, "");
        let count = 0;
        if (tmp.substring(0, 1) === " ") {
            tmp = tmp.substring(1);
        }
        count = JSON.stringify(colour).replace(/,/g, "").length;

        if (count >= 10) {
            return tmp.substring(0, 9);
        } else {
            return tmp;
        }
    },

    trimHex: (colour) => {
        let tmp = JSON.stringify(colour).replace(/[^a-fA-F0-9\s]/g, "");
        if (tmp.substring(0, 1) === "#") {
            tmp = tmp.substring(1);
        }
        if (tmp.length >= 7) {
            return tmp.substring(0, 6);
        } else {
            return tmp;
        }
    },

    convertColours: (data) => {
        switch(data.type) {
            case 'rgb':
                return convertRgb(data);
                break;
            case 'hex':
                return convertHex(data);
                break;
            case 'hue':
            case 'saturation':
            case 'lightness':
                return convertHsl(data);
                break;
        }
    }

};
module.exports = helper;
<|endoftext|>