<commit_before>// Generated by CoffeeScript 1.4.0
(function() {
  "use strict";

  describe("Util provides the following functions:", function() {
    describe("truncateIfTooLarge", function() {
      it("does nothing if the length of the text is less then the given max size", function() {
        expect(truncateIfTooLarge('puppy', 5)).toBe('puppy');
        return expect(truncateIfTooLarge('', 100)).toBe('');
      });
      it("truncates the text and appends a suffix if the length text of the text        is greater then the max size", function() {
        expect(truncateIfTooLarge('puppy', 4)).toBe('p...');
        return expect(truncateIfTooLarge('sally had a little lamb', 10)).toBe('sally h...');
      });
      return it("can have the suffix changed", function() {
        return expect(truncateIfTooLarge('puppy', 4, '!')).toBe('pup!');
      });
    });
    describe("stripColorCodes", function() {
      it("removes color codes that specify a foreground color", function() {
        var coloredText;
        coloredText = "\u000315hey guy\u0003, how's it going?";
        expect(html.stripColorCodes(coloredText)).toBe("hey guy\u0003, how's it going?");
        coloredText = "\u00033hey guy\u000388, how's it going?";
        return expect(html.stripColorCodes(coloredText)).toBe("hey guy, how's it going?");
      });
      it("removes color codes even when they come before a number", function() {
        var coloredText;
        coloredText = "hi\u0003055";
        return expect(html.stripColorCodes(coloredText)).toBe("hi5");
      });
      return it("removes color codes that specify a forground and background color", function() {
        var coloredText;
        coloredText = "so \u00038,77how are you?";
        return expect(html.stripColorCodes(coloredText)).toBe("so how are you?");
      });
    });
    describe("pluralize", function() {
      it("does nothing if there is one of something", function() {
        expect(pluralize('dog', 1)).toBe('dog');
        return expect(pluralize('stress', 1)).toBe('stress');
      });
      it("adds an 's' when there is 0 or > 1 of something", function() {
        expect(pluralize('cat', 2)).toBe('cats');
        return expect(pluralize('cat', 0)).toBe('cats');
      });
      return it("adds an 'es' when there is 0 or > 1 of something and the word ends in 's'", function() {
        return expect(pluralize('stress', 2)).toBe('stresses');
      });
    });
    describe("getLogger", function() {
      var TestClass1, TestClass2;
      TestClass1 = (function() {

        function TestClass1() {}

        return TestClass1;

      })();
      TestClass2 = (function() {

        function TestClass2() {}

        return TestClass2;

      })();
      return it("logs debug info", function() {
        var a, b, logA, logB;
        spyOn(window.console, 'log');
        spyOn(window.console, 'error');
        spyOn(window.console, 'warn');
        a = new TestClass1;
        b = new TestClass2;
        logA = getLogger(a);
        logB = getLogger(b);
        logA('this is my message!');
        logB('w', 'warning', 5, 'is a great number');
        logA('e', 'error!', 'error msg');
        expect(console.log).toHaveBeenCalledWith('TestClass1:', 'this is my message!');
        expect(console.warn).toHaveBeenCalledWith('TestClass2:', 'warning', 5, 'is a great number');
        return expect(console.error).toHaveBeenCalledWith('TestClass1:', 'error!', 'error msg');
      });
    });
    describe("capitalizeString", function() {
      return it("capitalizes the first letter of words", function() {
        expect(capitalizeString('bob')).toBe('Bob');
        expect(capitalizeString('BILL')).toBe('BILL');
        return expect(capitalizeString('')).toBe('');
      });
    });
    return describe("getReadableList", function() {
      it("returns the single element when the list has a length of 1", function() {
        return expect(getReadableList([5])).toBe('5');
      });
      it("returns the two elements with an 'and' in between when the list has a length of 2", function() {
        return expect(getReadableList(['sally', 'joe'])).toBe('sally and joe');
      });
      return it("returns a comma seperated list with the last element and'd onto the end when the list has a length > 3", function() {
        return expect(getReadableList([1, 2, 3])).toBe('1, 2 and 3');
      });
    });
  });

}).call(this);
<commit_msg>Added tests for mIRC colors<commit_after>// Generated by CoffeeScript 1.4.0
(function() {
  "use strict";

  describe("Util provides the following functions:", function() {
    describe("truncateIfTooLarge", function() {
      it("does nothing if the length of the text is less then the given max size", function() {
        expect(truncateIfTooLarge('puppy', 5)).toBe('puppy');
        return expect(truncateIfTooLarge('', 100)).toBe('');
      });
      it("truncates the text and appends a suffix if the length text of the text        is greater then the max size", function() {
        expect(truncateIfTooLarge('puppy', 4)).toBe('p...');
        return expect(truncateIfTooLarge('sally had a little lamb', 10)).toBe('sally h...');
      });
      return it("can have the suffix changed", function() {
        return expect(truncateIfTooLarge('puppy', 4, '!')).toBe('pup!');
      });
    });
    describe("stripColorCodes", function() {
      it("removes color codes that specify a foreground color", function() {
        var coloredText;
        coloredText = "\u000315hey guy\u0003, how's it going?";
        expect(html.stripColorCodes(coloredText)).toBe("hey guy\u0003, how's it going?");
        coloredText = "\u00033hey guy\u000388, how's it going?";
        return expect(html.stripColorCodes(coloredText)).toBe("hey guy, how's it going?");
      });
      it("removes color codes even when they come before a number", function() {
        var coloredText;
        coloredText = "hi\u0003055";
        return expect(html.stripColorCodes(coloredText)).toBe("hi5");
      });
      it("removes color codes that specify a forground and background color", function() {
        var coloredText;
        coloredText = "so \u00038,77how are you?";
        return expect(html.stripColorCodes(coloredText)).toBe("so how are you?");
      });
      return it("removes control codes that affect the style", function() {
        var coloredText;
        coloredText = "what \x0F\x02\x1F\x1Dup";
        return expect(html.stripColorCodes(coloredText)).toBe("what up");
      });
    });
    describe("parseColorCodes", function() {
      it("parses color codes", function() {
        var coloredText;
        coloredText = "\u000315hey guy\u0003, how's it going?";
        expect(html.parseColorCodes(coloredText)).toBe("hey guy, how's it going?");
        coloredText = "\u00033hey guy\u00032, how's it going?";
        expect(html.parseColorCodes(coloredText)).toBe("hey guy, how's it going?");
        coloredText = "\u00033hey guy\u00031,2, how's it going?";
        expect(html.parseColorCodes(coloredText)).toBe("hey guy, how's it going?");
        coloredText = "\u00033hey guy\u00031,2, how's it going\u00031?";
        expect(html.parseColorCodes(coloredText)).toBe("hey guy, how's it going?");
        coloredText = "\u00033hey guy\u00031,2, how's it going\u00031?\x0F!";
        return expect(html.parseColorCodes(coloredText)).toBe("hey guy, how's it going?!");
      });
      it("parses underline/italics/bold", function() {
        var coloredText;
        coloredText = "\x02Bold \x1FUnderline \x1DItalics \x0F\x1FUnderline \x0FNone";
        return expect(html.parseColorCodes(coloredText)).toBe("Bold Underline Italics Underline None");
      });
    });
    describe("pluralize", function() {
      it("does nothing if there is one of something", function() {
        expect(pluralize('dog', 1)).toBe('dog');
        return expect(pluralize('stress', 1)).toBe('stress');
      });
      it("adds an 's' when there is 0 or > 1 of something", function() {
        expect(pluralize('cat', 2)).toBe('cats');
        return expect(pluralize('cat', 0)).toBe('cats');
      });
      return it("adds an 'es' when there is 0 or > 1 of something and the word ends in 's'", function() {
        return expect(pluralize('stress', 2)).toBe('stresses');
      });
    });
    describe("getLogger", function() {
      var TestClass1, TestClass2;
      TestClass1 = (function() {

        function TestClass1() {}

        return TestClass1;

      })();
      TestClass2 = (function() {

        function TestClass2() {}

        return TestClass2;

      })();
      return it("logs debug info", function() {
        var a, b, logA, logB;
        spyOn(window.console, 'log');
        spyOn(window.console, 'error');
        spyOn(window.console, 'warn');
        a = new TestClass1;
        b = new TestClass2;
        logA = getLogger(a);
        logB = getLogger(b);
        logA('this is my message!');
        logB('w', 'warning', 5, 'is a great number');
        logA('e', 'error!', 'error msg');
        expect(console.log).toHaveBeenCalledWith('TestClass1:', 'this is my message!');
        expect(console.warn).toHaveBeenCalledWith('TestClass2:', 'warning', 5, 'is a great number');
        return expect(console.error).toHaveBeenCalledWith('TestClass1:', 'error!', 'error msg');
      });
    });
    describe("capitalizeString", function() {
      return it("capitalizes the first letter of words", function() {
        expect(capitalizeString('bob')).toBe('Bob');
        expect(capitalizeString('BILL')).toBe('BILL');
        return expect(capitalizeString('')).toBe('');
      });
    });
    return describe("getReadableList", function() {
      it("returns the single element when the list has a length of 1", function() {
        return expect(getReadableList([5])).toBe('5');
      });
      it("returns the two elements with an 'and' in between when the list has a length of 2", function() {
        return expect(getReadableList(['sally', 'joe'])).toBe('sally and joe');
      });
      return it("returns a comma seperated list with the last element and'd onto the end when the list has a length > 3", function() {
        return expect(getReadableList([1, 2, 3])).toBe('1, 2 and 3');
      });
    });
  });

}).call(this);
<|endoftext|>


<commit_before>var X = X ||{};

