<commit_before>$(document).ready(function(){
  setTimeout(function(){
    $('.results-table h4').each(function(i){
      function getText(file,self) {
        $.ajax({
          url : file,
          context: self,
          dataType: "text",
          success : function (data) {
            self.parent().find(".text").html(data);
          }
        })
      }
      if ($(this).html().includes('User Agent')) {
        var filename = '/static/results-text/user-agent.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('HTTP_ACCEPT Headers')) {
        var filename = '/static/results-text/http-accept-headers.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Browser Plugin')) {
        var filename = '/static/results-text/browser-plugin-details.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('AudioContext')) {
        var filename = '/static/results-text/audiocontext.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Cookies Enabled')) {
        var filename = '/static/results-text/cookies-enabled.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Device Memory')) {
        var filename = '/static/results-text/device-memory.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('DNT Header')) {
        var filename = '/static/results-text/dnt-header.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Hardware Concurrency')) {
        var filename = '/static/results-text/hardware-concurrency.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Hash of canvas fingerprint')) {
        var filename = '/static/results-text/hash-of-canvas.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Hash of WebGL fingerprint')) {
        var filename = '/static/results-text/hash-of-webgl.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Limited supercookie ')) {
        var filename = '/static/results-text/limited-super-cookie.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Platform')) {
        var filename = '/static/results-text/platform.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Screen Size')) {
        var filename = '/static/results-text/screen-size.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('System Fonts')) {
        var filename = '/static/results-text/system-fonts.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Time Zone')) {
        var filename = '/static/results-text/time-zone.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Time Zone Offset')) {
        var filename = '/static/results-text/time-zone-offset.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Touch Support')) {
        var filename = '/static/results-text/touch-support.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('User Agent')) {
        var filename = '/static/results-text/user-agent.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('WebGL Vendor')) {
        var filename = '/static/results-text/webgl-vendor.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
    });
    $('.detailed').hide();
    $('#default-button').addClass('active');
    $('#default-button').on( 'click', function(e) {
      $('#default-button').addClass('active');
      $('#detailed-button').removeClass('active');
      $('.detailed').hide();
    });
    $('#detailed-button').on( 'click', function(e) {
      $('#detailed-button').addClass('active');
      $('#default-button').removeClass('active');
      $('.detailed').show();
    });
    $('select').selectmenu();  // select which characteristic to go to
    $('#characteristic').on('selectmenuchange', function() {
    var char = $( "#characteristic option:selected" ).text();
    window.location.href = '#'+ char;
});
  }, 2000);

});
<commit_msg>results dropdown now scrolls into view correctly<commit_after>$(document).ready(function(){
  setTimeout(function(){
    $('.results-table h4').each(function(i){
      function getText(file,self) {
        $.ajax({
          url : file,
          context: self,
          dataType: "text",
          success : function (data) {
            self.parent().find(".text").html(data);
          }
        })
      }
      if ($(this).html().includes('User Agent')) {
        var filename = '/static/results-text/user-agent.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('HTTP_ACCEPT Headers')) {
        var filename = '/static/results-text/http-accept-headers.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Browser Plugin')) {
        var filename = '/static/results-text/browser-plugin-details.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('AudioContext')) {
        var filename = '/static/results-text/audiocontext.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Cookies Enabled')) {
        var filename = '/static/results-text/cookies-enabled.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Device Memory')) {
        var filename = '/static/results-text/device-memory.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('DNT Header')) {
        var filename = '/static/results-text/dnt-header.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Hardware Concurrency')) {
        var filename = '/static/results-text/hardware-concurrency.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Hash of canvas fingerprint')) {
        var filename = '/static/results-text/hash-of-canvas.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Hash of WebGL fingerprint')) {
        var filename = '/static/results-text/hash-of-webgl.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Limited supercookie ')) {
        var filename = '/static/results-text/limited-super-cookie.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Platform')) {
        var filename = '/static/results-text/platform.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Screen Size')) {
        var filename = '/static/results-text/screen-size.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('System Fonts')) {
        var filename = '/static/results-text/system-fonts.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Time Zone')) {
        var filename = '/static/results-text/time-zone.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Time Zone Offset')) {
        var filename = '/static/results-text/time-zone-offset.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('Touch Support')) {
        var filename = '/static/results-text/touch-support.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('User Agent')) {
        var filename = '/static/results-text/user-agent.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
      if ($(this).html().includes('WebGL Vendor')) {
        var filename = '/static/results-text/webgl-vendor.txt';
        var selfname = $(this);
        getText(filename, selfname);
      }
    });
    $('.detailed').hide();
    $('#default-button').addClass('active');
    $('#default-button').on( 'click', function(e) {
      $('#default-button').addClass('active');
      $('#detailed-button').removeClass('active');
      $('.detailed').hide();
    });
    $('#detailed-button').on( 'click', function(e) {
      $('#detailed-button').addClass('active');
      $('#default-button').removeClass('active');
      $('.detailed').show();
    });
    $('select').selectmenu();  // select which characteristic to go to
    $('#characteristic').on('selectmenuchange', function() {
      var char = $( "#characteristic option:selected" ).text();
      console.log(char);
      charId = document.getElementById(char);
      var $char = $(charId);
      $('html,body').animate({scrollTop: $char.offset().top-80},'slow');
    });
  }, 2000);

});
<|endoftext|>


<commit_before>define(
    [ "core/entity" ],
    function( Entity ) {
      return function() {

        module( "Entity", {
          setup: function() {},
          teardown: function() {}
        });

        test( "create a new entity without parameters", function() {
          expect( 5 );

          var entity = new Entity();
          ok( entity.hasOwnProperty( "id" ), "has an id" );
          equal( entity.size, 0, "no components" );
          equal( entity.tags.length, 0, "no tags" );
          equal( entity.parent, null, "no parent" );
          equal( entity.space, null, "no space" );
        });

        test( "create a new entity with a name", function() {
          expect( 1 );

          var entity = new Entity( "MyEntity" );
          equal( entity.name, "MyEntity", "name is correct" );
        });

        test( "create a new entity with some tags", function() {
          expect( 3 );

          var entity = new Entity( "MyEntity", [], ["Tag1", "Tag2"] );
          equal( entity.tags.length, 2, "correct number of tags" );
          ok( entity.tags.indexOf( "Tag1" ) >= 0, "tag is present" );
          ok( entity.tags.indexOf( "Tag2" ) >= 0, "tag is present" );
        });

        test( "create a new entity with a parent", function() {
          expect( 1 );

          var entity = new Entity( "MyEntity", [], [], 123 );
          equal( entity.parent, 123, "parent is correct" );
        });

        test( "create a new entity with some components", function() {
          expect( 2 );

          var component1 = {
              type: "Component1",
              dependsOn: [],
              setOwner: function() {}
          };
          var component2 = {
              type: "Component2",
              dependsOn: ["Component1"],
              setOwner: function() {}
          };

          var entity = new Entity( "MyEntity", [component1, component2] );
          ok( entity.hasComponent( "Component1" ), "has component" );
          ok( entity.hasComponent( "Component2" ), "has component" );
        });

        test( "create a new entity with broken dependencies", function() {
          expect( 1 );

          var component1 = {
              type: "Component1",
              dependsOn: [],
              setOwner: function() {}
          };
          var component2 = {
              type: "Component2",
              dependsOn: ["Component1"],
              setOwner: function() {}
          };

          raises( function() {
            var entity = new Entity( "MyEntity", [component2, component1] );
          }, Error, "exception thrown for broken dependency" );
        });

      };
    }
);<commit_msg>Added part of add component test for entity<commit_after>define(
    [ "core/entity" ],
    function( Entity ) {
      return function() {

        module( "Entity", {
          setup: function() {},
          teardown: function() {}
        });

        test( "create a new entity without parameters", function() {
          expect( 5 );

          var entity = new Entity();
          ok( entity.hasOwnProperty( "id" ), "has an id" );
          equal( entity.size, 0, "no components" );
          equal( entity.tags.length, 0, "no tags" );
          equal( entity.parent, null, "no parent" );
          equal( entity.space, null, "no space" );
        });

        test( "create a new entity with a name", function() {
          expect( 1 );

          var entity = new Entity( "MyEntity" );
          equal( entity.name, "MyEntity", "name is correct" );
        });

        test( "create a new entity with some tags", function() {
          expect( 3 );

          var entity = new Entity( "MyEntity", [], ["Tag1", "Tag2"] );
          equal( entity.tags.length, 2, "correct number of tags" );
          ok( entity.tags.indexOf( "Tag1" ) >= 0, "tag is present" );
          ok( entity.tags.indexOf( "Tag2" ) >= 0, "tag is present" );
        });

        test( "create a new entity with a parent", function() {
          expect( 1 );

          var entity = new Entity( "MyEntity", [], [], 123 );
          equal( entity.parent, 123, "parent is correct" );
        });

        test( "create a new entity with some components", function() {
          expect( 2 );

          var component1 = {
              type: "Component1",
              dependsOn: [],
              setOwner: function() {}
          };
          var component2 = {
              type: "Component2",
              dependsOn: ["Component1"],
              setOwner: function() {}
          };

          var entity = new Entity( "MyEntity", [component1, component2] );
          ok( entity.hasComponent( "Component1" ), "has component" );
          ok( entity.hasComponent( "Component2" ), "has component" );
        });

        test( "create a new entity with broken dependencies", function() {
          expect( 1 );

          var component1 = {
              type: "Component1",
              dependsOn: [],
              setOwner: function() {}
          };
          var component2 = {
              type: "Component2",
              dependsOn: ["Component1"],
              setOwner: function() {}
          };

          raises( function() {
            var entity = new Entity( "MyEntity", [component2, component1] );
          }, Error, "exception thrown for broken dependency" );
        });

        test("addComponent adds a component successfully", function(){
          expect( 4 );

          var entity = new Entity( "MyEntity", [] );
          entity.addComponent(
          {
            type: "Component1",
            dependsOn: [],
            setOwner: function() {ok(true, "setOwner was called");}
          });
          ok("Component1" in entity._components, "component was added");
          equals(entity.size, 1, "size was incremented");

          //check that an event was sent
        });

//        function onChildEntityRemoved( event )
//        onChildEntityAdded
//        handleEvent
//        hasComponent
//        setActive
//        setSpace
//        setParent
//        findComponent
      };
    }
);<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc service
 * @name voyager.visrec
 * @description
 * # visrec
 * Service in the voyager.
 */