X.GB = (function() {

  'use strict';

  var stats;

  var prev_time;

  return {

    running: false,

    init: function() {

      // Initialize all modules

      X.Memory.init();
      X.CPU.init();
      X.Video.init();
      X.Audio.init();
      X.Joypad.init();
      X.Debugger.init();

      // Reset the console when a game is inserted

      var gb = this;

      var local_rom_select = document.querySelector('input#local_rom');
      local_rom_select.selectedIndex = -1;
      local_rom_select.addEventListener('change', function() {

        var reader = new FileReader();
        reader.addEventListener('load', function() {
          gb.reset();
          X.Cartridge.init(this.result);
          if (X.Cartridge.ready && !gb.running) gb.run();
        });

        reader.readAsArrayBuffer(this.files[0]);
      });

      var hosted_rom_select = document.querySelector('select#hosted_rom');
      hosted_rom_select.addEventListener('change', function(event) {

        var name = event.target.selectedOptions[0].textContent;

        var request = new XMLHttpRequest();
        request.open('GET', 'roms/' + name + '.gb', true);
        request.responseType = 'arraybuffer';

        request.onload = function() {
          gb.reset();
          X.Cartridge.init(request.response);
          if (X.Cartridge.ready && !gb.running) gb.run();
        };

        request.send(null);
      });

      // FPS counter

      stats = new Stats();
      stats.setMode(0);

      stats.domElement.style.position = 'absolute';
      stats.domElement.style.top = '0';
      stats.domElement.style.right = '0';
      document.body.appendChild(stats.domElement);
    },

    reset: function() {

      X.Memory.reset();
      X.CPU.reset();
      X.Video.reset();
      X.Audio.reset();
      X.Joypad.reset();
      X.Debugger.reset();
    },

    frame: function(time) {

      stats.begin();

      // Emulate until a V-Blank or a breakpoint
      do {

        if (X.Debugger.reached_breakpoint()) {
          this.running = false;
          X.Debugger.update();
          console.info('Breakpoint reached');
          break;
        }

        var cycles = X.CPU.step();
        X.Audio.step(cycles);
        var vblank = X.Video.step(cycles);

      } while (!vblank && cycles > 0);

      stats.end();

      // Repeat...
      if (this.running)
        requestAnimationFrame(this.frame.bind(this));
    },

    run: function() {
      if (!this.running) {
        this.running = true;
        requestAnimationFrame(this.frame.bind(this));
      }
    },

    pause: function() {
      this.running = false;
    },

    step: function() {
      X.Video.step(X.CPU.step());
      X.Debugger.update();
    },

  };

})();
<commit_msg>Emulate based on time elapsed, not until vblank<commit_after>var X = X ||{};

X.GB = (function() {

  'use strict';

  var stats;

  var last_frame_time = 0;
  var leftover_cycles = 0;

  return {

    running: false,

    init: function() {

      // Initialize all modules

      X.Memory.init();
      X.CPU.init();
      X.Video.init();
      X.Audio.init();
      X.Joypad.init();
      X.Debugger.init();

      // Reset the console when a game is inserted

      var gb = this;

      var local_rom_select = document.querySelector('input#local_rom');
      local_rom_select.selectedIndex = -1;
      local_rom_select.addEventListener('change', function() {

        var reader = new FileReader();
        reader.addEventListener('load', function() {
          gb.reset();
          X.Cartridge.init(this.result);
          if (X.Cartridge.ready && !gb.running) gb.run();
        });

        reader.readAsArrayBuffer(this.files[0]);
      });

      var hosted_rom_select = document.querySelector('select#hosted_rom');
      hosted_rom_select.addEventListener('change', function(event) {

        var name = event.target.selectedOptions[0].textContent;

        var request = new XMLHttpRequest();
        request.open('GET', 'roms/' + name + '.gb', true);
        request.responseType = 'arraybuffer';

        request.onload = function() {
          gb.reset();
          X.Cartridge.init(request.response);
          if (X.Cartridge.ready && !gb.running) gb.run();
        };

        request.send(null);
      });

      // FPS counter

      stats = new Stats();
      stats.setMode(0);

      stats.domElement.style.position = 'absolute';
      stats.domElement.style.top = '0';
      stats.domElement.style.right = '0';
      document.body.appendChild(stats.domElement);
    },

    reset: function() {

      X.Memory.reset();
      X.CPU.reset();
      X.Video.reset();
      X.Audio.reset();
      X.Joypad.reset();
      X.Debugger.reset();

      leftover_cycles = 0;
    },

    frame: function(now) {
      // Compute time elapsed since the last frame
      var dt = now - (last_frame_time || now);
      last_frame_time = now;

      // How many cycles to emulate based on the elapsed time since the last
      // frame.  We add to keep track of the fractional part between calls.
      leftover_cycles += dt * X.Constants.cpu_freq / 1000;

      stats.begin();

      // Emulate all leftover cycles or until a breakpoint has been reached
      do {
        if (X.Debugger.reached_breakpoint()) {
          this.running = false;
          X.Debugger.update();
          console.info('Breakpoint reached');
          break;
        }

        var cycles = X.CPU.step();
        X.Audio.run(cycles);
        X.Video.step(cycles);

        leftover_cycles -= cycles;
      } while (leftover_cycles > 0);

      stats.end();

      // Repeat...
      if (this.running)
        requestAnimationFrame(this.frame.bind(this));
    },

    run: function() {
      if (!this.running) {
        this.running = true;
        last_frame_time = window.performance.now();
        requestAnimationFrame(this.frame.bind(this));
      }
    },

    pause: function() {
      this.running = false;
    },

    step: function() {
      X.Video.step(X.CPU.step());
      X.Debugger.update();
    },

  };

})();
<|endoftext|>


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

  angular
    .module(ApplicationConfiguration.applicationModuleName)
    .config(toastConfig)
    .config(textAngularConfig)
    .config(loadingBarConfig)
    .config(momentPickerConfig)
    .run(runConfig);

  toastConfig.$inject = ['toastrConfig'];
  function toastConfig(toastrConfig) {
    angular.extend(toastrConfig, {
      allowHtml: false,
      autoDismiss: true,
      closeButton: true,
      // containerId: 'toast-container',
      maxOpened: 5,
      newestOnTop: false,
      positionClass: 'toast-bottom-right',
      preventDuplicates: false,
      preventOpenDuplicates: false,
      target: 'body'
    });
  }

  textAngularConfig.$inject = ['$provide'];
  function textAngularConfig($provide) {
    $provide.decorator('taOptions', ['taRegisterTool', 'taToolFunctions', '$delegate',
      function (taRegisterTool, taToolFunctions, taOptions) {
        taRegisterTool('uploadImage', {
          iconclass: 'fa fa-upload',
          tooltiptext: 'Upload an image',
          onElementSelect: {
            element: 'img',
            action: taToolFunctions.imgOnSelectAction
          },
          action: function () {
            var $editor = this.$editor;

            // Create a virtual input element.
            var input = document.createElement('input');
            input.type = 'file';
            // input.accept = 'image/*';

            input.onchange = function () {
              alert(1);
              var reader = new FileReader();
              if (this.files && this.files[0]) {
                alert(3);
                reader.onload = function (e) {
                  alert(e.target.result);
                  $editor().wrapSelection('insertHtml', '

', true);
                };
                reader.readAsDataURL(this.files[0]);
              } else {
                alert(2);
              }
            };
            // Click on a virtual input element.
            input.click();
          }
        });
        taOptions.toolbar = [
          ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'quote'],
          ['bold', 'italics', 'underline', 'strikeThrough', 'ul', 'ol', 'redo', 'undo'],
          ['justifyLeft', 'justifyCenter', 'justifyRight', 'indent', 'outdent'],
          ['html', 'insertImage', 'insertLink', 'insertVideo', 'uploadImage']
        ];
        // taOptions.toolbar[3].push('uploadImage');
        return taOptions;
      }
    ]);
  }

  loadingBarConfig.$inject = ['cfpLoadingBarProvider'];
  function loadingBarConfig(cfpLoadingBarProvider) {
    // Loading bar
    cfpLoadingBarProvider.includeSpinner = false;
    cfpLoadingBarProvider.latencyThreshold = 1;
  }
  momentPickerConfig.$inject = ['momentPickerProvider'];
  function momentPickerConfig(momentPickerProvider) {
    momentPickerProvider.options({
      minutesFormat: 'HH:mm'
    });
  }
  function runConfig(amMoment) {
    moment.tz.add([
      'Asia/Tokyo|JST JDT|-90 -a0|010101010|-QJH0 QL0 1lB0 13X0 1zB0 NX0 1zB0 NX0|38e6',
      'Asia/Ho_Chi_Minh|LMT PLMT +07 +08 +09|-76.E -76.u -70 -80 -90|0123423232|-2yC76.E bK00.a 1h7b6.u 5lz0 18o0 3Oq0 k5b0 aW00 BAM0|90e5'
    ]);
    moment.tz.setDefault('Asia/Tokyo');
    moment.locale('ja');
    amMoment.changeLocale('ja');
  }
}());
<commit_msg>Commited from HaNhatLenh at Sat, Aug 19, 2017 10:42:03 AM<commit_after>(function () {
  'use strict';

  angular
    .module(ApplicationConfiguration.applicationModuleName)
    .config(toastConfig)
    .config(textAngularConfig)
    .config(loadingBarConfig)
    .config(momentPickerConfig)
    .run(runConfig);

  toastConfig.$inject = ['toastrConfig'];
  function toastConfig(toastrConfig) {
    angular.extend(toastrConfig, {
      allowHtml: false,
      autoDismiss: true,
      closeButton: true,
      // containerId: 'toast-container',
      maxOpened: 5,
      newestOnTop: false,
      positionClass: 'toast-bottom-right',
      preventDuplicates: false,
      preventOpenDuplicates: false,
      target: 'body'
    });
  }

  textAngularConfig.$inject = ['$provide', 'FileUploader'];
  function textAngularConfig($provide) {
    var uploader = new FileUploader({
      url: 'api/polls/images',
      alias: 'pollImageUpload'
    });
    uploader.filters.push({
      name: 'imageFilter',
      fn: function (item, options) {
        var type = '|' + item.type.slice(item.type.lastIndexOf('/') + 1) + '|';
        return '|jpg|png|jpeg|bmp|gif|'.indexOf(type) !== -1;
      }
    });
    $provide.decorator('taOptions', ['taRegisterTool', 'taToolFunctions', '$delegate',
      function (taRegisterTool, taToolFunctions, taOptions) {
        taRegisterTool('uploadImage', {
          iconclass: 'fa fa-upload',
          tooltiptext: 'Upload an image',
          onElementSelect: {
            element: 'img',
            action: taToolFunctions.imgOnSelectAction
          },
          action: function () {
            uploader.onAfterAddingAll = function (addedFileItems) {
              console.info('onAfterAddingAll', addedFileItems);
            };
            uploader.onSuccessItem = function (fileItem, response, status, headers) {
              console.info('onSuccessItem', fileItem, response, status, headers);
            };
            uploader.onErrorItem = function (fileItem, response, status, headers) {
              console.info('onErrorItem', fileItem, response, status, headers);
            };
            uploader.onCancelItem = function (fileItem, response, status, headers) {
              console.info('onCancelItem', fileItem, response, status, headers);
            };
            uploader.onCompleteItem = function (fileItem, response, status, headers) {
              console.info('onCompleteItem', fileItem, response, status, headers);
            };
            uploader.onCompleteAll = function () {
              console.info('onCompleteAll');
            };
            console.log('Button upload clicked');
            // var $editor = this.$editor;

            // Create a virtual input element.
            // var input = document.createElement('input');
            // input.type = 'file';
            // // input.accept = 'image/*';

            // input.onchange = function () {
            //   alert(1);
            //   var reader = new FileReader();
            //   if (this.files && this.files[0]) {
            //     alert(3);
            //     reader.onload = function (e) {
            //       alert(e.target.result);
            //       $editor().wrapSelection('insertHtml', '

', true);
            //     };
            //     reader.readAsDataURL(this.files[0]);
            //   } else {
            //     alert(2);
            //   }
            // };
            // // Click on a virtual input element.
            // input.click();
          }
        });
        taOptions.toolbar = [
          ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'quote'],
          ['bold', 'italics', 'underline', 'strikeThrough', 'ul', 'ol', 'redo', 'undo'],
          ['justifyLeft', 'justifyCenter', 'justifyRight', 'indent', 'outdent'],
          ['html', 'insertImage', 'insertLink', 'insertVideo', 'uploadImage']
        ];
        // taOptions.toolbar[3].push('uploadImage');
        return taOptions;
      }
    ]);
  }

  loadingBarConfig.$inject = ['cfpLoadingBarProvider'];
  function loadingBarConfig(cfpLoadingBarProvider) {
    // Loading bar
    cfpLoadingBarProvider.includeSpinner = false;
    cfpLoadingBarProvider.latencyThreshold = 1;
  }
  momentPickerConfig.$inject = ['momentPickerProvider'];
  function momentPickerConfig(momentPickerProvider) {
    momentPickerProvider.options({
      minutesFormat: 'HH:mm'
    });
  }
  function runConfig(amMoment) {
    moment.tz.add([
      'Asia/Tokyo|JST JDT|-90 -a0|010101010|-QJH0 QL0 1lB0 13X0 1zB0 NX0 1zB0 NX0|38e6',
      'Asia/Ho_Chi_Minh|LMT PLMT +07 +08 +09|-76.E -76.u -70 -80 -90|0123423232|-2yC76.E bK00.a 1h7b6.u 5lz0 18o0 3Oq0 k5b0 aW00 BAM0|90e5'
    ]);
    moment.tz.setDefault('Asia/Tokyo');
    moment.locale('ja');
    amMoment.changeLocale('ja');
  }
}());
<|endoftext|>


<commit_before>angular.module('ngWhisk')
    .controller('requestController', function($scope, $http, $log, $rootScope, ngDialog) {
        $log.log('inside');
        var API_URL = 'https://6e28847c-de9b-4446-8207-c2fadad1d143-gws.api-gw.mybluemix.net/OpenWhiskContact/api/v1'; // OpenWhisk exposed API
        $scope.emailSent = true; // setting message logic to false not display any message by default

        $scope.sendMail = function () { //The send button will call this method to make an API to a OpenWhisk Action exposed as a API

            //scope binding the form data
            var data = {
                myName: $scope.myName,
                myEmail: $scope.myEmail,
                myUrl: $scope.myUrl,
                myDescription: $scope.myDescription
            };
            // adding content type for post header, this is needed for when calling OpenWhisk API
            var config = {
                headers : {
                    'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
                }
            };
            // Simple POST request example (passing data) :
            $http.post(API_URL, data, config)
                .then(function(response) {
                    // this callback will be called asynchronously
                    // when the response is available
                    $log.log('Email Sent with response status of: ' + JSON.stringify(response.status));
                    $scope.emailSent = true;

                    // Injecting success into the array of alerts
                    $scope.alerts = [ {type: 'success', msg: ''} ];
                    $scope.alerts[0].msg = 'Thanks, ' + $scope.myName + ' we have got your request, and we will be in touch. ';

                    // After user sent the email, then clear the values to be empty
                    $scope.myName = "";
                    $scope.myEmail = "";
                    $scope.myUrl = "";
                    $scope.myDescription = "";
                }, function(response) {
                    // called asynchronously if an error occurs
                    // or server returns response with an error status.
                    $log.log("Error occurred with status: " + '' + JSON.stringify(response.status));
                    $scope.emailSent = true;

                    // if there was an error, then display this message
                    $scope.alerts = [
                        {type: 'danger', msg: ''}
                    ];
                    $scope.alerts[0].msg = 'Oops there was a problem sending your request, please contact Twana Daniel at twanaazi@ie.ibm.com';
                });
        };

        // Remove alert message area
        $scope.closeAlert = function (index) {
            $scope.alerts.splice(index, 1);
        };

        ///////Handling the popup
        $rootScope.jsonData = '{"foo": "bar"}';
        $rootScope.theme = 'ngdialog-theme-default';
        $scope.open = function () {
            ngDialog.open({ template: 'firstDialogId', controller: 'InsideCtrl' });
        };

        $scope.openDefault = function () {
            ngDialog.open({
                template: 'firstDialogId',
                controller: 'InsideCtrl',
                className: 'ngdialog-theme-default'
            });
        };

        $scope.openPlain = function () {
            $rootScope.theme = 'ngdialog-theme-plain';

            ngDialog.open({
                template: 'firstDialogId',
                controller: 'InsideCtrl',
                className: 'ngdialog-theme-plain'
            });
        };

        $scope.openTemplate = function () {
            $scope.value = true;

            ngDialog.open({
                template: 'externalTemplate.html',
                className: 'ngdialog-theme-plain',
                scope: $scope
            });
        };

    });

//popup ctrl
angular
    .module('ngWhisk')
    .controller('InsideCtrl', function ($scope, ngDialog) {
        $scope.openSecond = function () {
            ngDialog.open({
                template: '
Close all by click here!
',
                plain: true,
                closeByEscape: false,
                controller: 'SecondModalCtrl'
            });
        };
    });

angular
    .module('ngWhisk')
    .controller('SecondModalCtrl', function ($scope, ngDialog) {
        $scope.closeSecond = function () {
            ngDialog.close();
        };
    });

<commit_msg>debug message<commit_after>angular.module('ngWhisk')
    .controller('requestController', function($scope, $http, $log, $rootScope, ngDialog) {
        $log.log('inside');
        var API_URL = 'https://6e28847c-de9b-4446-8207-c2fadad1d143-gws.api-gw.mybluemix.net/OpenWhiskContact/api/v1'; // OpenWhisk exposed API
        $scope.emailSent = false; // setting message logic to false not display any message by default

        $scope.sendMail = function () { //The send button will call this method to make an API to a OpenWhisk Action exposed as a API

            //scope binding the form data
            var data = {
                myName: $scope.myName,
                myEmail: $scope.myEmail,
                myUrl: $scope.myUrl,
                myDescription: $scope.myDescription
            };
            // adding content type for post header, this is needed for when calling OpenWhisk API
            var config = {
                headers : {
                    'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
                }
            };
            // Simple POST request example (passing data) :
            $http.post(API_URL, data, config)
                .then(function(response) {
                    // this callback will be called asynchronously
                    // when the response is available
                    $log.log('Email Sent with response status of: ' + JSON.stringify(response.status));
                    $scope.emailSent = true;

                    // Injecting success into the array of alerts
                    $scope.alerts = [ {type: 'success', msg: ''} ];
                    $scope.alerts[0].msg = 'Thanks, ' + $scope.myName + ' we have got your request, and we will be in touch. ';

                    // After user sent the email, then clear the values to be empty
                    $scope.myName = "";
                    $scope.myEmail = "";
                    $scope.myUrl = "";
                    $scope.myDescription = "";
                }, function(response) {
                    // called asynchronously if an error occurs
                    // or server returns response with an error status.
                    $log.log("Error occurred with status: " + '' + JSON.stringify(response.status));
                    $scope.alerts[0].msg = JSON.stringify(response.status);
                    $scope.emailSent = true;

                    // if there was an error, then display this message
                    $scope.alerts = [
                        {type: 'danger', msg: ''}
                    ];
                    //$scope.alerts[0].msg = 'Oops there was a problem sending your request, please contact Twana Daniel at twanaazi@ie.ibm.com';
                });
        };

        // Remove alert message area
        $scope.closeAlert = function (index) {
            $scope.alerts.splice(index, 1);
        };

        ///////Handling the popup
        $rootScope.jsonData = '{"foo": "bar"}';
        $rootScope.theme = 'ngdialog-theme-default';
        $scope.open = function () {
            ngDialog.open({ template: 'firstDialogId', controller: 'InsideCtrl' });
        };

        $scope.openDefault = function () {
            ngDialog.open({
                template: 'firstDialogId',
                controller: 'InsideCtrl',
                className: 'ngdialog-theme-default'
            });
        };

        $scope.openPlain = function () {
            $rootScope.theme = 'ngdialog-theme-plain';

            ngDialog.open({
                template: 'firstDialogId',
                controller: 'InsideCtrl',
                className: 'ngdialog-theme-plain'
            });
        };

        $scope.openTemplate = function () {
            $scope.value = true;

            ngDialog.open({
                template: 'externalTemplate.html',
                className: 'ngdialog-theme-plain',
                scope: $scope
            });
        };

    });

//popup ctrl
angular
    .module('ngWhisk')
    .controller('InsideCtrl', function ($scope, ngDialog) {
        $scope.openSecond = function () {
            ngDialog.open({
                template: '
Close all by click here!
',
                plain: true,
                closeByEscape: false,
                controller: 'SecondModalCtrl'
            });
        };
    });

angular
    .module('ngWhisk')
    .controller('SecondModalCtrl', function ($scope, ngDialog) {
        $scope.closeSecond = function () {
            ngDialog.close();
        };
    });

<|endoftext|>


<commit_before>import React, { Component } from "react";
import PropTypes from "prop-types";
import { ThemeContext } from "@hig/theme-context";
import { css } from "emotion";
import stylesheet from "./Surface.stylesheet";
import {
  AVAILABLE_LEVELS,
  AVAILABLE_SPACINGS,
  AVAILABLE_SHADOWS,
  AVAILABLE_BORDER_RADII
} from "./constants";

export default class Surface extends Component {
  static propTypes = {
    /**
     * Specifies the the radius of the border. The default is no radius.
     */
    borderRadius: PropTypes.oneOf(AVAILABLE_BORDER_RADII),
    /**
     * Children to be rendered within the component.
     */
    children: PropTypes.node,
    /**
     * Specifies the amount of padding to be applied horizontally to the element. The default is no padding.
     */
    horizontalPadding: PropTypes.oneOf(AVAILABLE_SPACINGS),
    /**
     * Specifies the amount of padding to be applied vertically to the element. The default is no padding.
     */
    verticalPadding: PropTypes.oneOf(AVAILABLE_SPACINGS),
    /**
     * Specifies the color level of the background color for the element, respective of theme. The default is 100.
     */
    level: PropTypes.oneOf(AVAILABLE_LEVELS),
    /**
     * Specifies the level of shadow to surround the element.
     */
    shadow: PropTypes.oneOf(AVAILABLE_SHADOWS),
    /**
     * Enables specifying the semantic element to be rendered by the component
     * The default is "div"
     */
    tagName: PropTypes.string
  };

  static defaultProps = {
    level: 100,
    tagName: "div"
  };