angular.module('voyager')
  .service('Visrec', function (cp, vl, _, consts, Config, Dataset, Logger, Fields) {
    var Visrec = {
      /**
       * List of all recommended projections based on the selection.
       * Array of fieldSet (Array of Field without transformation)
       * projections = [ fieldSet (without aggregate) ]
       */
      projections: [],

      /**
       * Dictionary: projection key => a list of aggregated table
       * aggregates[pkey] = [ fieldSet (with aggregate) ]
       */
      aggregates: {},

      /**
       * Dictionary: field set key (fields of an aggregated table)  => list of fieldSets
       * fieldSetDict[fieldSetKey] = fieldSet
       */
      fieldSetDict: {},

      /**
       * ordered list of field sets
       */
      fieldSets: [],

      /**
       * ordered list of field set keys
       */
      fieldSetKeys: [],

      /**
       * Clustered Encoding variations of each field set
       *
       * Dictionary: field set key => list of list of spec
       * encodings[fieldSetkey] = [[ (vlSpec, vgSpec) ,...], ...]
       */
      chartClusters: {},
      numClustersGenerated: 0,

      selectedCluster: null,
      selectedFieldSet: null,
      update: {}
    };

    // Visrec Config

    var exactMatchOpt = {
      genTypeCasting: false,
    };

    var initOpt = {
      genTypeCasting: false,
      maxCardinalityForAutoAddOrdinal: null,
      omitDotPlot: true
    };

    var suggestionOpt = {
      genTypeCasting: false,
      // addCountForDimensionOnly: false
    };

    Visrec.update.projections = function(fieldList) {
      var start = new Date().getTime();
      // TODO decide if we can update projections only if field name list changes

      // First create a projection

      var projections = cp.gen.projections(fieldList, Dataset.stats,
        {} || (Fields.selected.length === 0 ? initOpt : suggestionOpt));

      var aggregates = {}, fieldSetDict = {},
        fieldSets = [], chartClusters = {};

      var endProjection = new Date().getTime();

      // For each projection, get different aggregations (fieldSetDict)
      projections.forEach(function(projection) {
        var pkey = projection.key;
        var isExactMatch = pkey === Fields.selectedPKey;
        var opt =  isExactMatch ? exactMatchOpt :  Fields.selected.length === 0 ? initOpt : suggestionOpt;

        aggregates[pkey] = cp.gen.aggregates([], projection, Dataset.stats, opt);

        aggregates[pkey].forEach(function(fieldSet) {
          fieldSetDict[fieldSet.key] = fieldSet;
          fieldSet.isExactMatch = isExactMatch;
          fieldSets.push(fieldSet);
        });
      });

      // TODO rank fieldSets here!

      var endAggregates = new Date().getTime();

      Visrec.numClustersGenerated = Math.min(consts.numInitClusters, fieldSets.length);
      for(var i=0; i< Visrec.numClustersGenerated; i++) {
        var fieldSet = fieldSets[i];
        chartClusters[fieldSet.key] = genClusters(fieldSet);
      }

      Visrec.projections = projections;
      Visrec.aggregates = aggregates;
      Visrec.fieldSetDict = fieldSetDict;
      Visrec.fieldSets = fieldSets;
      Visrec.chartClusters = chartClusters;

      var end = new Date().getTime();

      var selectedFields = fieldList.filter(function(f) {
        return f.selected;
      });

      console.log('gen time – projections ', vl.field.shorthands(selectedFields), ' :', (endProjection-start), 'aggregates:', (endAggregates - endProjection), 'encodings:'+ (end-endAggregates), 'total:', (end-start));
    };

    Visrec.update.clusters = function(limit) {
      if (limit > Visrec.numClustersGenerated) {

        var fieldSets = Visrec.fieldSets,
          oldnum = Visrec.numClustersGenerated,
          chartClusters = Visrec.chartClusters;

        limit = Math.min(limit, fieldSets.length);

        for (var i=oldnum; i< limit ; i++) {
          var fieldSet = fieldSets[i];
          chartClusters[fieldSet.key] = genClusters(fieldSet);
        }

        Visrec.numClustersGenerated = limit;
      }
    };

    function genClusters(fieldSet) {
      var encodings = cp.gen.encodings([], fieldSet, Dataset.stats, {
        data: Config.getData(),
        config: Config.getConfig()
      });

      var clusters = cp.cluster(encodings)
        .map(function(cluster) {
          return cluster.map(function(spec) {
            // auto sort
            spec = _.cloneDeep(spec);
            vl.Encoding.toggleSort(spec);

            var encoding = vl.Encoding.fromSpec(spec, {});

            return {
              fieldSetKey: fieldSet.key,
              fieldSet: fieldSet,
              vlSpec: spec,
              encoding: encoding,
              shorthand: encoding.toShorthand(),
              score: spec.score,
              scoreFeatures: spec.scoreFeatures
            };
          });
        });

      clusters.key = fieldSet.key;
      return clusters;
    }

    return Visrec;
  });
<commit_msg>Turn off sorting by default<commit_after>'use strict';

/**
 * @ngdoc service
 * @name voyager.visrec
 * @description
 * # visrec
 * Service in the voyager.
 */