  render() {
    const {
      borderRadius,
      children,
      horizontalPadding,
      verticalPadding,
      level,
      shadow,
      tagName
    } = this.props;

    return (
      <ThemeContext.Consumer>
        {({ resolvedRoles }) => {
          const styles = stylesheet(
            {
              borderRadius,
              horizontalPadding,
              verticalPadding,
              level,
              shadow
            },
            resolvedRoles
          );

          const Element = tagName;

          return <Element className={css(styles.surface)}>{children}</Element>;
        }}
      </ThemeContext.Consumer>
    );
  }
}
<commit_msg>feat: allow className to be passed down<commit_after>import React, { Component } from "react";
import PropTypes from "prop-types";
import { ThemeContext } from "@hig/theme-context";
import { css, cx } from "emotion";
import stylesheet from "./Surface.stylesheet";
import {
  AVAILABLE_LEVELS,
  AVAILABLE_SPACINGS,
  AVAILABLE_SHADOWS,
  AVAILABLE_BORDER_RADII
} from "./constants";

export default class Surface extends Component {
  static propTypes = {
    /**
     * Specifies the the radius of the border. The default is no radius.
     */
    borderRadius: PropTypes.oneOf(AVAILABLE_BORDER_RADII),
    /**
     * Children to be rendered within the component.
     */
    children: PropTypes.node,
    /**
     * Specifies the amount of padding to be applied horizontally to the element. The default is no padding.
     */
    horizontalPadding: PropTypes.oneOf(AVAILABLE_SPACINGS),
    /**
     * Specifies the amount of padding to be applied vertically to the element. The default is no padding.
     */
    verticalPadding: PropTypes.oneOf(AVAILABLE_SPACINGS),
    /**
     * Specifies the color level of the background color for the element, respective of theme. The default is 100.
     */
    level: PropTypes.oneOf(AVAILABLE_LEVELS),
    /**
     * Specifies the level of shadow to surround the element.
     */
    shadow: PropTypes.oneOf(AVAILABLE_SHADOWS),
    /**
     * Enables specifying the semantic element to be rendered by the component
     * The default is "div"
     */
    tagName: PropTypes.string
  };

  static defaultProps = {
    level: 100,
    tagName: "div"
  };

  render() {
    const {
      borderRadius,
      children,
      horizontalPadding,
      verticalPadding,
      level,
      shadow,
      tagName,
      ...otherProps
    } = this.props;
    const { className } = otherProps;
    return (
      <ThemeContext.Consumer>
        {({ resolvedRoles }) => {
          const styles = stylesheet(
            {
              borderRadius,
              horizontalPadding,
              verticalPadding,
              level,
              shadow
            },
            resolvedRoles
          );

          const Element = tagName;

          return (
            <Element className={cx(css(styles.surface), className)}>
              {children}
            </Element>
          );
        }}
      </ThemeContext.Consumer>
    );
  }
}
<|endoftext|>


<commit_before>/* global WeatherProvider */

/* Magic Mirror
 * Module: Weather
 *
 * By Michael Teeuw https://michaelteeuw.nl
 * MIT Licensed.
 */
Module.register("weather", {
	// Default module config.
	defaults: {
		weatherProvider: "openweathermap",
		roundTemp: false,
		type: "current", //current, forecast

		location: false,
		locationID: false,
		units: config.units,

		tempUnits: config.units,
		windUnits: config.units,

		updateInterval: 10 * 60 * 1000, // every 10 minutes
		animationSpeed: 1000,
		timeFormat: config.timeFormat,
		showPeriod: true,
		showPeriodUpper: false,
		showWindDirection: true,
		showWindDirectionAsArrow: false,
		useBeaufort: true,
		lang: config.language,
		showHumidity: false,
		showSun: true,
		degreeLabel: false,
		decimalSymbol: ".",
		showIndoorTemperature: false,
		showIndoorHumidity: false,
		maxNumberOfDays: 5,
		fade: true,
		fadePoint: 0.25, // Start on 1/4th of the list.

		initialLoadDelay: 0, // 0 seconds delay
		retryDelay: 2500,

		apiKey: "",
		apiSecret: "",
		apiVersion: "2.5",
		apiBase: "https://api.openweathermap.org/data/",
		weatherEndpoint: "/weather",

		appendLocationNameToHeader: true,
		calendarClass: "calendar",
		tableClass: "small",

		onlyTemp: false,
		showPrecipitationAmount: false,
		colored: false,
		showFeelsLike: true
	},

	// Module properties.
	weatherProvider: null,

	// Define required scripts.
	getStyles: function () {
		return ["font-awesome.css", "weather-icons.css", "weather.css"];
	},

	// Return the scripts that are necessary for the weather module.
	getScripts: function () {
		return ["moment.js", "weatherprovider.js", "weatherobject.js", "suncalc.js", this.file("providers/" + this.config.weatherProvider.toLowerCase() + ".js")];
	},

	// Override getHeader method.
	getHeader: function () {
		if (this.config.appendLocationNameToHeader && this.data.header !== undefined && this.weatherProvider) {
			return this.data.header + " " + this.weatherProvider.fetchedLocation();
		}

		return this.data.header;
	},

	// Start the weather module.
	start: function () {
		moment.locale(this.config.lang);

		// Initialize the weather provider.
		this.weatherProvider = WeatherProvider.initialize(this.config.weatherProvider, this);

		// Let the weather provider know we are starting.
		this.weatherProvider.start();

		// Add custom filters
		this.addFilters();

		// Schedule the first update.
		this.scheduleUpdate(this.config.initialLoadDelay);
	},

	// Override notification handler.
	notificationReceived: function (notification, payload, sender) {
		if (notification === "CALENDAR_EVENTS") {
			var senderClasses = sender.data.classes.toLowerCase().split(" ");
			if (senderClasses.indexOf(this.config.calendarClass.toLowerCase()) !== -1) {
				this.firstEvent = false;

				for (var e in payload) {
					var event = payload[e];
					if (event.location || event.geo) {
						this.firstEvent = event;
						//Log.log("First upcoming event with location: ", event);
						break;
					}
				}
			}
		} else if (notification === "INDOOR_TEMPERATURE") {
			this.indoorTemperature = this.roundValue(payload);
			this.updateDom(300);
		} else if (notification === "INDOOR_HUMIDITY") {
			this.indoorHumidity = this.roundValue(payload);
			this.updateDom(300);
		}
	},

	// Select the template depending on the display type.
	getTemplate: function () {
		return `${this.config.type.toLowerCase()}.njk`;
	},

	// Add all the data to the template.
	getTemplateData: function () {
		return {
			config: this.config,
			current: this.weatherProvider.currentWeather(),
			forecast: this.weatherProvider.weatherForecast(),
			indoor: {
				humidity: this.indoorHumidity,
				temperature: this.indoorTemperature
			}
		};
	},

	// What to do when the weather provider has new information available?
	updateAvailable: function () {
		Log.log("New weather information available.");
		this.updateDom(0);
		this.scheduleUpdate();
	},

	scheduleUpdate: function (delay = null) {
		var nextLoad = this.config.updateInterval;
		if (delay !== null && delay >= 0) {
			nextLoad = delay;
		}

		setTimeout(() => {
			if (this.config.type === "forecast") {
				this.weatherProvider.fetchWeatherForecast();
			} else {
				this.weatherProvider.fetchCurrentWeather();
			}
		}, nextLoad);
	},

	roundValue: function (temperature) {
		var decimals = this.config.roundTemp ? 0 : 1;
		return parseFloat(temperature).toFixed(decimals);
	},

	addFilters() {
		this.nunjucksEnvironment().addFilter(
			"formatTime",
			function (date) {
				date = moment(date);

				if (this.config.timeFormat !== 24) {
					if (this.config.showPeriod) {
						if (this.config.showPeriodUpper) {
							return date.format("h:mm A");
						} else {
							return date.format("h:mm a");
						}
					} else {
						return date.format("h:mm");
					}
				}

				return date.format("HH:mm");
			}.bind(this)
		);

		this.nunjucksEnvironment().addFilter(
			"unit",
			function (value, type) {
				if (type === "temperature") {
					if (this.config.tempUnits === "metric" || this.config.tempUnits === "imperial") {
						value += "°";
					}
					if (this.config.degreeLabel) {
						if (this.config.tempUnits === "metric") {
							value += "C";
						} else if (this.config.tempUnits === "imperial") {
							value += "F";
						} else {
							value += "K";
						}
					}
				} else if (type === "precip") {
					if (isNaN(value) || value === 0 || value.toFixed(2) === "0.00") {
						value = "";
					} else {
						if (this.config.weatherProvider === "ukmetoffice" || this.config.weatherProvider === "ukmetofficedatahub") {
							value += "%";
						} else {
							value = `${value.toFixed(2)} ${this.config.units === "imperial" ? "in" : "mm"}`;
						}
					}
				} else if (type === "humidity") {
					value += "%";
				}

				return value;
			}.bind(this)
		);

		this.nunjucksEnvironment().addFilter(
			"roundValue",
			function (value) {
				return this.roundValue(value);
			}.bind(this)
		);

		this.nunjucksEnvironment().addFilter(
			"decimalSymbol",
			function (value) {
				return value.toString().replace(/\./g, this.config.decimalSymbol);
			}.bind(this)
		);

		this.nunjucksEnvironment().addFilter(
			"calcNumSteps",
			function (forecast) {
				return Math.min(forecast.length, this.config.maxNumberOfDays);
			}.bind(this)
		);

		this.nunjucksEnvironment().addFilter(
			"opacity",
			function (currentStep, numSteps) {
				if (this.config.fade && this.config.fadePoint < 1) {
					if (this.config.fadePoint < 0) {
						this.config.fadePoint = 0;
					}
					var startingPoint = numSteps * this.config.fadePoint;
					var numFadesteps = numSteps - startingPoint;
					if (currentStep >= startingPoint) {
						return 1 - (currentStep - startingPoint) / numFadesteps;
					} else {
						return 1;
					}
				} else {
					return 1;
				}
			}.bind(this)
		);
	}
});
<commit_msg>Add TODO<commit_after>/* global WeatherProvider */

/* Magic Mirror
 * Module: Weather
 *
 * By Michael Teeuw https://michaelteeuw.nl
 * MIT Licensed.
 */