angular.module('voyager')
  .service('Visrec', function (cp, vl, _, consts, Config, Dataset, Logger, Fields) {
    var Visrec = {
      /**
       * List of all recommended projections based on the selection.
       * Array of fieldSet (Array of Field without transformation)
       * projections = [ fieldSet (without aggregate) ]
       */
      projections: [],

      /**
       * Dictionary: projection key => a list of aggregated table
       * aggregates[pkey] = [ fieldSet (with aggregate) ]
       */
      aggregates: {},

      /**
       * Dictionary: field set key (fields of an aggregated table)  => list of fieldSets
       * fieldSetDict[fieldSetKey] = fieldSet
       */
      fieldSetDict: {},

      /**
       * ordered list of field sets
       */
      fieldSets: [],

      /**
       * ordered list of field set keys
       */
      fieldSetKeys: [],

      /**
       * Clustered Encoding variations of each field set
       *
       * Dictionary: field set key => list of list of spec
       * encodings[fieldSetkey] = [[ (vlSpec, vgSpec) ,...], ...]
       */
      chartClusters: {},
      numClustersGenerated: 0,

      selectedCluster: null,
      selectedFieldSet: null,
      update: {}
    };

    // Visrec Config

    var exactMatchOpt = {
      genTypeCasting: false,
    };

    var initOpt = {
      genTypeCasting: false,
      maxCardinalityForAutoAddOrdinal: null,
      omitDotPlot: true
    };

    var suggestionOpt = {
      genTypeCasting: false,
      // addCountForDimensionOnly: false
    };

    Visrec.update.projections = function(fieldList) {
      var start = new Date().getTime();
      // TODO decide if we can update projections only if field name list changes

      // First create a projection

      var projections = cp.gen.projections(fieldList, Dataset.stats,
        {} || (Fields.selected.length === 0 ? initOpt : suggestionOpt));

      var aggregates = {}, fieldSetDict = {},
        fieldSets = [], chartClusters = {};

      var endProjection = new Date().getTime();

      // For each projection, get different aggregations (fieldSetDict)
      projections.forEach(function(projection) {
        var pkey = projection.key;
        var isExactMatch = pkey === Fields.selectedPKey;
        var opt =  isExactMatch ? exactMatchOpt :  Fields.selected.length === 0 ? initOpt : suggestionOpt;

        aggregates[pkey] = cp.gen.aggregates([], projection, Dataset.stats, opt);

        aggregates[pkey].forEach(function(fieldSet) {
          fieldSetDict[fieldSet.key] = fieldSet;
          fieldSet.isExactMatch = isExactMatch;
          fieldSets.push(fieldSet);
        });
      });

      // TODO rank fieldSets here!

      var endAggregates = new Date().getTime();

      Visrec.numClustersGenerated = Math.min(consts.numInitClusters, fieldSets.length);
      for(var i=0; i< Visrec.numClustersGenerated; i++) {
        var fieldSet = fieldSets[i];
        chartClusters[fieldSet.key] = genClusters(fieldSet);
      }

      Visrec.projections = projections;
      Visrec.aggregates = aggregates;
      Visrec.fieldSetDict = fieldSetDict;
      Visrec.fieldSets = fieldSets;
      Visrec.chartClusters = chartClusters;

      var end = new Date().getTime();

      var selectedFields = fieldList.filter(function(f) {
        return f.selected;
      });

      console.log('gen time – projections ', vl.field.shorthands(selectedFields), ' :', (endProjection-start), 'aggregates:', (endAggregates - endProjection), 'encodings:'+ (end-endAggregates), 'total:', (end-start));
    };

    Visrec.update.clusters = function(limit) {
      if (limit > Visrec.numClustersGenerated) {

        var fieldSets = Visrec.fieldSets,
          oldnum = Visrec.numClustersGenerated,
          chartClusters = Visrec.chartClusters;

        limit = Math.min(limit, fieldSets.length);

        for (var i=oldnum; i< limit ; i++) {
          var fieldSet = fieldSets[i];
          chartClusters[fieldSet.key] = genClusters(fieldSet);
        }

        Visrec.numClustersGenerated = limit;
      }
    };

    function genClusters(fieldSet) {
      var encodings = cp.gen.encodings([], fieldSet, Dataset.stats, {
        data: Config.getData(),
        config: Config.getConfig()
      });

      var clusters = cp.cluster(encodings)
        .map(function(cluster) {
          return cluster.map(function(spec) {
            // auto sort
            spec = _.cloneDeep(spec);
            // vl.Encoding.toggleSort(spec);

            var encoding = vl.Encoding.fromSpec(spec, {});

            return {
              fieldSetKey: fieldSet.key,
              fieldSet: fieldSet,
              vlSpec: spec,
              encoding: encoding,
              shorthand: encoding.toShorthand(),
              score: spec.score,
              scoreFeatures: spec.scoreFeatures
            };
          });
        });

      clusters.key = fieldSet.key;
      return clusters;
    }

    return Visrec;
  });
<|endoftext|>


<commit_before>// PLUGIN: text

(function ( Popcorn ) {

  /**
   * text Popcorn plug-in
   * Based on popcorn.text.js by @humph
   * @param {Object} options
   *
   * Example:

   **/

  var DEFAULT_FONT_COLOR = "#000";

  function newlineToBreak( string ) {
    // Deal with both \r\n and \n
    return string.replace( /\r?\n/gm, "
" );
  }

  Popcorn.plugin( "text", {

    manifest: {
      about: {
        name: "Popcorn text Plugin",
        version: "0.1",
        author: "@k88hudson, @mjschranz"
      },
      options: {
        text: {
          elem: "textarea",
          label: "Text",
          "default": "Popcorn Maker"
        },
        linkUrl: {
          elem: "input",
          type: "url",
          label: "Link URL"
        },
        position: {
          elem: "select",
          options: [ "Center", "Bottom", "Left", "Right", "Top", "Custom" ],
          values: [ "center", "bottom", "left", "right", "top", "custom"  ],
          label: "Text Position",
          "default": "center"
        },
        start: {
          elem: "input",
          type: "text",
          label: "In",
          group: "advanced",
          "units": "seconds"
        },
        end: {
          elem: "input",
          type: "text",
          label: "Out",
          group: "advanced",
          "units": "seconds"
        },
        transition: {
          elem: "select",
          options: [ "None", "Pop", "Fade", "Slide Up", "Slide Down" ],
          values: [ "popcorn-none", "popcorn-pop", "popcorn-fade", "popcorn-slide-up", "popcorn-slide-down" ],
          label: "Transition",
          "default": "popcorn-fade"
        },
        fontFamily: {
          elem: "select",
          label: "Font",
          styleClass: "",
          googleFonts: true,
          group: "advanced",
          "default": "Merriweather"
        },
        fontSize: {
          elem: "input",
          type: "number",
          label: "Font Size",
          "default": 10,
          units: "%",
          group: "advanced"
        },
        fontColor: {
          elem: "input",
          type: "color",
          label: "Font colour",
          "default": DEFAULT_FONT_COLOR,
          group: "advanced"
        },
        fontDecorations: {
          elem: "checkbox-group",
          labels: { bold: "Bold", italics: "Italics", underline: "Underline" },
          "default": { bold: false, italics: false, underline: false },
          group: "advanced"
        },
        left: {
          elem: "input",
          type: "number",
          label: "Left",
          units: "%",
          "default": 25,
          hidden: true
        },
        top: {
          elem: "input",
          type: "number",
          label: "Top",
          units: "%",
          "default": 0,
          hidden: true
        },
        width: {
          elem: "input",
          type: "number",
          units: "%",
          label: "Width",
          "default": 50,
          hidden: true
        },
        zindex: {
          hidden: true
        }
      }
    },

    _setup: function( options ) {

      var target = Popcorn.dom.find( options.target ),
          text = newlineToBreak( options.text ),
          container = options._container = document.createElement( "div" ),
          innerContainer = document.createElement( "div" ),
          innerSpan = document.createElement( "span" ),
          innerDiv = document.createElement( "div" ),
          fontSheet,
          fontDecorations = options.fontDecorations || options._natives.manifest.options.fontDecorations[ "default" ],
          position = options.position || options._natives.manifest.options.position[ "default" ],
          transition = options.transition || options._natives.manifest.options.transition[ "default" ],
          link,
          context = this;

      if ( !target ) {
        target = this.media.parentNode;
      }

      options._target = target;
      container.style.position = "absolute";
      container.classList.add( "popcorn-text" );

      // innerDiv inside innerSpan is to allow zindex from layers to work properly.
      // if you mess with this code, make sure to check for zindex issues.
      innerSpan.appendChild( innerDiv );
      innerContainer.appendChild( innerSpan );
      container.appendChild( innerContainer );
      target.appendChild( container );

      // Add transition class
      options._container.classList.add( transition );
      options._container.classList.add( "off" );

      // Handle all custom fonts/styling

      options.fontColor = options.fontColor || DEFAULT_FONT_COLOR;
      innerContainer.classList.add( "text-inner-div" );
      innerContainer.style.color = options.fontColor;
      innerContainer.style.fontStyle = fontDecorations.italics ? "italic" : "normal";
      innerContainer.style.textDecoration = fontDecorations.underline ? "underline" : "none";
      innerContainer.style.fontWeight = fontDecorations.bold ? "bold" : "normal";

      fontSheet = document.createElement( "link" );
      fontSheet.rel = "stylesheet";
      fontSheet.type = "text/css";
      options.fontFamily = options.fontFamily ? options.fontFamily : options._natives.manifest.options.fontFamily[ "default" ];
      // Store reference to generated sheet for removal later, remove any existing ones
      options._fontSheet = fontSheet;
      document.head.appendChild( fontSheet );

      fontSheet.onload = function ( e ) {
        innerContainer.style.fontFamily = options.fontFamily;
        innerContainer.style.fontSize = options.fontSize + "%";
        if ( position === "custom" ) {
          container.classList.add( "text-custom" );
          container.style.left = options.left + "%";
          container.style.top = options.top + "%";
          if ( options.width ) {
            container.style.width = options.width + "%";
          }
          container.style.zIndex = +options.zindex;
        }
        else {
          container.classList.add( "text-fixed" );
          innerContainer.classList.add( position );
          innerDiv.style.zIndex = +options.zindex;
        }

        if ( options.linkUrl ) {
          link = document.createElement( "a" );
          link.href = options.linkUrl;
          link.target = "_blank";
          link.innerHTML = text;

          link.addEventListener( "click", function( e ) {
            context.media.pause();
          }, false );

          link.style.color = innerContainer.style.color;

          innerDiv.appendChild( link );
        } else {
          innerDiv.innerHTML = text;
        }
      };
      fontSheet.href = "//fonts.googleapis.com/css?family=" + options.fontFamily.replace( /\s/g, "+" );

      options.toString = function() {
        // use the default option if it doesn't exist
        return options.text || options._natives.manifest.options.text[ "default" ];
      };
    },

    start: function( event, options ) {
      if ( options._container ) {
        options._container.classList.add( "on" );
        options._container.classList.remove( "off" );
      }
    },

    end: function( event, options ) {
      if ( options._container ) {
        options._container.classList.add( "off" );
        options._container.classList.remove( "on" );
      }
    },

    _teardown: function( options ) {
      if ( options._target ) {
        options._target.removeChild( options._container );
      }

      if ( options._fontSheet ) {
        document.head.removeChild( options._fontSheet );
      }
    }
  });
}( window.Popcorn ));
<commit_msg>[t2609] Lets load real fonts<commit_after>// PLUGIN: text

(function ( Popcorn ) {

  /**
   * text Popcorn plug-in
   * Based on popcorn.text.js by @humph
   * @param {Object} options
   *
   * Example:

   **/

  var DEFAULT_FONT_COLOR = "#000";

  function newlineToBreak( string ) {
    // Deal with both \r\n and \n
    return string.replace( /\r?\n/gm, "
" );
  }

  Popcorn.plugin( "text", {

    manifest: {
      about: {
        name: "Popcorn text Plugin",
        version: "0.1",
        author: "@k88hudson, @mjschranz"
      },
      options: {
        text: {
          elem: "textarea",
          label: "Text",
          "default": "Popcorn Maker"
        },
        linkUrl: {
          elem: "input",
          type: "url",
          label: "Link URL"
        },
        position: {
          elem: "select",
          options: [ "Center", "Bottom", "Left", "Right", "Top", "Custom" ],
          values: [ "center", "bottom", "left", "right", "top", "custom"  ],
          label: "Text Position",
          "default": "center"
        },
        start: {
          elem: "input",
          type: "text",
          label: "In",
          group: "advanced",
          "units": "seconds"
        },
        end: {
          elem: "input",
          type: "text",
          label: "Out",
          group: "advanced",
          "units": "seconds"
        },
        transition: {
          elem: "select",
          options: [ "None", "Pop", "Fade", "Slide Up", "Slide Down" ],
          values: [ "popcorn-none", "popcorn-pop", "popcorn-fade", "popcorn-slide-up", "popcorn-slide-down" ],
          label: "Transition",
          "default": "popcorn-fade"
        },
        fontFamily: {
          elem: "select",
          label: "Font",
          styleClass: "",
          googleFonts: true,
          group: "advanced",
          "default": "Merriweather"
        },
        fontSize: {
          elem: "input",
          type: "number",
          label: "Font Size",
          "default": 10,
          units: "%",
          group: "advanced"
        },
        fontColor: {
          elem: "input",
          type: "color",
          label: "Font colour",
          "default": DEFAULT_FONT_COLOR,
          group: "advanced"
        },
        fontDecorations: {
          elem: "checkbox-group",
          labels: { bold: "Bold", italics: "Italics", underline: "Underline" },
          "default": { bold: false, italics: false, underline: false },
          group: "advanced"
        },
        left: {
          elem: "input",
          type: "number",
          label: "Left",
          units: "%",
          "default": 25,
          hidden: true
        },
        top: {
          elem: "input",
          type: "number",
          label: "Top",
          units: "%",
          "default": 0,
          hidden: true
        },
        width: {
          elem: "input",
          type: "number",
          units: "%",
          label: "Width",
          "default": 50,
          hidden: true
        },
        zindex: {
          hidden: true
        }
      }
    },

    _setup: function( options ) {

      var target = Popcorn.dom.find( options.target ),
          text = newlineToBreak( options.text ),
          container = options._container = document.createElement( "div" ),
          innerContainer = document.createElement( "div" ),
          innerSpan = document.createElement( "span" ),
          innerDiv = document.createElement( "div" ),
          fontSheet,
          fontDecorations = options.fontDecorations || options._natives.manifest.options.fontDecorations[ "default" ],
          position = options.position || options._natives.manifest.options.position[ "default" ],
          transition = options.transition || options._natives.manifest.options.transition[ "default" ],
          link,
          context = this;

      if ( !target ) {
        target = this.media.parentNode;
      }

      options._target = target;
      container.style.position = "absolute";
      container.classList.add( "popcorn-text" );

      // innerDiv inside innerSpan is to allow zindex from layers to work properly.
      // if you mess with this code, make sure to check for zindex issues.
      innerSpan.appendChild( innerDiv );
      innerContainer.appendChild( innerSpan );
      container.appendChild( innerContainer );
      target.appendChild( container );

      // Add transition class
      options._container.classList.add( transition );
      options._container.classList.add( "off" );

      // Handle all custom fonts/styling

      options.fontColor = options.fontColor || DEFAULT_FONT_COLOR;
      innerContainer.classList.add( "text-inner-div" );
      innerContainer.style.color = options.fontColor;
      innerContainer.style.fontStyle = fontDecorations.italics ? "italic" : "normal";
      innerContainer.style.textDecoration = fontDecorations.underline ? "underline" : "none";
      innerContainer.style.fontWeight = fontDecorations.bold ? "bold" : "normal";

      fontSheet = document.createElement( "link" );
      fontSheet.rel = "stylesheet";
      fontSheet.type = "text/css";
      options.fontFamily = options.fontFamily ? options.fontFamily : options._natives.manifest.options.fontFamily[ "default" ];
      // Store reference to generated sheet for removal later, remove any existing ones
      options._fontSheet = fontSheet;
      document.head.appendChild( fontSheet );

      fontSheet.onload = function ( e ) {
        innerContainer.style.fontFamily = options.fontFamily;
        innerContainer.style.fontSize = options.fontSize + "%";
        if ( position === "custom" ) {
          container.classList.add( "text-custom" );
          container.style.left = options.left + "%";
          container.style.top = options.top + "%";
          if ( options.width ) {
            container.style.width = options.width + "%";
          }
          container.style.zIndex = +options.zindex;
        }
        else {
          container.classList.add( "text-fixed" );
          innerContainer.classList.add( position );
          innerDiv.style.zIndex = +options.zindex;
        }

        if ( options.linkUrl ) {
          link = document.createElement( "a" );
          link.href = options.linkUrl;
          link.target = "_blank";
          link.innerHTML = text;

          link.addEventListener( "click", function( e ) {
            context.media.pause();
          }, false );

          link.style.color = innerContainer.style.color;

          innerDiv.appendChild( link );
        } else {
          innerDiv.innerHTML = text;
        }
      };
      fontSheet.href = "//fonts.googleapis.com/css?family=" + options.fontFamily.replace( /\s/g, "+" ) + ":400,700";

      options.toString = function() {
        // use the default option if it doesn't exist
        return options.text || options._natives.manifest.options.text[ "default" ];
      };
    },

    start: function( event, options ) {
      if ( options._container ) {
        options._container.classList.add( "on" );
        options._container.classList.remove( "off" );
      }
    },

    end: function( event, options ) {
      if ( options._container ) {
        options._container.classList.add( "off" );
        options._container.classList.remove( "on" );
      }
    },

    _teardown: function( options ) {
      if ( options._target ) {
        options._target.removeChild( options._container );
      }

      if ( options._fontSheet ) {
        document.head.removeChild( options._fontSheet );
      }
    }
  });
}( window.Popcorn ));
<|endoftext|>


<commit_before>/*global historyState:true */

/**
@module Discourse
*/

var get = Ember.get, set = Ember.set;
var popstateReady = false;

/**
  `Ember.DiscourseLocation` implements the location API using the browser's
  `history.pushState` API.

  @class DiscourseLocation
  @namespace Discourse
  @extends Ember.Object
*/
Ember.DiscourseLocation = Ember.Object.extend({
  init: function() {
    set(this, 'location', get(this, 'location') || window.location);
    if ( $.inArray('state', $.event.props) < 0 )
      jQuery.event.props.push('state')
    this.initState();
  },

  /**
    @private

    Used to set state on first call to setURL

    @method initState
  */
  initState: function() {
    this.replaceState(this.formatURL(this.getURL()));
    set(this, 'history', window.history);
  },

  /**
    Will be pre-pended to path upon state change

    @property rootURL
    @default '/'
  */
  rootURL: '/',

  /**
    @private

    Returns the current `location.pathname` without rootURL

    @method getURL
  */
  getURL: function() {
    var rootURL = get(this, 'rootURL'),
        url = get(this, 'location').pathname;

    rootURL = rootURL.replace(/\/$/, '');
    url = url.replace(rootURL, '');

    return url;
  },

  /**
    @private

    Uses `history.pushState` to update the url without a page reload.

    @method setURL
    @param path {String}
  */
  setURL: function(path) {
    path = this.formatURL(path);
    if (this.getState() && this.getState().path !== path) {
      popstateReady = true;
      this.pushState(path);
    }
  },

  /**
    @private

    Uses `history.replaceState` to update the url without a page reload
    or history modification.

    @method replaceURL
    @param path {String}
  */
  replaceURL: function(path) {
    path = this.formatURL(path);

    if (this.getState() && this.getState().path !== path) {
      popstateReady = true;
      this.replaceState(path);
    }
  },

  /**
   @private

   Get the current `history.state`

   @method getState
  */
  getState: function() {
    historyState = get(this, 'history').state;
    if (historyState) return historyState;

    return {path: window.location.pathname};
  },

  /**
   @private

   Pushes a new state

   @method pushState
   @param path {String}
  */
  pushState: function(path) {
    if (!window.history.pushState) return;
    this.set('currentState', { path: path } );
    window.history.pushState({ path: path }, null, path);
  },

  /**
   @private

   Replaces the current state

   @method replaceState
   @param path {String}
  */
  replaceState: function(path) {
    if (!window.history.replaceState) return;
    this.set('currentState', { path: path } );
    window.history.replaceState({ path: path }, null, path);
  },

  /**
    @private

    Register a callback to be invoked whenever the browser
    history changes, including using forward and back buttons.

    @method onUpdateURL
    @param callback {Function}
  */
  onUpdateURL: function(callback) {
    var guid = Ember.guidFor(this),
        self = this;

    $(window).bind('popstate.ember-location-'+guid, function(e) {
      if (e.state) {
        var currentState = self.get('currentState');
        if (currentState) {
          callback(e.state.path);
        } else {
          this.set('currentState', e.state);
        }
      }

    });
  },

  /**
    @private

    Used when using `{{action}}` helper.  The url is always appended to the rootURL.

    @method formatURL
    @param url {String}
  */
  formatURL: function(url) {
    var rootURL = get(this, 'rootURL');

    if (url !== '') {
      rootURL = rootURL.replace(/\/$/, '');
    }

    return rootURL + url;
  },

  willDestroy: function() {
    var guid = Ember.guidFor(this);

    Ember.$(window).unbind('popstate.ember-location-'+guid);
  }
});

Ember.Location.registerImplementation('discourse_location', Ember.DiscourseLocation);
<commit_msg>Reworked rootURL in ember.js and allow handling of back/forward buttons in browser<commit_after>/*global historyState:true */

/**
@module Discourse
*/

var get = Ember.get, set = Ember.set;
var popstateReady = false;

/**
  `Ember.DiscourseLocation` implements the location API using the browser's
  `history.pushState` API.

  @class DiscourseLocation
  @namespace Discourse
  @extends Ember.Object
*/
Ember.DiscourseLocation = Ember.Object.extend({
  init: function() {
    set(this, 'location', get(this, 'location') || window.location);
    if ( $.inArray('state', $.event.props) < 0 )
      jQuery.event.props.push('state')
    this.initState();
  },

  /**
    @private

    Used to set state on first call to setURL

    @method initState
  */
  initState: function() {
    this.replaceState(this.formatURL(this.getURL()));
    set(this, 'history', window.history);
  },

  /**
    Will be pre-pended to path upon state change

    @property rootURL
    @default '/'
  */
  rootURL: '/',

  /**
    @private

    Returns the current `location.pathname` without rootURL

    @method getURL
  */
  getURL: function() {
    var rootURL = get(this, 'rootURL'),
        url = get(this, 'location').pathname;

    rootURL = rootURL.replace(/\/$/, '');
    url = url.replace(rootURL, '');

    return url;
  },

  /**
    @private

    Uses `history.pushState` to update the url without a page reload.

    @method setURL
    @param path {String}
  */
  setURL: function(path) {
    path = this.formatURL(path);
    if (this.getState() && this.getState().path !== path) {
      popstateReady = true;
      this.pushState(path);
    }
  },

  /**
    @private

    Uses `history.replaceState` to update the url without a page reload
    or history modification.

    @method replaceURL
    @param path {String}
  */
  replaceURL: function(path) {
    path = this.formatURL(path);

    if (this.getState() && this.getState().path !== path) {
      popstateReady = true;
      this.replaceState(path);
    }
  },

  /**
   @private

   Get the current `history.state`

   @method getState
  */
  getState: function() {
    historyState = get(this, 'history').state;
    if (historyState) return historyState;

    return {path: window.location.pathname};
  },

  /**
   @private

   Pushes a new state

   @method pushState
   @param path {String}
  */
  pushState: function(path) {
    if (!window.history.pushState) return;
    this.set('currentState', { path: path } );
    window.history.pushState({ path: path }, null, path);
  },

  /**
   @private

   Replaces the current state

   @method replaceState
   @param path {String}
  */
  replaceState: function(path) {
    if (!window.history.replaceState) return;
    this.set('currentState', { path: path } );
    window.history.replaceState({ path: path }, null, path);
  },

  /**
    @private

    Register a callback to be invoked whenever the browser
    history changes, including using forward and back buttons.

    @method onUpdateURL
    @param callback {Function}
  */
  onUpdateURL: function(callback) {
    var guid = Ember.guidFor(this),
        self = this;

    $(window).bind('popstate.ember-location-'+guid, function(e) {
      if (e.state) {
        var currentState = self.get('currentState');
        if (currentState) {
          var url = e.state.path,
              rootURL = get(self, 'rootURL');

          rootURL = rootURL.replace(/\/$/, '');
          url = url.replace(rootURL, '');
          callback(url);
        } else {
          this.set('currentState', e.state);
        }
      }

    });
  },

  /**
    @private

    Used when using `{{action}}` helper.  The url is always appended to the rootURL.

    @method formatURL
    @param url {String}
  */
  formatURL: function(url) {
    var rootURL = get(this, 'rootURL');

    if (url !== '') {
      rootURL = rootURL.replace(/\/$/, '');
    }

    return rootURL + url;
  },

  willDestroy: function() {
    var guid = Ember.guidFor(this);

    Ember.$(window).unbind('popstate.ember-location-'+guid);
  }
});

Ember.Location.registerImplementation('discourse_location', Ember.DiscourseLocation);
<|endoftext|>


<commit_before>    angular.module('TimelineDSL', [ 'ng' ])
        .service(  '$timelines', TimelineBuilder )
        .directive('timeline',  TimelineDirective )
        .directive('step',      StepDirective );

    /**
     * Service to build a GSAP TimelineLite instance based on <timeline> and nested <step>
     * directive settings...
     */
    function TimelineBuilder($log, $rootScope, $q ) {
        var counter = 0,
            targets = { },
            cache   = { },
            self;

        // Publish API for `$timelines` service

        return self = {
            state      : findByState,
            id         : findById,
            register   : register,
            instanceOf : build
        };

        // ******************************************************************
        // Internal Methods
        // ******************************************************************

        /**
         * Provide a async lookup to return a timeline after
         * all $digest changes have completed.
         *
         * @param id
         * @returns {Deferred.promise|*}
         */
        function findById( id ) {
            var deferred = $q.defer();

                $rootScope.$evalAsync( function(){
                    var timeline = cache[id];

                    if ( timeline )  deferred.resolve(timeline);
                    else             deferred.reject( "Timeline( id == '{0}' ) was not found.".supplant([ id ]) );

                });

            return deferred.promise;
        }

        /**
         * Provide a async lookup to return a timeline after
         * all $digest changes have completed.
         *
         * @param state
         * @returns {Deferred.promise|*}
         */
        function findByState( state ) {
            var deferred = $q.defer();

                $rootScope.$evalAsync( function(){
                    var timeline;

                    cache.forEach(function(it) {
                        if ( angular.isDefined(it.$$state) ){
                            if ( it.$$state == state )
                            {
                                timeline = it;
                            }
                        }
                    });

                    if ( timeline )  deferred.resolve(timeline);
                    else             deferred.reject( "Timeline( state == '{0}' ) was not found.".supplant([ state ]) );

                });

            return deferred.promise;
        }

        /**
         * Register timeline for easy lookups later...
         */
        function register(timeline, id, state) {
            if ( timeline && id && id.length ) {

                cache[ id ] = timeline;

                if ( angular.isDefined(state) )
                {
                    timeline.$$state = state;
                }
            }
        }

        /**
         * Build a TimelineLite instance
         *
         * @param source TimelineController
         * @param flushTargets Boolean to rebuild the query selectors
         * @returns {*} GSAP TimelineLite instance
         */
        function build(source, flushTargets) {
            targets = flushTargets ? { } : targets;

            var timeline = source.timeline || new TimelineLite({paused: true, data: {id: source.id || counter++ }});
                timeline.clear(true).timeScale( source.timeScale );
                timeline.eventCallback("onUpdate", source.onUpdate || angular.noop, ["{self}"] );

            source.timeline = timeline;
            source.steps.forEach(function(step, index) {

                var element     = querySelector(step.target);
                var frameLabel  = keyValue(step, "markPosition");
                var position    = keyValue(step, "position", "");
                var styles      = toJSON(keyValue(step, "style"));
                var hasDuration = !!keyValue(step, "duration");
                var duration    = hasDuration ? keyValue(step, "duration") : 0;

                if ( frameLabel )   timeline.addLabel( frameLabel );
                if ( hasDuration )  timeline.to(element,  +duration, styles,  position );
                else                timeline.set(element, styles );

            });
            source.children.forEach(function(it){
                if ( it.timeline ) {
                    timeline.add(it.timeline, it.position);

                    // Unpause children timelines
                    it.timeline.paused(false);
                }
            });

            return logBuild(source);

            // ******************************************************************
            // Internal Debug Methods
            // ******************************************************************

            function logBuild( source ) {
                var timeline = source.timeline;

                $log.debug( "---------------------".supplant(timeline) );
                $log.debug( "rebuild timeline( {data.id} )".supplant(timeline) );
                $log.debug( "---------------------".supplant(timeline) );

                source.steps.forEach(function(step, index) {

                    var element     = querySelector(step.target);
                    var frameLabel  = keyValue(step, "markPosition");
                    var position    = keyValue(step, "position", "");
                    var styles      = toJSON(keyValue(step, "style"));
                    var hasDuration = !!keyValue(step, "duration");
                    var duration    = hasDuration ? keyValue(step, "duration") : 0;

                    if ( frameLabel )  $log.debug( "addLabel( '{0}' )"                    .supplant( [frameLabel] ));
                    if ( hasDuration ) $log.debug( "timeline.set( '{0}', {1},  {2}, '{3}' )" .supplant( [step.target, duration, JSON.stringify(styles), position ] ));
                    else               $log.debug( "timeline.set( '{0}', '{1}' )"            .supplant( [step.target, JSON.stringify(styles)] ));

                });

                source.children.forEach(function(it){
                    if ( it.timeline ) {

                    }
                });

                timeline.eventCallback("onUpdate", function onTimeLineUpdate(tl)
                {
                    $log.debug("timeline " + tl.data.id + " update()");

                }, ["{self}"]);

                return timeline;
            }

            // ******************************************************************
            // Internal Builder Methods
            // ******************************************************************

            /**
             * Find DOM element associated with query selector
             * Use the fallback timeline target if the step target `selector` is not
             * specified.
             *
             * @param selector
             * @returns {*}
             */
            function querySelector( selector ) {
                selector = selector || source.target;

                var element = targets[selector];
                if ( !element ) {

                    // Cache the jQuery querySelector for reuse
                    targets[selector] = element = $(selector);
                }

                return element;
            }
        }

        /**
         * Convert markup styles to JSON style map
         * @param keyValues
         */
        function toJSON(style) {
           var result = { };
           var pairs = style ? style.split(";") : [ ];

           pairs.forEach(function(it) {
              it = it.trim();
              if ( it.length ) {
                  it = it.split(":");
                  var key = it[0];
                  var value = it[1];

                  if ( String(value).length ) {
                    result[ stripQuotes(key) ] = stripQuotes(value);
                  }
              }
           });

           return result;
        }

        /**
         * Check map for valid string value...
         * @returns {*} String || defVal
         */
        function keyValue(map, key, defVal) {
            return angular.isDefined(map[key]) && (map[key].length > 0) ? map[key] : defVal;
        }

        /**
         * Strip any "" or '' quotes
         * @returns {String}
         */
        function stripQuotes(source) {
            return source.replace(/\"/g,"").replace(/\'/g,"");
        }
    }

    /**
     * Timeline Controller
     * Each controller manages its own timeline with its nested child steps.
     * However, a Timeline controller may be a child of a parent Timeline controller.
     *
     * @param $scope
     * @constructor
     */
    function TimeLineController($scope, $element, $q, $timelines) {
        var self         = this,
            timeline     = null,
            children     = [ ],
            steps        = [ ],
            pendingRebuild = null,
            bouncedRebuild = null,
            parentCntrl    = $element.parent().controller('timeline');

        self.addStep  = onStepChanged;  // Publish method for StepDirective
        self.addChild = onAddTimeline;  // Publish method for TimelineDirective

        // Publish accessors for $timelines::buildTimeline()

        self.target   = function(){ return $scope.target;            };
        self.timeScale= function(){ return +$scope.timeScale || 1.0; };
        self.position = function(){ return +$scope.position  || 0.0; };

        self.steps    = function(){ return steps;                    };
        self.timeline = function(){ return $q.when(timeline);        };

        // ******************************************************************
        // Internal Builder Methods
        // ******************************************************************

        /**
         * Create a `debounced` async timeline build process; this allows
         * all step changes and child timeline additions to complete before
         * rebuilding.
         */
        function asyncRebuild() {

            self.timeline = getTimelinePromise; // Publish deferred timeline accessor

            bouncedRebuild = bouncedRebuild || debounce(rebuildTimeline, 10);
            pendingRebuild = pendingRebuild || $q.defer();

            // Keep debouncing...

            bouncedRebuild();

            /**
             * Rebuild the timeline when the steps or children timelines are changed...
             */
             function rebuildTimeline() {
                 if ( !pendingRebuild ) return;

                 try {
                     if ( children.length || steps.length ) {

                         // Build or update the TimelineLite instance
                         timeline = $timelines.instanceOf({
                             steps    : steps,
                             timeScale: self.timeScale(),
                             target   : self.target(),
                             children : children,
                             timeline : timeline
                         });

                         // Register for easy lookups later...
                         $timelines.register( timeline, $scope.id, $scope.state );
                     }

                     // Add to parent as child timeline (if parent exists)
                     parentCntrl && parentCntrl.addChild( timeline );

                     // Now resolve any pending requests with the up-to-date `timeline`
                     pendingRebuild.resolve( timeline );

                 } finally {
                     pendingRebuild = null;
                 }
             }

            /**
             * Get a promise for the current or updated timeline
             */
             function getTimelinePromise() {
                var deferred = $q.defer();

                    if ( pendingRebuild ) {
                        pendingRebuild.promise.then( deferred.resolve, deferred.reject );
                    }
                    else {
                        deferred.resolve( timeline );
                    }

                return deferred.promise;
             }
        }

        /**
         * Add a child timeline instance to this timeline parent
         *
         * @param timeline Child TimelineLite instance
         * @param position start offset in the parent timeline
         */
        function onAddTimeline(timeline, position) {
            try {
                // If not already registered...
                if ( children.indexOf(timeline) < 0 ) {
                    children.push({
                        timeline : timeline,
                        position : +position
                    });
                }
            } finally {

                // Perform an async rebuild of the timeline; async to
                // respond to all changes as a single batch response.

                asyncRebuild();
            }
        }

        /**
         * When properties of a child step changes,
         * we need to rebuild the timeline...
         * @param step
         */
        function onStepChanged(step) {

            try{

                if ( steps.indexOf(step) < 0 ) {
                    // If not already registered...
                    steps.push(step);
                }

            } finally {

                // Perform an async rebuild of the timeline; async to
                // respond to all changes as a single batch response.

                asyncRebuild();
            }
        }

        /**
         * Returns a function, that, as long as it continues to be invoked, will not
         * be triggered. The function will be called after it stops being called for
         * <wait> milliseconds.
         *
         * @param func
         * @param wait
         * @param scope
         * @returns {Function}
         */
        function debounce(func, wait, scope) {
          var timeout;

          return function debounced() {
            var context = scope || this, args = arguments;

            clearTimeout(timeout);

            timeout = setTimeout(function() {
              timeout = null;
              func.apply(context, args);
            }, wait);

          };
        }
    }

    /**
    * @ngdoc directive
    * @returns {{restrict: string, controller: string, link: Function}}
    * @constructor
    */
   function TimelineDirective($timeout, $timelines) {
       var counter = 1;

       return {
           restrict: "E",
           scope : {
               resolve : "&?"
           },
           controller : TimeLineController,
           link : function (scope, element, attr, controller)
           {
               var parentCntl = element.parent().controller('timeline');

               // Manually access these static properties

               scope.id        = attr.id        || ("timeline_" + counter++);
               scope.position  = attr.position  || 0;
               scope.timeScale = attr.timeScale || 1.0;
               scope.state     = attr.state;
               scope.target    = attr.target;

               // Build watchers to trigger animations or nest timelines...

               if ( !parentCntl ) autoStart();

               // ******************************************************************
               // Internal Methods
               // ******************************************************************

               /**
                *  Watch the `state` variable and autostart the Timeline instance when state
                *  changes
                */
               function autoStart() {
                 var state  = attr.state || "";
                 if ( state.length ) {
                     // Watch for the scope `state` change... to start or reverse the animations

                     parent = scope.$parent;
                     parent.state = parent.state || undefined;

                     parent.$watch('state', function(current, old){
                         if ( current === undefined ) return;
                         if ( state   === ""        ) return;

                         $timelines
                            .find(scope.id)
                            .then(function( timeline ){

                                if ( current == state ) timeline.restart();
                                else if (current == "") timeline.reverse();

                            });

                     });
                 }
               }
           }
       };
   }

    /**
     * @ngdoc directive
     *
     * Steps can only be defined as children of a Timeline. Steps are used to label frames, set styles,
     * or animation 1..n sets of properties for a specific duration.
     *
     * @returns {{restrict: string, scope: {style: string, duration: string, position: string, markPosition: string, clazz: string}, require: string[], link: LinkStepDirective}}
     * @constructor
     *
     * @example:
     *
     *      <step   class=""
     *              duration="0.3"
     *              position="0.1"
     *              style="opacity:1; left:{{source.left}}; top:{{source.top}}; width:{{source.width}}; height:{{source.height}};" >
     *      </step>
     */
    function StepDirective() {
        return {
            restrict : "E",
            scope : {
                className    : "@?",
                duration     : "@?",
                markPosition : "@?",
                position     : "@?",
                style        : "@"
            },
            require : "^timeline",
            link : function LinkStepDirective(scope, element, attr, ctrl) {

                scope.target = attr.target;
                scope.$watch('style', function onChangeStep() {
                    ctrl.addStep(scope);
                });

            }
        };
    }

<commit_msg>dead code cleanup.<commit_after>    angular.module('TimelineDSL', [ 'ng' ])
        .service(  '$timelines', TimelineBuilder )
        .directive('timeline',  TimelineDirective )
        .directive('step',      StepDirective );

    /**
     * Service to build a GSAP TimelineLite instance based on <timeline> and nested <step>
     * directive settings...
     */
    function TimelineBuilder($log, $rootScope, $q ) {
        var counter = 0,
            targets = { },
            cache   = { },
            self;

        // Publish API for `$timelines` service

        return self = {
            state      : findByState,
            id         : findById,
            register   : register,
            instanceOf : build
        };

        // ******************************************************************
        // Internal Methods
        // ******************************************************************

        /**
         * Provide a async lookup to return a timeline after
         * all $digest changes have completed.
         *
         * @param id
         * @returns {Deferred.promise|*}
         */
        function findById( id ) {
            var deferred = $q.defer();

                $rootScope.$evalAsync( function(){
                    var timeline = cache[id];

                    if ( timeline )  deferred.resolve(timeline);
                    else             deferred.reject( "Timeline( id == '{0}' ) was not found.".supplant([ id ]) );

                });

            return deferred.promise;
        }

        /**
         * Provide a async lookup to return a timeline after
         * all $digest changes have completed.
         *
         * @param state
         * @returns {Deferred.promise|*}
         */
        function findByState( state ) {
            var deferred = $q.defer();

                $rootScope.$evalAsync( function(){
                    var timeline;

                    cache.forEach(function(it) {
                        if ( angular.isDefined(it.$$state) ){
                            if ( it.$$state == state )
                            {
                                timeline = it;
                            }
                        }
                    });

                    if ( timeline )  deferred.resolve(timeline);
                    else             deferred.reject( "Timeline( state == '{0}' ) was not found.".supplant([ state ]) );

                });

            return deferred.promise;
        }

        /**
         * Register timeline for easy lookups later...
         */
        function register(timeline, id, state) {
            if ( timeline && id && id.length ) {

                cache[ id ] = timeline;

                if ( angular.isDefined(state) )
                {
                    timeline.$$state = state;
                }
            }
        }

        /**
         * Build a TimelineLite instance
         *
         * @param source TimelineController
         * @param flushTargets Boolean to rebuild the query selectors
         * @returns {*} GSAP TimelineLite instance
         */
        function build(source, flushTargets) {
            targets = flushTargets ? { } : targets;

            var timeline = source.timeline || new TimelineLite({paused: true, data: {id: source.id || counter++ }});
                timeline.clear(true).timeScale( source.timeScale );
                timeline.eventCallback("onUpdate", source.onUpdate || angular.noop, ["{self}"] );

            source.timeline = timeline;
            source.steps.forEach(function(step, index) {

                var element     = querySelector(step.target);
                var frameLabel  = keyValue(step, "markPosition");
                var position    = keyValue(step, "position", "");
                var styles      = toJSON(keyValue(step, "style"));
                var hasDuration = !!keyValue(step, "duration");
                var duration    = hasDuration ? keyValue(step, "duration") : 0;

                if ( frameLabel )   timeline.addLabel( frameLabel );
                if ( hasDuration )  timeline.to(element,  +duration, styles,  position );
                else                timeline.set(element, styles );

            });
            source.children.forEach(function(it){
                if ( it.timeline ) {
                    timeline.add(it.timeline, it.position);

                    // Unpause children timelines
                    it.timeline.paused(false);
                }
            });

            return logBuild(source);

            // ******************************************************************
            // Internal Debug Methods
            // ******************************************************************

            function logBuild( source ) {
                var timeline = source.timeline;

                $log.debug( "---------------------".supplant(timeline) );
                $log.debug( "rebuild timeline( {data.id} )".supplant(timeline) );
                $log.debug( "---------------------".supplant(timeline) );

                source.steps.forEach(function(step, index) {

                    var element     = querySelector(step.target);
                    var frameLabel  = keyValue(step, "markPosition");
                    var position    = keyValue(step, "position", "");
                    var styles      = toJSON(keyValue(step, "style"));
                    var hasDuration = !!keyValue(step, "duration");
                    var duration    = hasDuration ? keyValue(step, "duration") : 0;

                    if ( frameLabel )  $log.debug( "addLabel( '{0}' )"                    .supplant( [frameLabel] ));
                    if ( hasDuration ) $log.debug( "timeline.set( '{0}', {1},  {2}, '{3}' )" .supplant( [step.target, duration, JSON.stringify(styles), position ] ));
                    else               $log.debug( "timeline.set( '{0}', '{1}' )"            .supplant( [step.target, JSON.stringify(styles)] ));

                });

                source.children.forEach(function(it){
                    if ( it.timeline ) {

                    }
                });

                timeline.eventCallback("onUpdate", function onTimeLineUpdate(tl)
                {
                    $log.debug("timeline " + tl.data.id + " update()");

                }, ["{self}"]);

                return timeline;
            }

            // ******************************************************************
            // Internal Builder Methods
            // ******************************************************************

            /**
             * Find DOM element associated with query selector
             * Use the fallback timeline target if the step target `selector` is not
             * specified.
             *
             * @param selector
             * @returns {*}
             */
            function querySelector( selector ) {
                selector = selector || source.target;

                var element = targets[selector];
                if ( !element ) {

                    // Cache the jQuery querySelector for reuse
                    targets[selector] = element = $(selector);
                }

                return element;
            }
        }

        /**
         * Convert markup styles to JSON style map
         * @param keyValues
         */
        function toJSON(style) {
           var result = { };
           var pairs = style ? style.split(";") : [ ];

           pairs.forEach(function(it) {
              it = it.trim();
              if ( it.length ) {
                  it = it.split(":");
                  var key = it[0];
                  var value = it[1];

                  if ( String(value).length ) {
                    result[ stripQuotes(key) ] = stripQuotes(value);
                  }
              }
           });

           return result;
        }

        /**
         * Check map for valid string value...
         * @returns {*} String || defVal
         */
        function keyValue(map, key, defVal) {
            return angular.isDefined(map[key]) && (map[key].length > 0) ? map[key] : defVal;
        }

        /**
         * Strip any "" or '' quotes
         * @returns {String}
         */
        function stripQuotes(source) {
            return source.replace(/\"/g,"").replace(/\'/g,"");
        }
    }

    /**
     * Timeline Controller
     * Each controller manages its own timeline with its nested child steps.
     * However, a Timeline controller may be a child of a parent Timeline controller.
     *
     * @param $scope
     * @constructor
     */
    function TimeLineController($scope, $element, $q, $timelines) {
        var self         = this,
            timeline     = null,
            children     = [ ],
            steps        = [ ],
            pendingRebuild = null,
            bouncedRebuild = null,
            parentCntrl    = $element.parent().controller('timeline');

        self.addStep  = onStepChanged;  // Publish method for StepDirective
        self.addChild = onAddTimeline;  // Publish method for TimelineDirective

        // Publish accessors for $timelines::buildTimeline()

        // ******************************************************************
        // Internal Builder Methods
        // ******************************************************************

        /**
         * Create a `debounced` async timeline build process; this allows
         * all step changes and child timeline additions to complete before
         * rebuilding.
         */
        function asyncRebuild() {

            bouncedRebuild = bouncedRebuild || debounce(rebuildTimeline, 10);
            pendingRebuild = pendingRebuild || $q.defer();

            // Keep debouncing...

            bouncedRebuild();

            /**
             * Rebuild the timeline when the steps or children timelines are changed...
             */
             function rebuildTimeline() {
                 if ( !pendingRebuild ) return;

                 try {
                     if ( children.length || steps.length ) {

                         // Build or update the TimelineLite instance
                         timeline = $timelines.instanceOf({
                             timeline : timeline,
                             steps    : steps,
                             children : children,
                             target   : $scope.target,
                             timeScale: +$scope.timeScale || 1.0
                         });

                         // Register for easy lookups later...
                         $timelines.register( timeline, $scope.id, $scope.state );
                     }

                     // Add to parent as child timeline (if parent exists)
                     parentCntrl && parentCntrl.addChild( timeline, +$scope.position  || 0.0 );

                     // Now resolve any pending requests with the up-to-date `timeline`
                     pendingRebuild.resolve( timeline );

                 } finally {
                     pendingRebuild = null;
                 }
             }
        }

        /**
         * Add a child timeline instance to this timeline parent
         *
         * @param timeline Child TimelineLite instance
         * @param position start offset in the parent timeline
         */
        function onAddTimeline(timeline, position) {
            try {
                // If not already registered...
                if ( children.indexOf(timeline) < 0 ) {
                    children.push({
                        timeline : timeline,
                        position : +position
                    });
                }
            } finally {

                // Perform an async rebuild of the timeline; async to
                // respond to all changes as a single batch response.

                asyncRebuild();
            }
        }

        /**
         * When properties of a child step changes,
         * we need to rebuild the timeline...
         * @param step
         */
        function onStepChanged(step) {

            try{

                if ( steps.indexOf(step) < 0 ) {
                    // If not already registered...
                    steps.push(step);
                }

            } finally {

                // Perform an async rebuild of the timeline; async to
                // respond to all changes as a single batch response.

                asyncRebuild();
            }
        }

        /**
         * Returns a function, that, as long as it continues to be invoked, will not
         * be triggered. The function will be called after it stops being called for
         * <wait> milliseconds.
         *
         * @param func
         * @param wait
         * @param scope
         * @returns {Function}
         */
        function debounce(func, wait, scope) {
          var timeout;

          return function debounced() {
            var context = scope || this, args = arguments;

            clearTimeout(timeout);

            timeout = setTimeout(function() {
              timeout = null;
              func.apply(context, args);
            }, wait);

          };
        }
    }

    /**
    * @ngdoc directive
    * @returns {{restrict: string, controller: string, link: Function}}
    * @constructor
    */
   function TimelineDirective($timeout, $timelines) {
       var counter = 1;

       return {
           restrict: "E",
           scope : {
               resolve : "&?"
           },
           controller : TimeLineController,
           link : function (scope, element, attr, controller)
           {
               var parentCntl = element.parent().controller('timeline');

               // Manually access these static properties

               scope.id        = attr.id        || ("timeline_" + counter++);
               scope.position  = attr.position  || 0;
               scope.timeScale = attr.timeScale || 1.0;
               scope.state     = attr.state;
               scope.target    = attr.target;

               // Build watchers to trigger animations or nest timelines...

               if ( !parentCntl ) autoStart();

               // ******************************************************************
               // Internal Methods
               // ******************************************************************

               /**
                *  Watch the `state` variable and autostart the Timeline instance when state
                *  changes
                */
               function autoStart() {
                 var state  = attr.state || "";
                 if ( state.length ) {
                     // Watch for the scope `state` change... to start or reverse the animations

                     parent = scope.$parent;
                     parent.state = parent.state || undefined;

                     parent.$watch('state', function(current, old){
                         if ( current === undefined ) return;
                         if ( state   === ""        ) return;

                         $timelines
                            .find(scope.id)
                            .then(function( timeline ){

                                if ( current == state ) timeline.restart();
                                else if (current == "") timeline.reverse();

                            });

                     });
                 }
               }
           }
       };
   }

    /**
     * @ngdoc directive
     *
     * Steps can only be defined as children of a Timeline. Steps are used to label frames, set styles,
     * or animation 1..n sets of properties for a specific duration.
     *
     * @returns {{restrict: string, scope: {style: string, duration: string, position: string, markPosition: string, clazz: string}, require: string[], link: LinkStepDirective}}
     * @constructor
     *
     * @example:
     *
     *      <step   class=""
     *              duration="0.3"
     *              position="0.1"
     *              style="opacity:1; left:{{source.left}}; top:{{source.top}}; width:{{source.width}}; height:{{source.height}};" >
     *      </step>
     */
    function StepDirective() {
        return {
            restrict : "E",
            scope : {
                className    : "@?",
                duration     : "@?",
                markPosition : "@?",
                position     : "@?",
                style        : "@"
            },
            require : "^timeline",
            link : function LinkStepDirective(scope, element, attr, ctrl) {

                scope.target = attr.target;
                scope.$watch('style', function onChangeStep() {
                    ctrl.addStep(scope);
                });

            }
        };
    }

<|endoftext|>


<commit_before>import React, {Component} from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import styles from './RunLog.css'

export default class RunLog extends Component {
  componentDidUpdate () {
    if (this.refs.ensureVisible) this.refs.ensureVisible.scrollIntoView(true)
  }

  render () {
    const { style, commands } = this.props

    const makeCommandToTemplateMapper = (depth) => (command) => {
      const {id, isCurrent, description, children, handledAt} = command
      const style = [styles[`indent-${depth}`]]
      const contents = [

[{id}] : {description}

      ]

      if (children.length) {
        contents.push(

            {children.map(makeCommandToTemplateMapper(depth + 1))}

        )
      }

      return (

          {contents}

      )
    }

    const commandItems = commands.map(makeCommandToTemplateMapper(0))

    return (

          {commandItems}

    )
  }
}

/*
Commenting out isRequired for some props for now, using local mock data for first pass
*/
RunLog.propTypes = {
  style: PropTypes.string,
  isConnected: PropTypes.bool.isRequired,
  // TODO(mc, 2017-08-23): use PropTypes.shape (or whatever that method is)
  // instead of object
  commands: PropTypes.arrayOf(PropTypes.object).isRequired
}
<commit_msg>rebase app-3-0-nested-commands-rebase, remove mock nested command data, use generated robot commands<commit_after>import React, {Component} from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import styles from './RunLog.css'

export default class RunLog extends Component {
  componentDidUpdate () {
    if (this.refs.ensureVisible) this.refs.ensureVisible.scrollIntoView(true)
  }

  render () {
    const {style, commands} = this.props
    const makeCommandToTemplateMapper = (depth) => (command) => {
      const {id, isCurrent, description, children, handledAt} = command
      const style = [styles[`indent-${depth}`]]
      const contents = [

[{id}] : {description}

      ]

      if (children.length) {
        contents.push(

            {children.map(makeCommandToTemplateMapper(depth + 1))}

        )
      }

      return (

          {contents}

      )
    }

    const commandItems = commands.map(makeCommandToTemplateMapper(0))

    return (

          {commandItems}

    )
  }
}

/*
Commenting out isRequired for some props for now, using local mock data for first pass
*/
RunLog.propTypes = {
  style: PropTypes.string,
  isConnected: PropTypes.bool.isRequired,
  // TODO(mc, 2017-08-23): use PropTypes.shape (or whatever that method is)
  // instead of object
  commands: PropTypes.arrayOf(PropTypes.object).isRequired
}
<|endoftext|>


<commit_before>import { Meteor } from 'meteor/meteor';
import { Mongo } from 'meteor/mongo';
import { check } from 'meteor/check';

export const Tasks = new Mongo.Collection('tasks');

// publish
if (Meteor.isServer) {
  Meteor.publish('tasks', function tasksPublication() {
    return Tasks.find();
  });
}

Meteor.methods({
  'tasks.insert'(text) {
    check(text, String);

    if (! Meteor.userId() ) {
      // not logged in
      throw new Meteor.Error('not-authorized');
    }

    Tasks.insert({
      text,
      createdAt: new Date(),
      owner: Meteor.userId(),
      username: Meteor.user().username,
    });

  },
  'tasks.remove'(taskId) {
    check(taskId, String);

    Tasks.remove(taskId);
  },
  'tasks.setChecked'(taskId, setChecked) {
    check(taskId, String);
    check(setChecked, Boolean);

    Tasks.update(taskId, { $set: { checked: setChecked } });
  },
  'tasks.setPrivate'(taskId, setToPrivate) {
    check(taskId, String);
    check(setToPrivate, Boolean);

    const task = Tasks.findOne(taskId);

    if (task.owner !== Meteor.userId()) {
      // Make sure only the task owner can make a task private
      throw new Meteor.Error('not-authorized');
    }

    Tasks.update(taskId, { $set: { private: setToPrivate } });
  },
});
<commit_msg>modify publication of tasks to account for private setting<commit_after>import { Meteor } from 'meteor/meteor';
import { Mongo } from 'meteor/mongo';
import { check } from 'meteor/check';

export const Tasks = new Mongo.Collection('tasks');

// publish
if (Meteor.isServer) {
  Meteor.publish('tasks', function tasksPublication() {
    // only publish tasks if
    // 1) owner of task -- or --
    // 2) private != true; its a public task
    return Tasks.find({
      $or: [
        { private: { $ne: true } },
        { owner: this.userId },
      ],
    });
  });
}

Meteor.methods({
  'tasks.insert'(text) {
    check(text, String);

    if (! Meteor.userId() ) {
      // not logged in
      throw new Meteor.Error('not-authorized');
    }

    Tasks.insert({
      text,
      createdAt: new Date(),
      owner: Meteor.userId(),
      username: Meteor.user().username,
    });

  },
  'tasks.remove'(taskId) {
    check(taskId, String);

    Tasks.remove(taskId);
  },
  'tasks.setChecked'(taskId, setChecked) {
    check(taskId, String);
    check(setChecked, Boolean);

    Tasks.update(taskId, { $set: { checked: setChecked } });
  },
  'tasks.setPrivate'(taskId, setToPrivate) {
    check(taskId, String);
    check(setToPrivate, Boolean);

    const task = Tasks.findOne(taskId);

    if (task.owner !== Meteor.userId()) {
      // Make sure only the task owner can make a task private
      throw new Meteor.Error('not-authorized');
    }

    Tasks.update(taskId, { $set: { private: setToPrivate } });
  },
});
<|endoftext|>