Module.register("weather", {
	// Default module config.
	defaults: {
		weatherProvider: "openweathermap",
		roundTemp: false,
		type: "current", //current, forecast

		location: false,
		locationID: false,
		units: config.units,

		tempUnits: config.units,
		windUnits: config.units,

		updateInterval: 10 * 60 * 1000, // every 10 minutes
		animationSpeed: 1000,
		timeFormat: config.timeFormat,
		showPeriod: true,
		showPeriodUpper: false,
		showWindDirection: true,
		showWindDirectionAsArrow: false,
		useBeaufort: true,
		lang: config.language,
		showHumidity: false,
		showSun: true,
		degreeLabel: false,
		decimalSymbol: ".",
		showIndoorTemperature: false,
		showIndoorHumidity: false,
		maxNumberOfDays: 5,
		fade: true,
		fadePoint: 0.25, // Start on 1/4th of the list.

		initialLoadDelay: 0, // 0 seconds delay
		retryDelay: 2500,

		apiKey: "",
		apiSecret: "",
		apiVersion: "2.5",
		apiBase: "https://api.openweathermap.org/data/", // TODO: this should not be part of the weather.js file, but should be contained in the openweatherprovider
		weatherEndpoint: "/weather",

		appendLocationNameToHeader: true,
		calendarClass: "calendar",
		tableClass: "small",

		onlyTemp: false,
		showPrecipitationAmount: false,
		colored: false,
		showFeelsLike: true
	},

	// Module properties.
	weatherProvider: null,

	// Define required scripts.
	getStyles: function () {
		return ["font-awesome.css", "weather-icons.css", "weather.css"];
	},

	// Return the scripts that are necessary for the weather module.
	getScripts: function () {
		return ["moment.js", "weatherprovider.js", "weatherobject.js", "suncalc.js", this.file("providers/" + this.config.weatherProvider.toLowerCase() + ".js")];
	},

	// Override getHeader method.
	getHeader: function () {
		if (this.config.appendLocationNameToHeader && this.data.header !== undefined && this.weatherProvider) {
			return this.data.header + " " + this.weatherProvider.fetchedLocation();
		}

		return this.data.header;
	},

	// Start the weather module.
	start: function () {
		moment.locale(this.config.lang);

		// Initialize the weather provider.
		this.weatherProvider = WeatherProvider.initialize(this.config.weatherProvider, this);

		// Let the weather provider know we are starting.
		this.weatherProvider.start();

		// Add custom filters
		this.addFilters();

		// Schedule the first update.
		this.scheduleUpdate(this.config.initialLoadDelay);
	},

	// Override notification handler.
	notificationReceived: function (notification, payload, sender) {
		if (notification === "CALENDAR_EVENTS") {
			var senderClasses = sender.data.classes.toLowerCase().split(" ");
			if (senderClasses.indexOf(this.config.calendarClass.toLowerCase()) !== -1) {
				this.firstEvent = false;

				for (var e in payload) {
					var event = payload[e];
					if (event.location || event.geo) {
						this.firstEvent = event;
						//Log.log("First upcoming event with location: ", event);
						break;
					}
				}
			}
		} else if (notification === "INDOOR_TEMPERATURE") {
			this.indoorTemperature = this.roundValue(payload);
			this.updateDom(300);
		} else if (notification === "INDOOR_HUMIDITY") {
			this.indoorHumidity = this.roundValue(payload);
			this.updateDom(300);
		}
	},

	// Select the template depending on the display type.
	getTemplate: function () {
		return `${this.config.type.toLowerCase()}.njk`;
	},

	// Add all the data to the template.
	getTemplateData: function () {
		return {
			config: this.config,
			current: this.weatherProvider.currentWeather(),
			forecast: this.weatherProvider.weatherForecast(),
			indoor: {
				humidity: this.indoorHumidity,
				temperature: this.indoorTemperature
			}
		};
	},

	// What to do when the weather provider has new information available?
	updateAvailable: function () {
		Log.log("New weather information available.");
		this.updateDom(0);
		this.scheduleUpdate();
	},

	scheduleUpdate: function (delay = null) {
		var nextLoad = this.config.updateInterval;
		if (delay !== null && delay >= 0) {
			nextLoad = delay;
		}

		setTimeout(() => {
			if (this.config.type === "forecast") {
				this.weatherProvider.fetchWeatherForecast();
			} else {
				this.weatherProvider.fetchCurrentWeather();
			}
		}, nextLoad);
	},

	roundValue: function (temperature) {
		var decimals = this.config.roundTemp ? 0 : 1;
		return parseFloat(temperature).toFixed(decimals);
	},

	addFilters() {
		this.nunjucksEnvironment().addFilter(
			"formatTime",
			function (date) {
				date = moment(date);

				if (this.config.timeFormat !== 24) {
					if (this.config.showPeriod) {
						if (this.config.showPeriodUpper) {
							return date.format("h:mm A");
						} else {
							return date.format("h:mm a");
						}
					} else {
						return date.format("h:mm");
					}
				}

				return date.format("HH:mm");
			}.bind(this)
		);

		this.nunjucksEnvironment().addFilter(
			"unit",
			function (value, type) {
				if (type === "temperature") {
					if (this.config.tempUnits === "metric" || this.config.tempUnits === "imperial") {
						value += "°";
					}
					if (this.config.degreeLabel) {
						if (this.config.tempUnits === "metric") {
							value += "C";
						} else if (this.config.tempUnits === "imperial") {
							value += "F";
						} else {
							value += "K";
						}
					}
				} else if (type === "precip") {
					if (isNaN(value) || value === 0 || value.toFixed(2) === "0.00") {
						value = "";
					} else {
						if (this.config.weatherProvider === "ukmetoffice" || this.config.weatherProvider === "ukmetofficedatahub") {
							value += "%";
						} else {
							value = `${value.toFixed(2)} ${this.config.units === "imperial" ? "in" : "mm"}`;
						}
					}
				} else if (type === "humidity") {
					value += "%";
				}

				return value;
			}.bind(this)
		);

		this.nunjucksEnvironment().addFilter(
			"roundValue",
			function (value) {
				return this.roundValue(value);
			}.bind(this)
		);

		this.nunjucksEnvironment().addFilter(
			"decimalSymbol",
			function (value) {
				return value.toString().replace(/\./g, this.config.decimalSymbol);
			}.bind(this)
		);

		this.nunjucksEnvironment().addFilter(
			"calcNumSteps",
			function (forecast) {
				return Math.min(forecast.length, this.config.maxNumberOfDays);
			}.bind(this)
		);

		this.nunjucksEnvironment().addFilter(
			"opacity",
			function (currentStep, numSteps) {
				if (this.config.fade && this.config.fadePoint < 1) {
					if (this.config.fadePoint < 0) {
						this.config.fadePoint = 0;
					}
					var startingPoint = numSteps * this.config.fadePoint;
					var numFadesteps = numSteps - startingPoint;
					if (currentStep >= startingPoint) {
						return 1 - (currentStep - startingPoint) / numFadesteps;
					} else {
						return 1;
					}
				} else {
					return 1;
				}
			}.bind(this)
		);
	}
});
<|endoftext|>


<commit_before>/**
*
* pull-to-reload
*
* A pull-to-reload system that is compatible with both both web and mobile.
* Configurable with loads of options.
*
* @author Erlend Ellingsen <erlend.ame@gmail.com>
* @copyright MIT, Erlend Ellingsen
* @version	1.1	05.03.2017
*/

var PullToReload = function (optsUser) {
	var self = this;

    // --- OPTIONS ---
	this.opts = {
		'refresh-element': 'ptr', // Required
		'content-element': 'content', // Required
		'border-height': 1,
		height: 80,
		'font-size': '30px',
		threshold: 20,
		'pre-content': '...',
		'loading-content': 'Loading...',
		'callback-loading': function () {
			setTimeout(function () {
				self.loadingEnd();
			}, 1000);
		} // Required
	};

    // Overwrite options with user-options if present
	for (var prop in self.opts) {
		if (optsUser[prop] !== undefined) {
			self.opts[prop] = optsUser[prop];
		}
	}

    // --- INIT CODE ---
	this.ptr = document.querySelector('#' + self.opts['refresh-element']);
	this.content = document.querySelector('#' + self.opts['content-element']);

    // --- STYLING ---

    // Set style
	this.ptr.style.padding = '0px';
	this.ptr.style.margin = '0px';
	this.ptr.style.display = 'block';
	this.ptr.style.height = self.opts.height + 'px';
	this.ptr.style.border = self.opts['border-height'] + 'px solid #000';
	this.ptr.style.borderTop = '0px';
	this.ptr.style.borderLeft = '0px';
	this.ptr.style.borderRight = '0px';
	this.ptr.style.textAlign = 'center';
	this.ptr.style.lineHeight = self.opts.height + 'px';
	this.ptr.style.fontSize = self.opts['font-size'];

    // Hide the margin
	this.ptr.style.marginTop = '-' + (self.opts['border-height'] + self.opts.height) + 'px';

    // --- CODE ---

    // --- CODE: HANDLING  ---
	this.loadingStart = function () {
		this.ptr.innerHTML = self.opts['loading-content'];

		self.opts['callback-loading'](); // Call callback
        // end loadingStart
	};

	this.loadingEnd = function () {
		this.ptr.innerHTML = self.opts['pre-content'];
		this.ptr.style.marginTop = '-' + (self.opts['border-height'] + self.opts.height + 'px');

        // end loadingEnd
	};

    // --- CODE: COMMON FUNCS ---
	this.getPageY = function (event) {
		if (event.pageY === undefined && event.touches !== undefined) {
			if (event.touches.length <= 0) {
				return false;
			}
			event.pageY = event.touches[event.touches.length - 1].pageY;
		}
		return event.pageY;

        // end getPageY
	};

    // --- CODE: EVENTS  ---

    // EVENT: MOUSEUP
	this.isDragging = false;
	this.isThresholdReached = false;
	this.posStart = 0;

	self.content.addEventListener('touchstart', function (event) {
		self.mouseStart(event);
	});

	self.content.addEventListener('mousedown', function (event) {
		self.mouseStart(event);
	});

	this.mouseStart = function (event) {
		event.preventDefault();
		event.stopImmediatePropagation();

		self.isDragging = true;
		self.isThresholdReached = false;

		self.posStart = self.getPageY(event);

        // end mousedown touchstart
	};

    // EVENT: MOUSEUP
	document.addEventListener('touchmove', function (event) {
		self.mouseMove(event);
	});

	document.addEventListener('mousemove', function (event) {
		self.mouseMove(event);
	});

	this.mouseMove = function (event) {
		if (!self.isDragging) {
			return;
		}

		event.preventDefault();
		event.stopImmediatePropagation();

        // Calculate the drag distance
        // Android / Chrome compability. Sometimes consists of a list of touches.
		event.pageY = self.getPageY(event);
		if (event.pageY === false) {
			return;
		}

		var dragDistance = (event.pageY - self.posStart);

		if (dragDistance <= 0) {
			return;
		} // Do not inverse the drag..

		var newMargin = (self.opts['border-height'] + (self.opts.height - dragDistance));
		if (newMargin <= 0) {
			return;
		}

        // Update
		if (newMargin <= self.opts.threshold) {
			self.isThresholdReached = true;
		}

		self.ptr.style.marginTop = '-' + (newMargin + 'px');

        // end mousemove touchmove
	};

    // EVENT: MOUSEUP
	document.addEventListener('touchend', function (event) {
		self.mouseEnd(event);
	});
	document.addEventListener('mouseup', function (event) {
		self.mouseEnd(event);
	});

	this.mouseEnd = function (event) {
		if (!self.isDragging) {
			return;
		}

		event.preventDefault();
		event.stopImmediatePropagation();

		if (self.isThresholdReached) {
            // Set margin to show entire
			self.ptr.style.marginTop = '0px';

			self.isDragging = false;
			self.isThresholdReached = false;

			self.loadingStart();
			return;
		}

        // Reset margin
		self.ptr.style.marginTop = '-' + (self.opts['border-height'] + self.opts.height + 'px');

		self.isDragging = false;
		self.isThresholdReached = false;

        // end mouseup touchend
	};

    // end PullToReload
};
<commit_msg>Correct version number<commit_after>/**
*
* pull-to-reload
*
* A pull-to-reload system that is compatible with both both web and mobile.
* Configurable with loads of options.
*
* @author Erlend Ellingsen <erlend.ame@gmail.com>
* @copyright MIT, Erlend Ellingsen
* @version	1.1.3	05.03.2017
*/

var PullToReload = function (optsUser) {
	var self = this;

    // --- OPTIONS ---
	this.opts = {
		'refresh-element': 'ptr', // Required
		'content-element': 'content', // Required
		'border-height': 1,
		height: 80,
		'font-size': '30px',
		threshold: 20,
		'pre-content': '...',
		'loading-content': 'Loading...',
		'callback-loading': function () {
			setTimeout(function () {
				self.loadingEnd();
			}, 1000);
		} // Required
	};

    // Overwrite options with user-options if present
	for (var prop in self.opts) {
		if (optsUser[prop] !== undefined) {
			self.opts[prop] = optsUser[prop];
		}
	}

    // --- INIT CODE ---
	this.ptr = document.querySelector('#' + self.opts['refresh-element']);
	this.content = document.querySelector('#' + self.opts['content-element']);

    // --- STYLING ---

    // Set style
	this.ptr.style.padding = '0px';
	this.ptr.style.margin = '0px';
	this.ptr.style.display = 'block';
	this.ptr.style.height = self.opts.height + 'px';
	this.ptr.style.border = self.opts['border-height'] + 'px solid #000';
	this.ptr.style.borderTop = '0px';
	this.ptr.style.borderLeft = '0px';
	this.ptr.style.borderRight = '0px';
	this.ptr.style.textAlign = 'center';
	this.ptr.style.lineHeight = self.opts.height + 'px';
	this.ptr.style.fontSize = self.opts['font-size'];

    // Hide the margin
	this.ptr.style.marginTop = '-' + (self.opts['border-height'] + self.opts.height) + 'px';

    // --- CODE ---

    // --- CODE: HANDLING  ---
	this.loadingStart = function () {
		this.ptr.innerHTML = self.opts['loading-content'];

		self.opts['callback-loading'](); // Call callback
        // end loadingStart
	};

	this.loadingEnd = function () {
		this.ptr.innerHTML = self.opts['pre-content'];
		this.ptr.style.marginTop = '-' + (self.opts['border-height'] + self.opts.height + 'px');

        // end loadingEnd
	};

    // --- CODE: COMMON FUNCS ---
	this.getPageY = function (event) {
		if (event.pageY === undefined && event.touches !== undefined) {
			if (event.touches.length <= 0) {
				return false;
			}
			event.pageY = event.touches[event.touches.length - 1].pageY;
		}
		return event.pageY;

        // end getPageY
	};

    // --- CODE: EVENTS  ---

    // EVENT: MOUSEUP
	this.isDragging = false;
	this.isThresholdReached = false;
	this.posStart = 0;

	self.content.addEventListener('touchstart', function (event) {
		self.mouseStart(event);
	});

	self.content.addEventListener('mousedown', function (event) {
		self.mouseStart(event);
	});

	this.mouseStart = function (event) {
		event.preventDefault();
		event.stopImmediatePropagation();

		self.isDragging = true;
		self.isThresholdReached = false;

		self.posStart = self.getPageY(event);

        // end mousedown touchstart
	};

    // EVENT: MOUSEUP
	document.addEventListener('touchmove', function (event) {
		self.mouseMove(event);
	});

	document.addEventListener('mousemove', function (event) {
		self.mouseMove(event);
	});

	this.mouseMove = function (event) {
		if (!self.isDragging) {
			return;
		}

		event.preventDefault();
		event.stopImmediatePropagation();

        // Calculate the drag distance
        // Android / Chrome compability. Sometimes consists of a list of touches.
		event.pageY = self.getPageY(event);
		if (event.pageY === false) {
			return;
		}

		var dragDistance = (event.pageY - self.posStart);

		if (dragDistance <= 0) {
			return;
		} // Do not inverse the drag..

		var newMargin = (self.opts['border-height'] + (self.opts.height - dragDistance));
		if (newMargin <= 0) {
			return;
		}

        // Update
		if (newMargin <= self.opts.threshold) {
			self.isThresholdReached = true;
		}

		self.ptr.style.marginTop = '-' + (newMargin + 'px');

        // end mousemove touchmove
	};

    // EVENT: MOUSEUP
	document.addEventListener('touchend', function (event) {
		self.mouseEnd(event);
	});
	document.addEventListener('mouseup', function (event) {
		self.mouseEnd(event);
	});

	this.mouseEnd = function (event) {
		if (!self.isDragging) {
			return;
		}

		event.preventDefault();
		event.stopImmediatePropagation();

		if (self.isThresholdReached) {
            // Set margin to show entire
			self.ptr.style.marginTop = '0px';

			self.isDragging = false;
			self.isThresholdReached = false;

			self.loadingStart();
			return;
		}

        // Reset margin
		self.ptr.style.marginTop = '-' + (self.opts['border-height'] + self.opts.height + 'px');

		self.isDragging = false;
		self.isThresholdReached = false;

        // end mouseup touchend
	};

    // end PullToReload
};
<|endoftext|>


<commit_before>// index.js of anonChat Copyright 2015 Paul Beaudet, MIT Licence see LICENCE for detials
// Constants, these can change the behavior of the application
var WAIT_TIME = 30;  // time to wait for talking turn
var NUM_ENTRIES = 6; // number of dialog rows allowed in the application
var NUM_TIMERS = NUM_ENTRIES + 1; // timer 6 is for the send button
// call NUM_ENTRIES for send button timer
var SEND_TIMER = NUM_ENTRIES;

// Methods revolving around tracking possition of row
var edit = { // dep: rows, time, textBar, edit
    row: 1,
    increment: function(){ // decides with row to edit to and when the dialog needs to scoot up
        if(edit.row < NUM_ENTRIES - 2)         { edit.row++; }
        else if ( edit.row === NUM_ENTRIES - 2){ edit.row = NUM_ENTRIES - 1; }
        else if ( edit.row < NUM_ENTRIES + 1)  { edit.scoot(); }
    },
    onStart: function(){ // called when starting a message
        if(edit.row === NUM_ENTRIES){
            edit.scoot();
            edit.row--;
        }  // checks to see if a scoot is needed upon typing
        time.from(edit.row, "You");
    },
    type: function(data){
        var thisRow = 0;
        if(data.row){thisRow = data.row;} else{thisRow = edit.row;}
        rows.dialog[thisRow].innerHTML = data.text;
    },
    myTurn: function(){
        send.mode = CHAT;             // allow user to type
        textBar.changeAction(CHAT);   // clear text box and use correct dialog
        time.from(edit.row, "other"); // write other onto the last row
        edit.increment();             // increment place to write to
        time.countDown(SEND_TIMER, send.passOn);     // time out input
    },
    scoot: function(){
        for(var i = 2; i < NUM_ENTRIES; i++){
            rows.dialog[i-1].innerHTML = rows.dialog[i].innerHTML;
            time.rs[i-1].innerHTML = time.rs[i].innerHTML;
        }
        rows.dialog[NUM_ENTRIES - 1].innerHTML = "";
        time.rs[NUM_ENTRIES - 1].innerHTML = "";
    }
}

// transition handling of visual elements
var trans = { // dep: send, time, rows, textBar
    selectTopic: function(){  // respond to someone else's topic
        var row = this.id[this.id.length-1];
        var user = topic.user[parseInt(row)];
        send.to = user;
        sock.et.emit("selectTopic", user); // signal which user that needs to be connected with
        send.mode = CHAT; // signal to the sender that is it now time to chat
        trans.ition({perspec: "other", head: rows.dialog[row].innerHTML});
        time.countDown(SEND_TIMER, send.passOn); // set stopwatch for sending a message
    },
    gotBreak: function(user){         // someone responded to users personal
        send.to = user;               // keep track of who we are talking to
        time.stopSend("");            // stop time to live timer
        send.mode = BLOCK;            // signal user is listening to someones response
        trans.ition({perspec: "you", head: document.getElementById("textEntry").value});
    },
    ition: function(opener){
        time.clear();
        rows.reset();
        if(opener){
            time.from(0, opener.perspec);           // write perspective to first row
            rows.dialog[0].innerHTML = opener.head; // write topic to top of page
            info.chat();       // set hint text for chat mode
            edit.row = 1;      // new dialog starts at possition 1
        } else {               // transition back to topic making and picking mode
            send.mode = TOPIC; // reset into topic mode
            info.home();       // Set hint text for topic picking mode
            edit.row = 0;      // topic can now posted to possition 0
            topic.user = [];   // clear users from old topic list if exist
        }
        textBar.changeAction(send.mode); // make sure send mode is properly set before trans.ition called
    }
}

// Typing modes
var TOPIC = 0; // users post or select topics
var CHAT  = 1; // two users chat one on one
var BLOCK = 2; // blocks user entry, waiting for either their topic to expire or chatting partner to finish

// sending logic
var send = { // dep: sock, trans, edit, textBar
    empty: true,
    mode: 0,
    to: '', // potential user id
    nonPrint: function(event){ // account for pressing the enter key
        if(send.mode === TOPIC || send.mode === CHAT){if(event.which == 13){send.passOn();}}
    },
    passOn: function(){
        if(send.mode === TOPIC){
            send.startTTL(); // start ttl timer, shows time topics have to live in send timer
        } else if (send.mode === CHAT){
            if(send.empty){
                sock.et.emit('endChat', send.to);
                trans.ition();     // trasition back to home screen
            } else {
                sock.et.emit('toOther', send.to);
                edit.increment();            // increase row number to edit
                send.mode = BLOCK;           // block user till other responds
                textBar.changeAction(BLOCK); // show wait notice
                time.stopSend("");           // stop the clock from running anymore
            }
        }
        send.empty = true; // it will be empty when it is responded to.
    },
    input: function(){
        if(send.mode === TOPIC){
            if(send.empty){
                send.empty = false;
                time.counter[SEND_TIMER] = WAIT_TIME - 1;  // note: Make sure post sent before timeout on other client
                time.countDown(SEND_TIMER, send.startTTL); // this is where breakers will start being timed
            }
            sock.et.emit("create", textBar.entry.value);   // create topic ( real time to server )
        }else if(send.mode === CHAT){
            if(send.empty){edit.onStart(); send.empty = false;} // account for nessisary transitions
            edit.type({text: textBar.entry.value, row: 0});     // print on own screen
            sock.et.emit("chat", {text: textBar.entry.value, id: send.to}); // send to other user
        }
        else if(send.mode === BLOCK){ // block more input from happening, leaving last sent message in box
            textBar.entry.value = textBar.entry.value.substring(0, textBar.entry.value.length -1);
        }
    },
    startTTL: function(){ // called when topic composition is complete
        sock.et.emit('post');         // Signal to the server that composition of topic is done
        time.stopSend(WAIT_TIME);     // in case this was called by passOn
        send.mode = BLOCK;            // block input till time to live is over
        textBar.changeAction(BLOCK);  // display notice of block
        time.countDown(SEND_TIMER, function(){
            time.stopSend("");        // reset timer
            send.empty = true;        // text is now empty
            send.mode = TOPIC;        // set so topics can be made again
            textBar.changeAction(TOPIC); // display notice that topics can be made again
        });
    }
}

// logic for recieving topics
var topic = { // dep: rows, time, edit
    user: [],
    post: function(ttl){ // re-adjust ttl (time to live) on post
        for(var row = 0; topic.user[row]; row++){
            if(topic.user[row] == ttl.user){
                clearTimeout(time.inProg[row]);                   // give counter at our row the right time to live
                time.counter[row] = ttl.ttl;
                time.countDown(row, function(){topic.done(row)}); // Set timer on this row
                return;
            }
        }
    },
    ttl: function(ttl){
        var row = 0;
        for(row; topic.user[row]; row++){ // check if this is coming from one of the existing listings
            if(topic.user[row] == ttl.user){
                edit.type({text: ttl.text, row: row}); // update changing real time text
                return;                                // if user was found this is end of what we need to do
            }
        } // in the case of getting this topic for the first time
        if( row < NUM_ENTRIES ){ // make sure there is still room on the page
            topic.user.push(ttl.user);                        // add this user to our list
            rows.button[row].style.visibility = "visible";    // make the button visible to the user
            time.counter[row] = ttl.ttl;                      // give counter at our row the right time to live
            time.countDown(row, function(){topic.done(row)}); // Set timer on this row
            edit.type({text: ttl.text, row: row});            // display first text
        } else { console.log("server sent me too many topics"); }
    },
    done: function(row) {           // this is the action to occur on count end
        rows.button[row].style.visibility = "hidden"; // on end hide button
        rows.dialog[row].innerHTML = "";              // on end remove dialog
        topic.user.splice(row, 1);                    // on end remove this user
    }
}

// -- socket handler
var sock = {  // dep: sockets.io, topic, trans, edit, send
    et: io(), // connect to server the page was served from
    init: function (){
        // Topic starting components
        sock.et.on('post', topic.post);         // starts timer and stores user of topic
        sock.et.on('topic', topic.ttl);         // grab time to live topics: timed from the getgo
        sock.et.on('chatInit', trans.gotBreak); // someone wants to chat with us
        // real time chat reception components
        sock.et.on('toMe', edit.type);          // recieve Real Time Text
        sock.et.on('yourTurn', edit.myTurn);    // signals when it is this clients turn to type
        sock.et.on('endChat', trans.ition);     // switch back to default appearence
    }
}

// informational header, this can change from screen to screen to indicate use information
var info = {
    mation: document.getElementById('info'),
    inProg: null,
    chat: function(){
        info.mation.innerHTML = "Chat: Pressing done while text box empty, ends chat";
        info.inProg = setTimeout(function(){
            info.mation.innerHTML = "Actions auto-complete on timeout";
        }, (WAIT_TIME / 2 * 1000));
    },
    home: function(){
        if(info.inProg){clearTimeout(info.inProg);}
        info.mation.innerHTML = "Pick or create topic";
    }
}

// timer logic
var time = { // dep: document
    rs: [],      // list of timer elements on page, build with init
    counter: [], // one exist per row, last is send timer
    inProg: [],  // IDs of timers in case clear is needed
    countDown: function(pos, ondone){
        if (time.counter[pos]) {
            time.counter[pos]--;
            time.rs[pos].innerHTML = "T-" + time.counter[pos];
            time.inProg[pos] = setTimeout(function(){time.countDown(pos, ondone);}, 1000);
        } else {
            time.rs[pos].innerHTML = "";
            time.counter[pos] = WAIT_TIME;
            if(ondone){ondone();}
        }
    },
    clear: function(){
        for (var i = 0; i < NUM_TIMERS; i++){
            if(time.inProg[i]){clearTimeout(time.inProg[i]);} // deactivate active timeouts
            time.rs[i].innerHTML = "";                        // empty timer text
            time.counter[i] = WAIT_TIME;                      // reset timeouts
        }
    },
    stopSend: function(text){
        clearTimeout(time.inProg[SEND_TIMER]);
        time.rs[SEND_TIMER].innerHTML = text;
        time.counter[SEND_TIMER] = WAIT_TIME;
    },
    init: function(){
        for(var i = 0; i < NUM_TIMERS; i++){time.rs.push(document.getElementById('timer' + i));}
    },
    from: function(whichRow, who){ // replaces time span elemement with perspective of user
        time.rs[whichRow].style.visibility = "visible"; // make the element visible from within invisible button
        time.rs[whichRow].innerHTML = who;              // which perspective its this
    }, // Should probably be done with a seperate element but for the sake of simplicity this one is reused
}

// Bottom of page text bar footer object
var textBar = { // dep: document, send
    entry: document.getElementById('textEntry'),
    button: document.getElementById('sendButton'),
    btnTxt: document.getElementById('sendText'),
    init: function(){
        textBar.entry.onkeydown = send.nonPrint; // deal with non-printable input
        textBar.entry.oninput = send.input;      // block when not user's turn
        textBar.button.onclick = send.passOn;
    },
    changeAction: function(mode){
        if(mode === TOPIC){
            textBar.btnTxt.innerHTML = "Make Topic ";
            textBar.entry.value = "";
        } else if ( mode === CHAT ){
            textBar.btnTxt.innerHTML = "Done ";
            textBar.entry.value = "";
        } else if ( mode === BLOCK){
            textBar.btnTxt.innerHTML = "Wait ";
        }
    }
}

// anything to do with the topic selection buttons or row data
var rows = { // dep: document, trans
    button: [],
    dialog: [],
    init: function() { // actions for selection of topic
        for(var i = 0; i < NUM_ENTRIES; i++){                        // for every entry and
            rows.dialog.push(document.getElementById("dialog" + i)); // store dialog elements
            rows.button.push(document.getElementById("button" + i)); // store a button element
            rows.button[i].onclick = trans.selectTopic;              // give the button its action
        }
    },
    reset: function() {
        for(var i = 0; i < NUM_ENTRIES; i++){                         // for every entry
            if(i){rows.dialog[i].innerHTML = "";}                     // set dialog to be empty
            else{rows.dialog[i].innerHTML = "Waiting for topics...";} // set a default entry for dialog 0
            rows.button[i].style.visibility = "hidden";               // hide the buttons
        }
    }
}

// sets up application on page load
var app = { // dep: rows, time, trans, textBar, sock, document
    // one call to methods used to start the application
    init: function () {
        document.getElementById("app").onload = function () {
            rows.init();     // setup row elements !do this first!
            time.init();     // set up timers
            trans.ition();   // default appearance
            textBar.init();  // Set-up bottom text bar
            sock.init();     // connect socket to server
        }
    }
};

// -- Global execution --
app.init(); // start the app
<commit_msg>Use a better name and get the right spacing after countdowns<commit_after>// index.js of anonChat Copyright 2015 Paul Beaudet, MIT Licence see LICENCE for detials
// Constants, these can change the behavior of the application
var WAIT_TIME = 30;  // time to wait for talking turn
var NUM_ENTRIES = 6; // number of dialog rows allowed in the application
var NUM_TIMERS = NUM_ENTRIES + 1; // timer 6 is for the send button
// call NUM_ENTRIES for send button timer
var SEND_TIMER = NUM_ENTRIES;

// Methods revolving around tracking possition of row
var edit = { // dep: rows, time, textBar, edit
    row: 1,
    increment: function(){ // decides with row to edit to and when the dialog needs to scoot up
        if(edit.row < NUM_ENTRIES - 2)         { edit.row++; }
        else if ( edit.row === NUM_ENTRIES - 2){ edit.row = NUM_ENTRIES - 1; }
        else if ( edit.row < NUM_ENTRIES + 1)  { edit.scoot(); }
    },
    onStart: function(){ // called when starting a message
        if(edit.row === NUM_ENTRIES){
            edit.scoot();
            edit.row--;
        }  // checks to see if a scoot is needed upon typing
        time.from(edit.row, "You");
    },
    type: function(data){
        var thisRow = 0;
        if(data.row){thisRow = data.row;} else{thisRow = edit.row;}
        rows.dialog[thisRow].innerHTML = data.text;
    },
    myTurn: function(){
        send.mode = CHAT;             // allow user to type
        textBar.changeAction(CHAT);   // clear text box and use correct dialog
        time.from(edit.row, "other"); // write other onto the last row
        edit.increment();             // increment place to write to
        time.countDown(SEND_TIMER, send.passOn);     // time out input
    },
    scoot: function(){
        for(var i = 2; i < NUM_ENTRIES; i++){
            rows.dialog[i-1].innerHTML = rows.dialog[i].innerHTML;
            time.rs[i-1].innerHTML = time.rs[i].innerHTML;
        }
        rows.dialog[NUM_ENTRIES - 1].innerHTML = "";
        time.rs[NUM_ENTRIES - 1].innerHTML = "";
    }
}

// transition handling of visual elements
var trans = { // dep: send, time, rows, textBar
    selectTopic: function(){  // respond to someone else's topic
        var row = this.id[this.id.length-1];
        var user = topic.user[parseInt(row)];
        send.to = user;
        sock.et.emit("selectTopic", user); // signal which user that needs to be connected with
        send.mode = CHAT; // signal to the sender that is it now time to chat
        trans.ition({perspec: "other", head: rows.dialog[row].innerHTML});
        time.countDown(SEND_TIMER, send.passOn); // set stopwatch for sending a message
    },
    gotTopic: function(user){         // someone responded to users personal
        send.to = user;               // keep track of who we are talking to
        time.stopSend("");            // stop time to live timer
        send.mode = BLOCK;            // signal user is listening to someones response
        trans.ition({perspec: "you", head: document.getElementById("textEntry").value});
    },
    ition: function(opener){
        time.clear();
        rows.reset();
        if(opener){
            time.from(0, opener.perspec);           // write perspective to first row
            rows.dialog[0].innerHTML = opener.head; // write topic to top of page
            info.chat();       // set hint text for chat mode
            edit.row = 1;      // new dialog starts at possition 1
        } else {               // transition back to topic making and picking mode
            send.mode = TOPIC; // reset into topic mode
            info.home();       // Set hint text for topic picking mode
            edit.row = 0;      // topic can now posted to possition 0
            topic.user = [];   // clear users from old topic list if exist
        }
        textBar.changeAction(send.mode); // make sure send mode is properly set before trans.ition called
    }
}

// Typing modes
var TOPIC = 0; // users post or select topics
var CHAT  = 1; // two users chat one on one
var BLOCK = 2; // blocks user entry, waiting for either their topic to expire or chatting partner to finish

// sending logic
var send = { // dep: sock, trans, edit, textBar
    empty: true,
    mode: 0,
    to: '', // potential user id
    nonPrint: function(event){ // account for pressing the enter key
        if(send.mode === TOPIC || send.mode === CHAT){if(event.which == 13){send.passOn();}}
    },
    passOn: function(){
        if(send.mode === TOPIC){
            send.startTTL(); // start ttl timer, shows time topics have to live in send timer
        } else if (send.mode === CHAT){
            if(send.empty){
                sock.et.emit('endChat', send.to);
                trans.ition();     // trasition back to home screen
            } else {
                sock.et.emit('toOther', send.to);
                edit.increment();            // increase row number to edit
                send.mode = BLOCK;           // block user till other responds
                textBar.changeAction(BLOCK); // show wait notice
                time.stopSend("");           // stop the clock from running anymore
            }
        }
        send.empty = true; // it will be empty when it is responded to.
    },
    input: function(){
        if(send.mode === TOPIC){
            if(send.empty){
                send.empty = false;
                time.counter[SEND_TIMER] = WAIT_TIME - 1;  // note: Make sure post sent before timeout on other client
                time.countDown(SEND_TIMER, send.startTTL); // this is where breakers will start being timed
            }
            sock.et.emit("create", textBar.entry.value);   // create topic ( real time to server )
        }else if(send.mode === CHAT){
            if(send.empty){edit.onStart(); send.empty = false;} // account for nessisary transitions
            edit.type({text: textBar.entry.value, row: 0});     // print on own screen
            sock.et.emit("chat", {text: textBar.entry.value, id: send.to}); // send to other user
        }
        else if(send.mode === BLOCK){ // block more input from happening, leaving last sent message in box
            textBar.entry.value = textBar.entry.value.substring(0, textBar.entry.value.length -1);
        }
    },
    startTTL: function(){ // called when topic composition is complete
        sock.et.emit('post');         // Signal to the server that composition of topic is done
        time.stopSend(WAIT_TIME);     // in case this was called by passOn
        send.mode = BLOCK;            // block input till time to live is over
        textBar.changeAction(BLOCK);  // display notice of block
        time.countDown(SEND_TIMER, function(){
            time.stopSend("");        // reset timer
            send.empty = true;        // text is now empty
            send.mode = TOPIC;        // set so topics can be made again
            textBar.changeAction(TOPIC); // display notice that topics can be made again
        });
    }
}

// logic for recieving topics
var topic = { // dep: rows, time, edit
    user: [],
    post: function(ttl){ // re-adjust ttl (time to live) on post
        for(var row = 0; topic.user[row]; row++){
            if(topic.user[row] == ttl.user){
                clearTimeout(time.inProg[row]);                   // give counter at our row the right time to live
                time.counter[row] = ttl.ttl;
                time.countDown(row, function(){topic.done(row)}); // Set timer on this row
                return;
            }
        }
    },
    ttl: function(ttl){
        var row = 0;
        for(row; topic.user[row]; row++){ // check if this is coming from one of the existing listings
            if(topic.user[row] == ttl.user){
                edit.type({text: ttl.text, row: row}); // update changing real time text
                return;                                // if user was found this is end of what we need to do
            }
        } // in the case of getting this topic for the first time
        if( row < NUM_ENTRIES ){ // make sure there is still room on the page
            topic.user.push(ttl.user);                        // add this user to our list
            rows.button[row].style.visibility = "visible";    // make the button visible to the user
            time.counter[row] = ttl.ttl;                      // give counter at our row the right time to live
            time.countDown(row, function(){topic.done(row)}); // Set timer on this row
            edit.type({text: ttl.text, row: row});            // display first text
        } else { console.log("server sent me too many topics"); }
    },
    done: function(row) {           // this is the action to occur on count end
        rows.button[row].style.visibility = "hidden"; // on end hide button
        rows.dialog[row].innerHTML = "";              // on end remove dialog
        topic.user.splice(row, 1);                    // on end remove this user
    }
}

// -- socket handler
var sock = {  // dep: sockets.io, topic, trans, edit, send
    et: io(), // connect to server the page was served from
    init: function (){
        // Topic starting components
        sock.et.on('post', topic.post);         // starts timer and stores user of topic
        sock.et.on('topic', topic.ttl);         // grab time to live topics: timed from the getgo
        sock.et.on('chatInit', trans.gotTopic); // someone wants to chat with us
        // real time chat reception components
        sock.et.on('toMe', edit.type);          // recieve Real Time Text
        sock.et.on('yourTurn', edit.myTurn);    // signals when it is this clients turn to type
        sock.et.on('endChat', trans.ition);     // switch back to default appearence
    }
}

// informational header, this can change from screen to screen to indicate use information
var info = {
    mation: document.getElementById('info'),
    inProg: null,
    chat: function(){
        info.mation.innerHTML = "Chat: Pressing done while text box empty, ends chat";
        info.inProg = setTimeout(function(){
            info.mation.innerHTML = "Actions auto-complete on timeout";
        }, (WAIT_TIME / 2 * 1000));
    },
    home: function(){
        if(info.inProg){clearTimeout(info.inProg);}
        info.mation.innerHTML = "Pick or create topic";
    }
}

// timer logic
var time = { // dep: document
    rs: [],      // list of timer elements on page, build with init
    counter: [], // one exist per row, last is send timer
    inProg: [],  // IDs of timers in case clear is needed
    countDown: function(pos, ondone){
        if (time.counter[pos]) {
            time.counter[pos]--;
            time.rs[pos].innerHTML = "T-" + time.counter[pos] + " ";
            time.inProg[pos] = setTimeout(function(){time.countDown(pos, ondone);}, 1000);
        } else {
            time.rs[pos].innerHTML = "";
            time.counter[pos] = WAIT_TIME;
            if(ondone){ondone();}
        }
    },
    clear: function(){
        for (var i = 0; i < NUM_TIMERS; i++){
            if(time.inProg[i]){clearTimeout(time.inProg[i]);} // deactivate active timeouts
            time.rs[i].innerHTML = "";                        // empty timer text
            time.counter[i] = WAIT_TIME;                      // reset timeouts
        }
    },
    stopSend: function(text){
        clearTimeout(time.inProg[SEND_TIMER]);
        time.rs[SEND_TIMER].innerHTML = text;
        time.counter[SEND_TIMER] = WAIT_TIME;
    },
    init: function(){
        for(var i = 0; i < NUM_TIMERS; i++){time.rs.push(document.getElementById('timer' + i));}
    },
    from: function(whichRow, who){ // replaces time span elemement with perspective of user
        time.rs[whichRow].style.visibility = "visible"; // make the element visible from within invisible button
        time.rs[whichRow].innerHTML = who;              // which perspective its this
    }, // Should probably be done with a seperate element but for the sake of simplicity this one is reused
}

// Bottom of page text bar footer object
var textBar = { // dep: document, send
    entry: document.getElementById('textEntry'),
    button: document.getElementById('sendButton'),
    btnTxt: document.getElementById('sendText'),
    init: function(){
        textBar.entry.onkeydown = send.nonPrint; // deal with non-printable input
        textBar.entry.oninput = send.input;      // block when not user's turn
        textBar.button.onclick = send.passOn;
    },
    changeAction: function(mode){
        if(mode === TOPIC){
            textBar.btnTxt.innerHTML = "Make Topic ";
            textBar.entry.value = "";
        } else if ( mode === CHAT ){
            textBar.btnTxt.innerHTML = "Done ";
            textBar.entry.value = "";
        } else if ( mode === BLOCK){
            textBar.btnTxt.innerHTML = "Wait ";
        }
    }
}

// anything to do with the topic selection buttons or row data
var rows = { // dep: document, trans
    button: [],
    dialog: [],
    init: function() { // actions for selection of topic
        for(var i = 0; i < NUM_ENTRIES; i++){                        // for every entry and
            rows.dialog.push(document.getElementById("dialog" + i)); // store dialog elements
            rows.button.push(document.getElementById("button" + i)); // store a button element
            rows.button[i].onclick = trans.selectTopic;              // give the button its action
        }
    },
    reset: function() {
        for(var i = 0; i < NUM_ENTRIES; i++){                         // for every entry
            if(i){rows.dialog[i].innerHTML = "";}                     // set dialog to be empty
            else{rows.dialog[i].innerHTML = "Waiting for topics...";} // set a default entry for dialog 0
            rows.button[i].style.visibility = "hidden";               // hide the buttons
        }
    }
}

// sets up application on page load
var app = { // dep: rows, time, trans, textBar, sock, document
    // one call to methods used to start the application
    init: function () {
        document.getElementById("app").onload = function () {
            rows.init();     // setup row elements !do this first!
            time.init();     // set up timers
            trans.ition();   // default appearance
            textBar.init();  // Set-up bottom text bar
            sock.init();     // connect socket to server
        }
    }
};

// -- Global execution --
app.init(); // start the app
<|endoftext|>


<commit_before>class MCTemplateBuilderMeasurementsComponentController {
    /*@ngInject*/
    constructor() {
        this.measurements = [];
        this.measurements.push("item 1");
    }
}

angular.module('materialscommons').component('mcTemplateBuilderMeasurements', {
    templateUrl: 'app/components/templates/mc-template-builder/mc-template-builder-measurements.html',
    controller: MCTemplateBuilderMeasurementsComponentController,
    bindings: {
        template: '<'
    }
});<commit_msg>No need for default element<commit_after>class MCTemplateBuilderMeasurementsComponentController {
    /*@ngInject*/
    constructor() {
        this.measurements = [];
        //this.measurements.push("item 1");
    }
}

angular.module('materialscommons').component('mcTemplateBuilderMeasurements', {
    templateUrl: 'app/components/templates/mc-template-builder/mc-template-builder-measurements.html',
    controller: MCTemplateBuilderMeasurementsComponentController,
    bindings: {
        template: '<'
    }
});<|endoftext|>