<commit_before>var File = require('enb-source-map/lib/file');

module.exports = {
    /**
     * Adapts single BH file content to client-side.
     * @param {String} input
     * @returns {String}
     */
    process: function (input) {
        return input
            .replace(/module\.exports\s*=\s*function\s*\([^\)]*\)\s*{/, '')
            .replace(/}\s*(?:;)?\s*$/, '');
    },

    /**
     * Builds module (see npm package "ym").
     * @param {String} bhEngineSource
     * @param {String} inputSources
     * @param {Object} dependencies example: {libName: "dependencyName"}
     * @param {String} jsAttrName
     * @param {String} jsAttrScheme
     * @param {String} mimic
     * @returns {string}
     */
    buildModule: function (targetPath, bhEngine, inputSources, dependencies, jsAttrName, jsAttrScheme,
                           useSourceMap, mimic) {
        var file = new File(targetPath, useSourceMap),
            libNames,
            depNames,
            libPrepares;

        if (dependencies) {
            libNames = Object.keys(dependencies);
            libPrepares = this._buildLibPrepares(dependencies);
            depNames = libNames.map(function (libName) {
                return dependencies[libName];
            });
        }

        file.writeLine('modules.define(\'bh\'' +
            (depNames ? ', ' + JSON.stringify(depNames) : '') +
            ', function(provide' + (libNames && libNames.length ? ', ' + libNames.join(', ') : '') + ') {'
        );

        this._concatFile(file, bhEngine, inputSources, libPrepares, jsAttrName, jsAttrScheme);

        file.writeLine('provide(bh);');
        file.writeLine('});');

        if (mimic) {
            file.writeLine('modules.define(\'' + mimic + '\', [\'bh\'], function(provide, bh) {');
            file.writeLine('provide(bh);');
            file.writeLine('});');
        }

        return file;
    },

    /**
     * Builds client js.
     * @param {String} bhEngineSource
     * @param {String} inputSources
     * @param {Object} dependencies example: {libName: "dependencyName"}
     * @param {String} jsAttrName
     * @param {String} jsAttrScheme
     * @param {Boolean} useSourceMap
     * @param {String} mimic
     * @returns {string}
     */
    build: function (targetPath, bhEngine, inputSources, dependencies, jsAttrName, jsAttrScheme, useSourceMap, mimic) {
        var file = new File(targetPath, useSourceMap),
            libPrepares = this._buildLibPrepares(dependencies);

        return this._concatFile(file, bhEngine, inputSources, libPrepares, jsAttrName, jsAttrScheme, mimic);
    },

    _buildLibPrepares: function (dependencies) {
        var libNames = Object.keys(dependencies);

        return libNames.map(function (libName) {
            return 'bh.lib.' + libName + ' = ' + dependencies[libName] + ';';
        });
    },

    _concatFile: function (file, bhEngine, inputSources, libPrepares, jsAttrName, jsAttrScheme, mimic) {
        file.writeFileContent(bhEngine.filename, bhEngine.content);
        file.writeLine('var bh = new BH();');
        file.writeLine('bh.setOptions({');
        file.writeLine('    jsAttrName: \'' + jsAttrName + '\',');
        file.writeLine('    jsAttrScheme: \'' + jsAttrScheme + '\'');
        file.writeLine('});');

        if (mimic) {
            file.writeLine('if (typeof ' + mimic + ' === \'undefined\') {');
            file.writeLine('var ' + mimic + ' = bh;');
            file.writeLine('}');
        }

        if (libPrepares) {
            libPrepares.forEach(function (libPrepare) {
                file.writeLine(libPrepare);
            });
        }

        inputSources.forEach(function (inputSource) {
            file.writeLine('// begin: ' + inputSource.relPath);
            file.writeFileContent(inputSource.filename, inputSource.content);
            file.writeLine('// end: ' + inputSource.relPath);
        });

        return file;
    }
};
<commit_msg>Update old code to fix the problem<commit_after>var File = require('enb-source-map/lib/file');

module.exports = {
    /**
     * Adapts single BH file content to client-side.
     * @param {String} input
     * @returns {String}
     */
    process: function (input) {
        return input
            .replace(/module\.exports\s*=\s*function\s*\([^\)]*\)\s*{/, '')
            .replace(/}\s*(?:;)?\s*$/, '');
    },

    /**
     * Builds module (see npm package "ym").
     * @param {String} bhEngineSource
     * @param {String} inputSources
     * @param {Object} dependencies example: {libName: "dependencyName"}
     * @param {String} jsAttrName
     * @param {String} jsAttrScheme
     * @param {String} mimic
     * @returns {string}
     */
    buildModule: function (targetPath, bhEngine, inputSources, dependencies, jsAttrName, jsAttrScheme,
                           useSourceMap, mimic) {
        var file = new File(targetPath, useSourceMap),
            libNames,
            depNames,
            libPrepares;

        if (dependencies) {
            libNames = Object.keys(dependencies);
            libPrepares = this._buildLibPrepares(dependencies);
            depNames = libNames.map(function (libName) {
                return dependencies[libName];
            });
        }

        file.writeLine('(function () {');
        this._concatFile(file, bhEngine, inputSources, null, jsAttrName, jsAttrScheme);
        this._defineModule('bh', file, depNames, libNames, libPrepares);

        if (mimic) {
            this._defineModule(mimic, file, ['bh'], ['bh'], null);
        }

        file.writeLine('})()');

        return file;
    },

    /**
     * Builds client js.
     * @param {String} bhEngineSource
     * @param {String} inputSources
     * @param {Object} dependencies example: {libName: "dependencyName"}
     * @param {String} jsAttrName
     * @param {String} jsAttrScheme
     * @param {Boolean} useSourceMap
     * @param {String} mimic
     * @returns {string}
     */
    build: function (targetPath, bhEngine, inputSources, dependencies, jsAttrName, jsAttrScheme, useSourceMap, mimic) {
        var file = new File(targetPath, useSourceMap),
            libPrepares = this._buildLibPrepares(dependencies);

        return this._concatFile(file, bhEngine, inputSources, libPrepares, jsAttrName, jsAttrScheme, mimic);
    },

    _buildLibPrepares: function (dependencies) {
        var libNames = Object.keys(dependencies);

        return libNames.map(function (libName) {
            return 'bh.lib.' + libName + ' = ' + dependencies[libName] + ';';
        });
    },

    _concatFile: function (file, bhEngine, inputSources, libPrepares, jsAttrName, jsAttrScheme, mimic) {
        file.writeFileContent(bhEngine.filename, bhEngine.content);
        file.writeLine('var bh = new BH();');
        file.writeLine('bh.setOptions({');
        file.writeLine('    jsAttrName: \'' + jsAttrName + '\',');
        file.writeLine('    jsAttrScheme: \'' + jsAttrScheme + '\'');
        file.writeLine('});');

        if (mimic) {
            file.writeLine('if (typeof ' + mimic + ' === \'undefined\') {');
            file.writeLine('var ' + mimic + ' = bh;');
            file.writeLine('}');
        }

        this._addLibPrepares(file, libPrepares);

        inputSources.forEach(function (inputSource) {
            file.writeLine('// begin: ' + inputSource.relPath);
            file.writeFileContent(inputSource.filename, inputSource.content);
            file.writeLine('// end: ' + inputSource.relPath);
        });

        return file;
    },

    _defineModule: function (name, file, depNames, libNames, libPrepares) {
        file.writeLine('modules.define(\'' + name + '\'' +
            (depNames ? ', ' + JSON.stringify(depNames) : '') +
            ', function(provide' + (libNames && libNames.length ? ', ' + libNames.join(', ') : '') + ') {'
        );

        if (libPrepares) {
            this._addLibPrepares(file, libPrepares);
        }

        file.writeLine('provide(bh);');
        file.writeLine('});');
    },

    _addLibPrepares: function (file, libPrepares) {
        if (libPrepares) {
            libPrepares.forEach(function (libPrepare) {
                file.writeLine(libPrepare);
            });
        }
    }
};
<|endoftext|>


<commit_before>/* @flow */
import Record from '../Record';

describe('Record', () => {
  class Entity extends Record {
    someString: string = 'default string';
    someNum: number = 0.134;
    someBool: boolean = true;
    someNullable: ?string = null;

    get exclamation() {
      return this.someString + '!';
    }
  }

  it('should create an entity with default values', () => {
    let entity = new Entity();

    expect(entity.toJSON()).toEqual({
      someString: 'default string',
      someNum: 0.134,
      someBool: true,
      someNullable: null,
    });
  });

  it('should override defaults with custom values', () => {
    let entity = new Entity({ someNullable: 1, someString: 'hello' });

    expect(entity.toJSON()).toEqual({
      someString: 'hello',
      someNum: 0.134,
      someBool: true,
      someNullable: 1,
    });
  });

  it('should satisfy composition law', () => {
    let entity = new Entity();
    let left = entity.copy({ someNum: 13, someBool: false });
    let right = entity.copy({ someNum: 13 }).copy({ someBool: false });

    expect(left.toJSON()).toEqual(right.toJSON());
  });

  it('should support subclassing', () => {
    class SubEntity extends Entity {
      someNewThing: string = 'default';
    }

    let entityA = new SubEntity();
    let entityB = new SubEntity({ someString: 'test', someNewThing: 'blah' });

    expect(entityA.toJSON()).toEqual({
      someString: 'default string',
      someNum: 0.134,
      someBool: true,
      someNullable: null,
      someNewThing: 'default',
    });

    expect(entityB.toJSON()).toEqual({
      someString: 'test',
      someNum: 0.134,
      someBool: true,
      someNullable: null,
      someNewThing: 'blah',
    });
  });

  it('should support polymorphism', () => {
    class Base extends Record {
      format: string = 'AAA';

      transform(value) {
        return this.format.replace(/A/g, value);
      }
    }

    class Child extends Base {
      transform(value) {
        return '-' + this.format.replace(/A/g, value);
      }
    }

    let baseEntity = new Base({ format: 'AAAAA' });
    let childEntity = new Child();

    expect(baseEntity.transform(1)).toBe('11111');
    expect(childEntity.transform(1)).toBe('-111');
  });

  it('should create new entity based on existent', () => {
    let entity = new Entity({ someBool: false });
    let updated = entity.copy({ someNum: 14 });

    expect(entity.toJSON()).toEqual({
      someString: 'default string',
      someNum: 0.134,
      someBool: false,
      someNullable: null,
    });

    expect(updated.toJSON()).toEqual({
      someString: 'default string',
      someNum: 14,
      someBool: false,
      someNullable: null,
    });
  });

  it('should compare custom values for two entities of the same type', () => {
    let entity = new Entity({ someBool: false });
    let equal = new Entity({ someBool: false });
    let updated = entity.copy({ someNum: 14 });

    expect(entity.equals(updated)).toBe(false);
    expect(entity.equals(equal)).toBe(true);
  });

  class Embedded extends Record {
    name: string = 'name';
    age: number = 1;
    entity: Entity = new Entity();
    date: Date = new Date();
    obj: Object = {foo: 'bar'};
  }

  it('should be serializable with embedded dataclass', () => {
    let dummyDate = new Date('1996-12-17T03:24:00');
    let embedded = new Embedded({
      date: dummyDate
    });
    let raw = {
      name: "name",
      age: 1,
      entity: {
        someString: "default string",
        someNum: 0.134,
        someBool: true,
        someNullable: null
      },
      date: dummyDate.toISOString(),
      obj: {
        foo: "bar"
      }
    };
    expect(JSON.stringify(embedded)).toBe(JSON.stringify(raw));
  })

  it('should compare dataclass with nested value objects', () => {
    let embeddedA = new Embedded({
      date: new Date('1996-12-17T03:24:00'),
      entity: new Entity({ someBool: false })
    });
    let embeddedB = new Embedded({
      date: new Date('1996-12-17T03:24:00'),
      entity: new Entity({ someBool: false })
    });
    let embeddedC = new Embedded({
      date: new Date('1996-12-17T03:24:00'),
      entity: new Entity({ someBool: true })
    });
    expect(embeddedA.equals(embeddedB)).toBe(true);
    expect(embeddedB.equals(embeddedC)).toBe(false);
  });

  it('should satisfy symmetry law', () => {
    let a = new Entity({ someString: '1' });
    let b = new Entity({ someString: '1' });
    let c = new Entity({ someString: '2' });

    expect(a.equals(b)).toBeTruthy();
    expect(b.equals(a)).toBeTruthy();
    expect(a.equals(c)).toBeFalsy();
    expect(c.equals(a)).toBeFalsy();
  });

  it('should satisfy transitivity law', () => {
    let a = new Entity({ someString: 'hello' });
    let b = new Entity({ someString: 'hello' });
    let c = new Entity({ someString: 'hello' });

    expect(a.equals(b)).toBeTruthy();
    expect(b.equals(c)).toBeTruthy();
    expect(a.equals(c)).toBeTruthy();
  });

  it('should be serializable', () => {
    let entity = new Entity({ someBool: false });
    let raw = {
      someString: 'default string',
      someNum: 0.134,
      someBool: false,
      someNullable: null,
    };

    expect(JSON.stringify(entity)).toBe(JSON.stringify(raw));
  });

  it('should support iterables', () => {
    let entity = new Entity({ someBool: false });

    expect(Object.entries(entity)).toEqual([
      ['someString', 'default string'],
      ['someNum', 0.134],
      ['someBool', false],
      ['someNullable', null],
    ]);

    expect(Object.keys(entity)).toEqual([
      'someString',
      'someNum',
      'someBool',
      'someNullable',
    ]);

    expect(Object.values(entity)).toEqual([
      'default string',
      0.134,
      false,
      null,
    ]);
  });

  it('should not allow assignment', () => {
    let entity = new Entity({ someBool: false });

    entity.someBool = null;

    expect(entity.someBool).toBe(false);
  });

  it('should support predefined getters', () => {
    let entity = new Entity({ someString: 'abcde' });

    expect(entity.exclamation).toBe('abcde!');
  });
});
<commit_msg>add one more assertion for valueOf()<commit_after>/* @flow */
import Record from '../Record';

describe('Record', () => {
  class Entity extends Record {
    someString: string = 'default string';
    someNum: number = 0.134;
    someBool: boolean = true;
    someNullable: ?string = null;

    get exclamation() {
      return this.someString + '!';
    }
  }

  it('should create an entity with default values', () => {
    let entity = new Entity();

    expect(entity.toJSON()).toEqual({
      someString: 'default string',
      someNum: 0.134,
      someBool: true,
      someNullable: null,
    });
  });

  it('should override defaults with custom values', () => {
    let entity = new Entity({ someNullable: 1, someString: 'hello' });

    expect(entity.toJSON()).toEqual({
      someString: 'hello',
      someNum: 0.134,
      someBool: true,
      someNullable: 1,
    });
  });

  it('should satisfy composition law', () => {
    let entity = new Entity();
    let left = entity.copy({ someNum: 13, someBool: false });
    let right = entity.copy({ someNum: 13 }).copy({ someBool: false });

    expect(left.toJSON()).toEqual(right.toJSON());
  });

  it('should support subclassing', () => {
    class SubEntity extends Entity {
      someNewThing: string = 'default';
    }

    let entityA = new SubEntity();
    let entityB = new SubEntity({ someString: 'test', someNewThing: 'blah' });

    expect(entityA.toJSON()).toEqual({
      someString: 'default string',
      someNum: 0.134,
      someBool: true,
      someNullable: null,
      someNewThing: 'default',
    });

    expect(entityB.toJSON()).toEqual({
      someString: 'test',
      someNum: 0.134,
      someBool: true,
      someNullable: null,
      someNewThing: 'blah',
    });
  });

  it('should support polymorphism', () => {
    class Base extends Record {
      format: string = 'AAA';

      transform(value) {
        return this.format.replace(/A/g, value);
      }
    }

    class Child extends Base {
      transform(value) {
        return '-' + this.format.replace(/A/g, value);
      }
    }

    let baseEntity = new Base({ format: 'AAAAA' });
    let childEntity = new Child();

    expect(baseEntity.transform(1)).toBe('11111');
    expect(childEntity.transform(1)).toBe('-111');
  });

  it('should create new entity based on existent', () => {
    let entity = new Entity({ someBool: false });
    let updated = entity.copy({ someNum: 14 });

    expect(entity.toJSON()).toEqual({
      someString: 'default string',
      someNum: 0.134,
      someBool: false,
      someNullable: null,
    });

    expect(updated.toJSON()).toEqual({
      someString: 'default string',
      someNum: 14,
      someBool: false,
      someNullable: null,
    });
  });

  it('should compare custom values for two entities of the same type', () => {
    let entity = new Entity({ someBool: false });
    let equal = new Entity({ someBool: false });
    let updated = entity.copy({ someNum: 14 });

    expect(entity.equals(updated)).toBe(false);
    expect(entity.equals(equal)).toBe(true);
  });

  class Embedded extends Record {
    name: string = 'name';
    age: number = 1;
    entity: Entity = new Entity();
    date: Date = new Date();
    obj: Object = {foo: 'bar'};
  }

  it('should be serializable with embedded dataclass', () => {
    let dummyDate = new Date('1996-12-17T03:24:00');
    let embedded = new Embedded({
      date: dummyDate
    });
    let raw = {
      name: "name",
      age: 1,
      entity: {
        someString: "default string",
        someNum: 0.134,
        someBool: true,
        someNullable: null
      },
      date: dummyDate.toISOString(),
      obj: {
        foo: "bar"
      }
    };
    expect(JSON.stringify(embedded)).toBe(JSON.stringify(raw));
  })

  it('should compare dataclass with nested value objects', () => {
    let embeddedA = new Embedded({
      date: new Date('1996-12-17T03:24:00'),
      entity: new Entity({ someBool: false })
    });
    let embeddedB = new Embedded({
      date: new Date('1996-12-17T03:24:00'),
      entity: new Entity({ someBool: false })
    });
    let embeddedC = new Embedded({
      date: new Date('1996-12-17T03:24:00'),
      entity: new Entity({ someBool: true })
    });
    let embeddedD = new Embedded({
      date: new Date('2001-12-17T03:24:00'),
      entity: new Entity({ someBool: true })
    });
    expect(embeddedA.equals(embeddedB)).toBe(true);
    expect(embeddedB.equals(embeddedC)).toBe(false);
    expect(embeddedC.equals(embeddedD)).toBe(false);
  });

  it('should satisfy symmetry law', () => {
    let a = new Entity({ someString: '1' });
    let b = new Entity({ someString: '1' });
    let c = new Entity({ someString: '2' });

    expect(a.equals(b)).toBeTruthy();
    expect(b.equals(a)).toBeTruthy();
    expect(a.equals(c)).toBeFalsy();
    expect(c.equals(a)).toBeFalsy();
  });

  it('should satisfy transitivity law', () => {
    let a = new Entity({ someString: 'hello' });
    let b = new Entity({ someString: 'hello' });
    let c = new Entity({ someString: 'hello' });

    expect(a.equals(b)).toBeTruthy();
    expect(b.equals(c)).toBeTruthy();
    expect(a.equals(c)).toBeTruthy();
  });

  it('should be serializable', () => {
    let entity = new Entity({ someBool: false });
    let raw = {
      someString: 'default string',
      someNum: 0.134,
      someBool: false,
      someNullable: null,
    };

    expect(JSON.stringify(entity)).toBe(JSON.stringify(raw));
  });

  it('should support iterables', () => {
    let entity = new Entity({ someBool: false });

    expect(Object.entries(entity)).toEqual([
      ['someString', 'default string'],
      ['someNum', 0.134],
      ['someBool', false],
      ['someNullable', null],
    ]);

    expect(Object.keys(entity)).toEqual([
      'someString',
      'someNum',
      'someBool',
      'someNullable',
    ]);

    expect(Object.values(entity)).toEqual([
      'default string',
      0.134,
      false,
      null,
    ]);
  });

  it('should not allow assignment', () => {
    let entity = new Entity({ someBool: false });

    entity.someBool = null;

    expect(entity.someBool).toBe(false);
  });

  it('should support predefined getters', () => {
    let entity = new Entity({ someString: 'abcde' });

    expect(entity.exclamation).toBe('abcde!');
  });
});
<|endoftext|>


<commit_before>//Capture log
if(typeof console === "undefined") {console = {log: function() { }};}

var animationId = null;
var analyserContext = null;
var canvasWidth, canvasHeight;
var input = null;

  function __log(e, data) {
    log.innerHTML += "\n" + e + " " + (data || '');
  }

  // The "opener" is the window that spawned this popup
  function callOpener(name, arg) {

    //Try this window
    if (typeof window[name] === 'function') {
	window[name](arg)
    }

    //Then check the opener
    else if (window.opener != null && typeof window.opener[name] === 'function') {
	window.opener[name](arg)
    }
  }

function audioAnalyzer(time) {
  if (!analyserContext) {
    var canvas = document.getElementById('audio-analyzer');
    $(canvas).show();
    canvasWidth = canvas.width;
    canvasHeight = canvas.height;
    analyserContext = canvas.getContext('2d');
  }

  {
    var barSpacing = 3;
    var barWidth = 2;
    var numBars = Math.round(canvasWidth / barSpacing);
    var freqByteData = new Uint8Array(analyzerNode.frequencyBinCount);
    analyzerNode.getByteFrequencyData(freqByteData);

    analyserContext.clearRect(0, 0, canvasWidth, canvasHeight);
    var multiplier = analyzerNode.frequencyBinCount / numBars;

    // Draw rectangle for each frequency
    for (var i = 0; i < numBars; ++i) {
      var magnitude = 0;
      var offset = Math.floor( i * multiplier );
      // sum/average the block or miss narrow-bandwidth spikes
      for (var j = 0; j< multiplier; j++) magnitude += freqByteData[offset + j];
      magnitude = magnitude / multiplier;
      var magnitude2 = freqByteData[i * multiplier];
      analyserContext.fillStyle = "hsl( " + Math.round((i*360)/numBars) + ", 70%, 50%)";
      analyserContext.fillRect(i * barSpacing, canvasHeight, barWidth, -magnitude);
    }
  }

  animationId = window.requestAnimationFrame(audioAnalyzer);
}

  function enableRecording(stream) {
      $('#audio-record').attr('disabled','').fadeTo('slow', 1.0);
      if (stream) {
          //Save the input for later
          input = audio_context.createMediaStreamSource(stream);
          console.log('Media input started.');
      }
  }

  function startUserMedia() {
      if (audio_context && input) {
		  //This command would be useful for preview but causes the audio to echo to no other effect
          //input.connect(audio_context.destination);
          //console.log('Input connected to audio context destination.');

          // this is our audio analysis setup
          analyzerNode = audio_context.createAnalyser();
          analyzerNode.fftSize = 2048;
          input.connect( analyzerNode );

          recorder = new Recorder(input);
          console.log('Recorder initialized.');

          // initialize the audio analysis
          audioAnalyzer();
      }

  }

  function startTimer() {
    timer = setInterval(function() {
      timeRemaining--;
      $('#audio-timer').text( (maxSeconds - timeRemaining) < 10 ? "0" + (maxSeconds - timeRemaining) : (maxSeconds - timeRemaining));
      if (timeRemaining <= 0) {
        clearInterval(timer);
        console.log('MaxSeconds reached');
        stopRecording(this);
      }
    }, 1000);
  }

  function startRecording(button) {

    //Try to stop/reload previous recording
    if (userMediaSupport) {
      document.getElementById('audio-html5').load();
    }
    else {
        //If this fails it's just because jRecorder hasn't started and they tried to close the window
        try {
            $.jRecorder.stopPreview();
        }
        catch (err) {}
    }

    // disable Save and Submit on parent page
    callOpener ("disableSave", window);
    callOpener ("disableSubmitForGrade", window);

    // Reset time remaining
    timeRemaining = maxSeconds;

    startUserMedia();

    if (userMediaSupport) {
      recorder && recorder.record();
      startTimer();
    }
    else {
      // wait for the callback from the SWF before starting timer
      $.jRecorder.record(maxSeconds);
    }

    // disable the record and play button, enable the stop button
    $('#audio-stop').attr('disabled','').fadeTo('slow', 1.0);
    $('#audio-record').attr('disabled','disabled').fadeTo('slow', 0.5);
    $('#audio-upload').attr('disabled','disabled').fadeTo('slow', 0.5);
    $('#audio-play').attr('disabled', 'disabled').fadeTo('slow', 0.5);
    console.log('Recording...');
  }

  function stopRecording(button) {
    if (userMediaSupport) {
      recorder && recorder.stop();
    }
    else {
		//If this fails it's just because jRecorder hasn't started and they tried to close the window
		try {
			$.jRecorder.stop();
		}
		catch (err) {}
    }

    //Disconnect the stream
    if (input != null) {
        input.disconnect();
    }

    // enable Save and Submit on parent page
    callOpener ("enableSave", window);
    callOpener ("enableSubmitForGrade", window);

    // reset timers
    clearInterval(timer);

    // disable the stop button, enable the record button
    $('#audio-stop').attr('disabled','disabled').fadeTo('slow', 0.5);
    $('#audio-record').attr('disabled','').fadeTo('slow', 1.0);
    $('#audio-upload').attr('disabled','').fadeTo('slow', 1.0);
    //button.previousElementSibling.disabled = false;
    console.log('Stopped recording.');

    // see if a user has attempts remaining
    attemptsRemaining--;
    console.log('Attempts remaining: ' + attemptsRemaining);
    $('#audio-attempts').text(attemptsRemaining);

    //force the user submission!
    if (attemptsRemaining < 1) {
      $('#audio-record').attr('disabled', 'disabled');
      $('#audio-stop').attr('disabled','disabled').fadeTo('slow', 0.5);

	  //This might fail if there's no data
	  try {
		  postDataToServer(button);
	  }
	  catch (err) {}
    }
    else {
        createDownloadLink();
    }
  }

  function postDataToServer (button) {
    console.log('seconds: ' + maxSeconds + ";remain: " + timeRemaining);
    var duration = maxSeconds - timeRemaining;
    var attempts = attemptsAllowed - attemptsRemaining;
    var agentId = navigator.userAgent

    if (postUrl) {
        var url  = postUrl + "&agent=" + agentId + "&lastDuration=" + duration + "&suffix=" + "au" + "&attempts=" + attempts;
    }
    else {
	console.log ("postUrl not set yet");
    }

    // disable all buttons while we upload
    $('#audio-controls button').fadeTo('slow', 0).hide();
    $('#audio-posting').fadeTo('slow', 1.0);

    if (userMediaSupport) {
      recorder && recorder.exportWAV(function(blob) {
        console.log('Blob size: ' + blob.size + ';type=' + blob.type);
        uploadBlob(url,blob);
      });
    }
    else {
      // add params before POSTing audio to server
      $.jRecorder.addParameter('agent', agentId);
      $.jRecorder.addParameter('suffix', 'wav');
      $.jRecorder.addParameter('lastDuration', duration);
      $.jRecorder.addParameter('attempts', attempts);
      $.jRecorder.addParameter('Command','QuickUploadAttachment');

      $.jRecorder.sendData();
    }
  }

  function uploadBlob (url, blob) {
    // plot the upload progress
    $('#audio-levelbar').hide();
    $('#audio-statusbar').css('width', '2px').show();

    var xhr = new XMLHttpRequest();
    xhr.open('POST', url, true);
    xhr.onload = function(e) { /*uploaded*/ };

    // Listen to the upload progress.
    xhr.upload.onprogress = function(e) {
      if (e.lengthComputable) {
        p = (e.loaded / e.total) * 100;
        if (!isNaN(p) && p > 0) {
          $('#audio-statusbar').css('width', ((p/100)*(maxWidth)) + 'px');
        }
        console.log('Progress: ' + p);
      }
    };

    xhr.onreadystatechange = function(e) {
      if ( 4 == this.readyState ) {
        console.log('xhr upload complete');

        // refresh the parent page
        callOpener ("clickReloadLink", window);

        // close up shop
        finishAndClose(true, this.responseText);
      }
    };

    xhr.send(blob);
  }

  function finishAndClose (success, responseUrl) {

	//Update the Url if it's passed back and this method accepts it
    callOpener ("updateUrl", responseUrl);
    $('#audio-levelbar').hide();
    $('#audio-statusbar').css('width', '2px').show();
    $('#audio-posting').hide();
    $('#audio-finished').fadeTo('slow', 1.0);

    var closeSoon = parseInt(1);
    var closer = setInterval(
      function() {
        $('#audio-statusbar').css('width', ((closeSoon/5)*(maxWidth)) + 'px');
        if (closeSoon > 5) {
            if (CKEDITOR) {
                curdialog = CKEDITOR.dialog.getCurrent()
                //Might have closed the dialog
                if (curdialog) {
					curdialog.hide();
                }
                //Stop timer
                clearInterval(closer);
            }
            else {
                window.close();
                //Stop timer
                clearInterval(closer);
            }
        }
        closeSoon++;
      }
    , 500);
  }

  function plotLevels (level) {
    if(level == -1) {
      $('#audio-levelbar').css('width',  '2px');
    }
    else {
      //console.log(level);
      $('#audio-levelbar').css("width", (level * (maxWidth/100))+ "px");
    }
  }

  function createDownloadLink() {
    $('#audio-play').attr('disabled', '').fadeTo('slow', 1.0);

    recorder && recorder.exportWAV(function(blob) {
      var url = URL.createObjectURL(blob);
      //var li = document.createElement('li');
      // var au = document.createElement('audio');
      var au = document.getElementById('audio-html5');

      au.src = url;
      // li.appendChild(au);
      //$('#audio-debug-log').append(li);

    });
  }

  function playRecording(button) {
	//Try to stop/reload previous recording
    if (userMediaSupport) {
      document.getElementById('audio-html5').load();
    }
    else {
        //If this fails it's just because jRecorder hasn't started and they tried to close the window
        try {
            $.jRecorder.stopPreview();
        }
        catch (err) {}
    }

    if (userMediaSupport) {
        document.getElementById('audio-html5').play();
    }
    else {
        try {
        	$.jRecorder.startPreview();
        }
        catch (err) {}
    }
  }

  function drawBuffer(width, height, context, data) {
    var step = Math.ceil( data.length / width );
    var amp = height / 2;
    context.fillStyle = "silver";
    for(var i=0; i < width; i++){
        var min = 1.0;
        var max = -1.0;
        for (j=0; j<step; j++) {
            var datum = data[(i*step)+j];
            if (datum < min)
                min = datum;
            if (datum > max)
                max = datum;
        }
        context.fillRect(i,(1+min)*amp,1,Math.max(1,(max-min)*amp));
    }
  }

$(document).ready(function() {

    try {
      // webkit shim
      window.AudioContext = window.AudioContext || window.webkitAudioContext;

      //navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
      // IE doesn't support everything needed yet, use flash fallback
      navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;

      window.URL = window.URL || window.webkitURL;

      //Experimental Chrome only
      if (AudioContext) {
        audio_context = new AudioContext;
        console.log('Audio context set up.');
      }
      console.log('navigator.getUserMedia ' + (navigator.getUserMedia ? 'available.' : 'not present!'));

    } catch (e) {
      console.log('No web audio support in this browser!' + e.message);
      userMediaSupport = false;
    }

    //Maybe no error but still no support
    if (navigator.getUserMedia === undefined) {
        userMediaSupport = false;
    }

    if (isNaN(attemptsAllowed)) {
      attemptsAllowed = 1;
    }

    if (isNaN(attemptsRemaining)) {
      attemptsRemaining = attemptsAllowed;
      console.log('Settings attempts remaining to ' + attemptsRemaining);
    }

    if (isNaN(maxSeconds)) {
      maxSeconds = 30;
      console.log('maxSeconds was NaN. Setting to ' + maxSeconds);
    }

    // Set some initial variables
    timeRemaining = maxSeconds;
    $('#audio-time-allowed').text(timeRemaining);
    $('#audio-max-time').text(maxSeconds);
    $('#audio-attempts').text(attemptsRemaining);

    maxWidth = $('#audio-controls').width();
    if (isNaN(maxWidth) || maxWidth < 100) {
      maxWidth = 100;
    }
    console.log('Width of controls: ' + maxWidth);

    // disable record button until the user grants microphone approval
    $('#audio-record').attr('disabled','disabled').fadeTo('slow', 0.5);

    if (userMediaSupport) {

      navigator.getUserMedia({audio: true}, enableRecording, function(e) {
        console.log('No live audio input: ' + e);
        userMediaSupport = false;

        // Why is the user denying the mic? Reload and try again.
        location.reload();
      });

    }
    else {

      var flash = document.getElementById('flashrecarea');
      $(flash).show();
      $.jRecorder({
        swf_path : '/library/js/recorder/jRecorder.swf',
        host : postUrl,
        swf_object_path : '/library/js/swfobject',
        //These are in the main body right now because flash couldn't call them
        callback_started_recording: function()      { startTimer(); },
        callback_activityLevel:     function(level) { plotLevels(level); },
        callback_finished_sending:  function(response)  {finishAndClose(true, response) },
        callback_hide_the_flash:    function() {enableRecording() }
      });
    }

});
<commit_msg>SAM-1709 removing Java applet and replacing with HTML5 audio recorder<commit_after>//Capture log
if(typeof console === "undefined") {console = {log: function() { }};}

var animationId = null;
var analyserContext = null;
var canvasWidth, canvasHeight;
var input = null;

  function __log(e, data) {
    log.innerHTML += "\n" + e + " " + (data || '');
  }

  // The "opener" is the window that spawned this popup
  function callOpener(name, arg) {

    //Try this window
    if (typeof window[name] === 'function') {
	window[name](arg)
    }

    //Then check the opener
    else if (window.opener != null && typeof window.opener[name] === 'function') {
	window.opener[name](arg)
    }
  }

function audioAnalyzer(time) {
  if (!analyserContext) {
    var canvas = document.getElementById('audio-analyzer');
    $(canvas).show();
    canvasWidth = canvas.width;
    canvasHeight = canvas.height;
    analyserContext = canvas.getContext('2d');
  }

  {
    var barSpacing = 3;
    var barWidth = 2;
    var numBars = Math.round(canvasWidth / barSpacing);
    var freqByteData = new Uint8Array(analyzerNode.frequencyBinCount);
    analyzerNode.getByteFrequencyData(freqByteData);

    analyserContext.clearRect(0, 0, canvasWidth, canvasHeight);
    var multiplier = analyzerNode.frequencyBinCount / numBars;

    // Draw rectangle for each frequency
    for (var i = 0; i < numBars; ++i) {
      var magnitude = 0;
      var offset = Math.floor( i * multiplier );
      // sum/average the block or miss narrow-bandwidth spikes
      for (var j = 0; j< multiplier; j++) magnitude += freqByteData[offset + j];
      magnitude = magnitude / multiplier;
      var magnitude2 = freqByteData[i * multiplier];
      analyserContext.fillStyle = "hsl( " + Math.round((i*360)/numBars) + ", 70%, 50%)";
      analyserContext.fillRect(i * barSpacing, canvasHeight, barWidth, -magnitude);
    }
  }

  animationId = window.requestAnimationFrame(audioAnalyzer);
}

  function enableRecording(stream) {
      $('#audio-record').attr('disabled','').fadeTo('slow', 1.0);
      if (stream) {
          //Save the input for later
          input = audio_context.createMediaStreamSource(stream);
          console.log('Media input started.');
      }
  }

  function startUserMedia() {
      if (audio_context && input) {
		  //This command would be useful for preview but causes the audio to echo to no other effect
          //input.connect(audio_context.destination);
          //console.log('Input connected to audio context destination.');

          // this is our audio analysis setup
          analyzerNode = audio_context.createAnalyser();
          analyzerNode.fftSize = 2048;
          input.connect( analyzerNode );

          recorder = new Recorder(input);
          console.log('Recorder initialized.');

          // initialize the audio analysis
          audioAnalyzer();
      }

  }

  function startTimer() {
    timer = setInterval(function() {
      timeRemaining--;
      $('#audio-timer').text( (maxSeconds - timeRemaining) < 10 ? "0" + (maxSeconds - timeRemaining) : (maxSeconds - timeRemaining));
      if (timeRemaining <= 0) {
        clearInterval(timer);
        console.log('MaxSeconds reached');
        stopRecording(this);
      }
    }, 1000);
  }

  function startRecording(button) {

    //Try to stop/reload previous recording
    if (userMediaSupport) {
      document.getElementById('audio-html5').load();
    }
    else {
        //If this fails it's just because jRecorder hasn't started and they tried to close the window
        try {
            $.jRecorder.stopPreview();
        }
        catch (err) {}
    }

    // disable Save and Submit on parent page
    callOpener ("disableSave", window);
    callOpener ("disableSubmitForGrade", window);

    // Reset time remaining
    timeRemaining = maxSeconds;

    startUserMedia();

    if (userMediaSupport) {
      recorder && recorder.record();
      startTimer();
    }
    else {
      // wait for the callback from the SWF before starting timer
      $.jRecorder.record(maxSeconds);
    }

    // disable the record and play button, enable the stop button
    $('#audio-stop').attr('disabled','').fadeTo('slow', 1.0);
    $('#audio-record').attr('disabled','disabled').fadeTo('slow', 0.5);
    $('#audio-upload').attr('disabled','disabled').fadeTo('slow', 0.5);
    $('#audio-play').attr('disabled', 'disabled').fadeTo('slow', 0.5);
    console.log('Recording...');
  }

  function stopRecording(button) {
    if (userMediaSupport) {
      recorder && recorder.stop();
    }
    else {
		//If this fails it's just because jRecorder hasn't started and they tried to close the window
		try {
			$.jRecorder.stop();
		}
		catch (err) {}
    }

    //Disconnect the stream
    if (input != null) {
        input.disconnect();
    }

    // enable Save and Submit on parent page
    callOpener ("enableSave", window);
    callOpener ("enableSubmitForGrade", window);

    // reset timers
    clearInterval(timer);

    // disable the stop button, enable the record button
    $('#audio-stop').attr('disabled','disabled').fadeTo('slow', 0.5);
    $('#audio-record').attr('disabled','').fadeTo('slow', 1.0);
    $('#audio-upload').attr('disabled','').fadeTo('slow', 1.0);
    //button.previousElementSibling.disabled = false;
    console.log('Stopped recording.');

    // see if a user has attempts remaining
    attemptsRemaining--;
    console.log('Attempts remaining: ' + attemptsRemaining);
    $('#audio-attempts').text(attemptsRemaining);

    //force the user submission!
    if (attemptsRemaining < 1) {
      $('#audio-record').attr('disabled', 'disabled');
      $('#audio-stop').attr('disabled','disabled').fadeTo('slow', 0.5);

	  //This might fail if there's no data
	  try {
		  postDataToServer(button);
	  }
	  catch (err) {}
    }
    else {
        createDownloadLink();
    }
  }

  function postDataToServer (button) {
    console.log('seconds: ' + maxSeconds + ";remain: " + timeRemaining);
    var duration = maxSeconds - timeRemaining;
    var attempts = attemptsAllowed - attemptsRemaining;
    var agentId = navigator.userAgent

    if (postUrl) {
        var url  = postUrl + "&agent=" + agentId + "&lastDuration=" + duration + "&suffix=" + "au" + "&attempts=" + attempts;
    }
    else {
	console.log ("postUrl not set yet");
    }

    // disable all buttons while we upload
    $('#audio-controls button').fadeTo('slow', 0).hide();
    $('#audio-posting').fadeTo('slow', 1.0);

    if (userMediaSupport) {
      recorder && recorder.exportWAV(function(blob) {
        console.log('Blob size: ' + blob.size + ';type=' + blob.type);
        uploadBlob(url,blob);
      });
    }
    else {
      // add params before POSTing audio to server
      $.jRecorder.addParameter('agent', agentId);
      $.jRecorder.addParameter('suffix', 'wav');
      $.jRecorder.addParameter('lastDuration', duration);
      $.jRecorder.addParameter('attempts', attempts);
      $.jRecorder.addParameter('Command','QuickUploadAttachment');

      $.jRecorder.sendData();
    }
  }

  function uploadBlob (url, blob) {
    // plot the upload progress
    $('#audio-levelbar').hide();
    $('#audio-statusbar').css('width', '2px').show();

    var xhr = new XMLHttpRequest();
    xhr.open('POST', url, true);
    xhr.onload = function(e) { /*uploaded*/ };

    // Listen to the upload progress.
    xhr.upload.onprogress = function(e) {
      if (e.lengthComputable) {
        p = (e.loaded / e.total) * 100;
        if (!isNaN(p) && p > 0) {
          $('#audio-statusbar').css('width', ((p/100)*(maxWidth)) + 'px');
        }
        console.log('Progress: ' + p);
      }
    };

    xhr.onreadystatechange = function(e) {
      if ( 4 == this.readyState ) {
        console.log('xhr upload complete');

        // refresh the parent page
        callOpener ("clickReloadLink", window);

        // close up shop
        finishAndClose(true, this.responseText);
      }
    };

    xhr.send(blob);
  }

  function finishAndClose (success, responseUrl) {

	//Update the Url if it's passed back and this method accepts it
    callOpener ("updateUrl", responseUrl);
    $('#audio-levelbar').hide();
    $('#audio-statusbar').css('width', '2px').show();
    $('#audio-posting').hide();
    $('#audio-finished').fadeTo('slow', 1.0);

    var closeSoon = parseInt(1);
    var closer = setInterval(
      function() {
        $('#audio-statusbar').css('width', ((closeSoon/5)*(maxWidth)) + 'px');
        if (closeSoon > 5) {
            if (CKEDITOR) {
                curdialog = CKEDITOR.dialog.getCurrent()
                //Might have closed the dialog
                if (curdialog) {
					curdialog.hide();
                }
                //Stop timer
                clearInterval(closer);
            }
            else {
                window.close();
                //Stop timer
                clearInterval(closer);
            }
        }
        closeSoon++;
      }
    , 500);
  }

  function plotLevels (level) {
    if(level == -1) {
      $('#audio-levelbar').css('width',  '2px');
    }
    else {
      //console.log(level);
      $('#audio-levelbar').css("width", (level * (maxWidth/100))+ "px");
    }
  }

  function createDownloadLink() {
    $('#audio-play').attr('disabled', '').fadeTo('slow', 1.0);

    recorder && recorder.exportWAV(function(blob) {
      var url = URL.createObjectURL(blob);
      //var li = document.createElement('li');
      // var au = document.createElement('audio');
      var au = document.getElementById('audio-html5');

      au.src = url;
      // li.appendChild(au);
      //$('#audio-debug-log').append(li);

    });
  }

  function playRecording(button) {
	//Try to stop/reload previous recording
    if (userMediaSupport) {
      document.getElementById('audio-html5').load();
    }
    else {
        //If this fails it's just because jRecorder hasn't started and they tried to close the window
        try {
            $.jRecorder.stopPreview();
        }
        catch (err) {}
    }

    if (userMediaSupport) {
        document.getElementById('audio-html5').play();
    }
    else {
        try {
        	$.jRecorder.startPreview();
        }
        catch (err) {}
    }
  }

  function drawBuffer(width, height, context, data) {
    var step = Math.ceil( data.length / width );
    var amp = height / 2;
    context.fillStyle = "silver";
    for(var i=0; i < width; i++){
        var min = 1.0;
        var max = -1.0;
        for (j=0; j<step; j++) {
            var datum = data[(i*step)+j];
            if (datum < min)
                min = datum;
            if (datum > max)
                max = datum;
        }
        context.fillRect(i,(1+min)*amp,1,Math.max(1,(max-min)*amp));
    }
  }

$(document).ready(function() {

    try {
      // webkit shim
      window.AudioContext = window.AudioContext || window.webkitAudioContext;

      //navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
      // IE doesn't support everything needed yet, use flash fallback
      navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;

      window.URL = window.URL || window.webkitURL;

      //Experimental Chrome only
      if (AudioContext) {
        audio_context = new AudioContext;
        console.log('Audio context set up.');
      }
      console.log('navigator.getUserMedia ' + (navigator.getUserMedia ? 'available.' : 'not present!'));

    } catch (e) {
      console.log('No web audio support in this browser!' + e.message);
      userMediaSupport = false;
    }

    //Maybe no error but still no support
    if (navigator.getUserMedia === undefined) {
        userMediaSupport = false;
    }

    if (isNaN(attemptsAllowed)) {
      attemptsAllowed = 1;
    }

    if (isNaN(attemptsRemaining)) {
      attemptsRemaining = attemptsAllowed;
      console.log('Settings attempts remaining to ' + attemptsRemaining);
    }

    if (isNaN(maxSeconds)) {
      maxSeconds = 30;
      console.log('maxSeconds was NaN. Setting to ' + maxSeconds);
    }

    // Set some initial variables
    timeRemaining = maxSeconds;
    $('#audio-time-allowed').text(timeRemaining);
    $('#audio-max-time').text(maxSeconds);
    $('#audio-attempts-allowed').text(attemptsRemaining);
    $('#audio-attempts').text(attemptsRemaining);

    maxWidth = $('#audio-controls').width();
    if (isNaN(maxWidth) || maxWidth < 100) {
      maxWidth = 100;
    }
    console.log('Width of controls: ' + maxWidth);

    // disable record button until the user grants microphone approval
    $('#audio-record').attr('disabled','disabled').fadeTo('slow', 0.5);

    if (userMediaSupport) {

      navigator.getUserMedia({audio: true}, enableRecording, function(e) {
        console.log('No live audio input: ' + e);
        userMediaSupport = false;

        // Why is the user denying the mic? Reload and try again.
        location.reload();
      });

    }
    else {

      var flash = document.getElementById('flashrecarea');
      $(flash).show();
      $.jRecorder({
        swf_path : '/library/js/recorder/jRecorder.swf',
        host : postUrl,
        swf_object_path : '/library/js/swfobject',
        //These are in the main body right now because flash couldn't call them
        callback_started_recording: function()      { startTimer(); },
        callback_activityLevel:     function(level) { plotLevels(level); },
        callback_finished_sending:  function(response)  {finishAndClose(true, response) },
        callback_hide_the_flash:    function() {enableRecording() }
      });
    }

});
<|endoftext|>


<commit_before>/*
 * Please see the included LICENSE.md file for license terms and conditions.
 */

(function() {

	// Wait for DOM tree is ready for access
    document.addEventListener('DOMContentLoaded', function() {
        var canvas = document.getElementById('gameScene');
        // make canvas full screen
        var width = screen.availWidth;
        var height = screen.availHeight;
        canvas.width = width;
        canvas.height = height;

        // get canvas 2d context
        // With canvas 2d context, you can draw anything freely on the canvas.
        // See https://docs.webplatform.org/wiki/tutorials/canvas/canvas_tutorial
        // for tutorials of using canvas.
        var context = canvas.getContext('2d');

        /*

            // load and draw image on the canvas
            img.onload = function() {
                context.drawImage(img, (width - img.width) / 2, (height - img.height) / 2);
            };
            img.src = "asset/9ja.png";

        */

        var player = {
            x: 0,
            y: 0,
            velX: 0,
            velY: 0,
            w: 128,
            h: 128,
        }

        var playerImg = new Image();
        playerImg.src = "asset/9ja.png";

        var gravity = 10;

        function draw(){
				context.clearRect(0,0,canvas.width,canvas.height);
				//context.fillRect(player.x,player.y,player.w,player.h);
                context.drawImage(playerImg, player.x, player.y);
                //context.drawImage(player.img, 0, 0);

        }

        function game() {
            console.log("Player: X: " + player.x + ", Y: " + player.y + ", velX: " + player.velX + ", velY: " + player.velY);
            player.x += player.velX;
            player.y += player.velY;
            player.velY += gravity;
            if (player.velY > 20) {
                player.velY = 20;
            }
            if (player.velY < -20) {
                player.velY = -20;
            }

            if (player.x + player.w > canvas.width) {
                    console.log("Player hit right edge of screen");
                    player.x = canvas.width - player.w;
                    player.velX *= -1;
            }
            if (player.x < 0) {
                    console.log("Player hit left edge of screen");
                    player.x = 0;
                    player.velX *= -1;
            }
            if (player.y + player.h > canvas.height) {
                    console.log("Player hit bottom edge of screen");
                    player.y = canvas.height - player.h;
                    player.velY = 0;
            }
            if (player.y < 0) {
                    console.log("Player hit top edge of screen");
                    player.y = 0;
                    player.velY *= -.75;
            }
        }

        var gameTimer = setInterval(game,1000/30);
		var drawTimer = setInterval(draw,1000/30);

    }, false);

}());
<commit_msg>Touch input<commit_after>/*
 * Please see the included LICENSE.md file for license terms and conditions.
 */

(function() {

	// Wait for DOM tree is ready for access
    document.addEventListener('DOMContentLoaded', function() {
        var canvas = document.getElementById('gameScene');
        // make canvas full screen
        var width = screen.availWidth;
        var height = screen.availHeight;
        canvas.width = width;
        canvas.height = height;

        // get canvas 2d context
        // With canvas 2d context, you can draw anything freely on the canvas.
        // See https://docs.webplatform.org/wiki/tutorials/canvas/canvas_tutorial
        // for tutorials of using canvas.
        var context = canvas.getContext('2d');
        var gravity = 10;

        var playerImg = new Image();
        playerImg.src = "asset/9ja.png";

        var player = {
            x: 0,
            y: 0,
            velX: 0,
            velY: 0,
            w: 128,
            h: 128,
            runSpeed: 0,

            act: function() {
                player.x += player.velX;
                player.velX += player.runSpeed;

                if (player.velX < 0) {
                    player.velX = 0;
                }
                if (player.velX > 20) {
                    player.velX = 20;
                }

                player.y += player.velY;
                player.velY += gravity;
                if (player.velY > 20) {
                    player.velY = 20;
                }
                if (player.velY < -20) {
                    player.velY = -20;
                }

                if (player.x + player.w > canvas.width) {
                        console.log("Player hit right edge of screen");
                        player.x = canvas.width - player.w;
                        player.velX *= -1;
                }
                if (player.x < 0) {
                        console.log("Player hit left edge of screen");
                        player.x = 0;
                        player.velX *= -1;
                }
                if (player.y + player.h > canvas.height) {
                        console.log("Player hit bottom edge of screen");
                        player.y = canvas.height - player.h;
                        player.velY = 0;
                }
                if (player.y < 0) {
                        console.log("Player hit top edge of screen");
                        player.y = 0;
                        player.velY *= -.75;
                }
            }
        }

        function draw(){
				context.clearRect(0,0,canvas.width,canvas.height);
				//context.fillRect(player.x,player.y,player.w,player.h);
                context.drawImage(playerImg, player.x, player.y);
                //context.drawImage(player.img, 0, 0);

        }

        addEventListener("touchstart", touchstarthandler,false);
        addEventListener("touchend", touchendhandler,false);

        function touchstarthandler(event)
        {
            player.runSpeed = 10;
        }
        function touchendhandler(event)
        {
            player.runSpeed = -5;
        }

        function game() {
            console.log("Player: X: " + player.x + ", Y: " + player.y + ", velX: " + player.velX + ", velY: " + player.velY);
            player.act();
        }

        var gameTimer = setInterval(game,1000/30);
		var drawTimer = setInterval(draw,1000/30);

    }, false);

}());
<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc function
 * @name twistedHangmanApp.controller:MainCtrl
 * @description
 * # MainCtrl
 * Controller of the twistedHangmanApp
 */
angular.module('twistedHangmanApp')
  .controller('MainCtrl', ['$rootScope', '$scope', 'twCurrentPlayerService', function ($rootScope, $scope, twCurrentPlayerService) {
    $scope.playerGreeting = '';
    function loadPlayer() {
      twCurrentPlayerService.currentPlayer().then(function (data) {
        $scope.playerGreeting = 'Welcome ' + data.displayName;
      }, function () {
        //  TODO
      });
    }

    loadPlayer();

    $scope.$on('playerSwitch', function () {
      console.info('Reload Main');
      loadPlayer();
    });

    $scope.refreshGames = function () {
      $rootScope.$broadcast('refreshGames', '');
    };
  }]);
<commit_msg>adjusted comment<commit_after>'use strict';

/**
 * @ngdoc function
 * @name twistedHangmanApp.controller:MainCtrl
 * @description
 * # MainCtrl
 * Controller of the twistedHangmanApp
 */
angular.module('twistedHangmanApp')
  .controller('MainCtrl', ['$rootScope', '$scope', 'twCurrentPlayerService', function ($rootScope, $scope, twCurrentPlayerService) {
    $scope.playerGreeting = '';
    function loadPlayer() {
      twCurrentPlayerService.currentPlayer().then(function (data) {
        $scope.playerGreeting = 'Welcome ' + data.displayName;
      }, function () {
        //  TODO - redirect to error page?
      });
    }

    loadPlayer();

    $scope.$on('playerSwitch', function () {
      console.info('Reload Main');
      loadPlayer();
    });

    $scope.refreshGames = function () {
      $rootScope.$broadcast('refreshGames', '');
    };
  }]);
<|endoftext|>


<commit_before>import React,{Component} from 'react';
import { connect } from 'react-redux';
import { fetchPolicies } from '../actions';
import { Button, FormGroup, FormControl, InputGroup, Glyphicon } from 'react-bootstrap';

class SearchBar extends Component {
    constructor(props) {
        super(props);
        this.state = {
            isLoading: false,
            searchTerm: ''
        };
    }

    handleSubmit(e) {
        e.preventDefault();
        this.setState({ isLoading: true });
        const callback = () => {
            this.setState({ isLoading: false });
        };

        this.props.fetchPolicies(this.state.searchTerm, callback);
    }

    onTextChange(e) {
        this.setState({ searchTerm: e.target.value });
    }

    render() {
        const isLoading = this.state.isLoading;
        return(
            <form
                className='searchbar'
                onSubmit={ this.handleSubmit.bind(this) }>
                <FormGroup>
                    <InputGroup>
                        <FormControl
                            type='text'
                            placeholder='search'
                            value={ this.state.searchTerm }
                            onChange={ this.onTextChange.bind(this) }
                        />
                        <InputGroup.Button>
                            <Button
                                disabled={ isLoading }
                                type='submit'
                                bsStyle='primary'>
                                { isLoading ? 'Loading..' : 'Search' }
                            </Button>
                        </InputGroup.Button>
                    </InputGroup>
                </FormGroup>
            </form>
        );
    }
}

export default connect(null, { fetchPolicies })(SearchBar);<commit_msg>Cleaning up the code<commit_after>import React,{Component} from 'react';
import { connect } from 'react-redux';
import { fetchPolicies } from '../actions';
import { Button, FormGroup, FormControl, InputGroup } from 'react-bootstrap';

class SearchBar extends Component {
    constructor(props) {
        super(props);
        this.state = {
            isLoading: false,
            searchTerm: ''
        };
    }

    handleSubmit(e) {
        e.preventDefault();
        this.setState({ isLoading: true });
        const callback = () => {
            this.setState({ isLoading: false });
        };

        this.props.fetchPolicies(this.state.searchTerm, callback);
    }

    onTextChange(e) {
        this.setState({ searchTerm: e.target.value });
    }

    render() {
        const isLoading = this.state.isLoading;
        return(
            <form
                className='searchbar'
                onSubmit={ this.handleSubmit.bind(this) }>
                <FormGroup>
                    <InputGroup>
                        <FormControl
                            type='text'
                            placeholder='search'
                            value={ this.state.searchTerm }
                            onChange={ this.onTextChange.bind(this) }
                        />
                        <InputGroup.Button>
                            <Button
                                disabled={ isLoading }
                                type='submit'
                                bsStyle='primary'>
                                { isLoading ? 'Loading..' : 'Search' }
                            </Button>
                        </InputGroup.Button>
                    </InputGroup>
                </FormGroup>
            </form>
        );
    }
}

export default connect(null, { fetchPolicies })(SearchBar);<|endoftext|>


<commit_before>'use strict';

angular
  .module('porttare.services')
  .factory('InterceptorsService', InterceptorsService);

function InterceptorsService($injector, $q) {
  var service = {
    responseError: responseError
  };
  var currentAlert;

  return service;

  function responseError(rejection) {
    if (rejection.status === 401 && !rejection.config.url.match('api/auth/user/sign_in')) {
      closeCurrentAlert();
      createAlert();
    }
    return $q.reject(rejection);
  }

  function createAlert() {
    currentAlert = $injector.get('$ionicPopup').alert({
      title: 'Ups!',
      template: 'No tienes permisos para realizar eso!'
    });
    currentAlert.then(unsetCurrentAlert);
  }

  function unsetCurrentAlert() {
    currentAlert = null;
  }

  function closeCurrentAlert() {
    if (currentAlert) {
      currentAlert.close();
    }
  }
}
<commit_msg>Redirect to home after 401<commit_after>'use strict';

angular
  .module('porttare.services')
  .factory('InterceptorsService', InterceptorsService);

function InterceptorsService($injector, $q) {
  var service = {
    responseError: responseError
  };
  var currentAlert;

  return service;

  function responseError(rejection) {
    if (rejection.status === 401 && !rejection.config.url.match('api/auth/user/sign_in')) {
      closeCurrentAlert();
      createAlert();
    }
    return $q.reject(rejection);
  }

  function createAlert() {
    currentAlert = $injector.get('$ionicPopup').alert({
      title: 'Ups!',
      template: 'No tienes permisos para realizar eso!'
    });
    currentAlert.then(function(){
      unsetCurrentAlert();
      $injector.get('$state').go('app.categories.index');
    });
  }

  function unsetCurrentAlert() {
    currentAlert = null;
  }

  function closeCurrentAlert() {
    if (currentAlert) {
      currentAlert.close();
    }
  }
}
<|endoftext|>


<commit_before>'use strict';

var WordsFinderApp = function(){
  var lettersGrid;

  var initialize = function(){
    getLettersElements().forEach(function(el){
      $(el).attr("maxlength", 1);
    });
    lettersGrid = LettersGrid(5);
    registerEventListeners();
  };

  var registerEventListeners = function(){
    $("#randomizer").click(function(event){
      $('.results').hide();
      getLettersElements().forEach(function(el){
        $(el).val( lettersGrid.randomLetter() );
      });
      return false;
    });

    $("#finder").click(function(event){
      uiWaitingState(true);

      var elapsedTime = TimeTracker();
      elapsedTime.start();
      lettersGrid.findWords(getLettersMatrix(), function(words){
        elapsedTime.stop();
        uiWaitingState(false);
        showWordsFound(words);
        $('.benchmark span').html( elapsedTime.getTime() );
      });

      return false;
    });

    $('.words').on('mouseenter', 'span', function(event){
      var el = $(event.target);
      el.addClass('highlight-word');
      toggleLettersHighlight( el.data('positions'), true);
      return false;
    });

    $('.words').on('mouseleave', 'span', function(event){
      var el = $(event.target);
      el.removeClass('highlight-word');
      toggleLettersHighlight( el.data('positions'), false);
      return false;
    });
  };

  function getLettersMatrix(){
    var lettersMatrix = [];
    var elements = getLettersElements();
    var dimension = lettersGrid.getDimension();
    for(var i = 0; i < dimension; i++){
      lettersMatrix[i] = [];
      for(var j = 0; j < dimension; j++){
        lettersMatrix[i][j] = $(elements[j*dimension + i]).val();
      }
    }
    return lettersMatrix;
  }

  function getLettersElements(){
    return $.makeArray($('input.letter'));
  }

  function uiWaitingState(waiting){
    if(waiting){
      $('#randomizer').attr('disabled', 'disabled');
      $('#finder').attr('disabled', 'disabled');
      $('.results').hide();
      $('.loading').show();
    }else{
      $('.loading').hide();
      $('#finder').removeAttr('disabled');
      $('#randomizer').removeAttr('disabled');
    }
  }

  function toggleLettersHighlight(positions, highlight){
    positions = JSON.parse(positions);
    getGridElements(positions).map(function(el){
      el.toggleClass('highlight-letter', highlight);
    });
  }

  function getGridElements(positions){
    var inputs = getLettersElements();
    return positions.map(function(position){
      return $(inputs[position[0] + lettersGrid.getDimension() * position[1]]);
    });
  }

  function showWordsFound(words){
    $('.results h2 span').html(words.length);
    $('.results').show();
    $('.words').empty();
    var list = $('.words');
    var count = words.length;
    words.forEach(function(word){
      var word_el = $('<span />').data('positions', JSON.stringify(word[1]) ).html( word[0] );
      list.append(word_el);
      words.indexOf(word) == (count - 1) ? list.append('.') : list.append(', ');
    });
  }

  // export public interface
  return {
    initialize: initialize
  };
};
<commit_msg>algorithm: forces letters to be lower cased<commit_after>'use strict';

var WordsFinderApp = function(){
  var lettersGrid;

  var initialize = function(){
    getLettersElements().forEach(function(el){
      $(el).attr("maxlength", 1);
    });
    lettersGrid = LettersGrid(5);
    registerEventListeners();
  };

  var registerEventListeners = function(){
    $("#randomizer").click(function(event){
      $('.results').hide();
      getLettersElements().forEach(function(el){
        $(el).val( lettersGrid.randomLetter() );
      });
      return false;
    });

    $("#finder").click(function(event){
      uiWaitingState(true);

      var elapsedTime = TimeTracker();
      elapsedTime.start();
      lettersGrid.findWords(getLettersMatrix(), function(words){
        elapsedTime.stop();
        uiWaitingState(false);
        showWordsFound(words);
        $('.benchmark span').html( elapsedTime.getTime() );
      });

      return false;
    });

    $('.words').on('mouseenter', 'span', function(event){
      var el = $(event.target);
      el.addClass('highlight-word');
      toggleLettersHighlight( el.data('positions'), true);
      return false;
    });

    $('.words').on('mouseleave', 'span', function(event){
      var el = $(event.target);
      el.removeClass('highlight-word');
      toggleLettersHighlight( el.data('positions'), false);
      return false;
    });
  };

  function getLettersMatrix(){
    var lettersMatrix = [];
    var elements = getLettersElements();
    var dimension = lettersGrid.getDimension();
    for(var i = 0; i < dimension; i++){
      lettersMatrix[i] = [];
      for(var j = 0; j < dimension; j++){
        lettersMatrix[i][j] = $(elements[j*dimension + i]).val().toLowerCase();
      }
    }
    return lettersMatrix;
  }

  function getLettersElements(){
    return $.makeArray($('input.letter'));
  }

  function uiWaitingState(waiting){
    if(waiting){
      $('#randomizer').attr('disabled', 'disabled');
      $('#finder').attr('disabled', 'disabled');
      $('.results').hide();
      $('.loading').show();
    }else{
      $('.loading').hide();
      $('#finder').removeAttr('disabled');
      $('#randomizer').removeAttr('disabled');
    }
  }

  function toggleLettersHighlight(positions, highlight){
    positions = JSON.parse(positions);
    getGridElements(positions).map(function(el){
      el.toggleClass('highlight-letter', highlight);
    });
  }

  function getGridElements(positions){
    var inputs = getLettersElements();
    return positions.map(function(position){
      return $(inputs[position[0] + lettersGrid.getDimension() * position[1]]);
    });
  }

  function showWordsFound(words){
    $('.results h2 span').html(words.length);
    $('.results').show();
    $('.words').empty();
    var list = $('.words');
    var count = words.length;
    words.forEach(function(word){
      var word_el = $('<span />').data('positions', JSON.stringify(word[1]) ).html( word[0] );
      list.append(word_el);
      words.indexOf(word) == (count - 1) ? list.append('.') : list.append(', ');
    });
  }

  // export public interface
  return {
    initialize: initialize
  };
};
<|endoftext|>


<commit_before>'use strict'

let Inflector = require('inflected')
let Cape = require('./utilities')

// Cape.RoutingMapper
class RoutingMapper {
  constructor(router, options) {
    this._ = new _Internal(this)
    this.router = router
    if (options) {
      // The namespace part of URL hash
      this.namespacePath = options.namespacePath
      this.singular = options.singular
      this.pathPrefix = options.pathPrefix
      this.resourcePath = options.resourcePath
      this.classNamePrefix = options.classNamePrefix
      this.resourceClassName = options.resourceClassName
    }
  }

  page(path, className, constraints, options) {
    if (path === undefined) throw new Error("Missing hash pattern.")

    if (className === undefined) {
      if (path.match(/^\w+(\/\w+)*$/)) className = path.replace('/', '.')
      else throw new Error("Missing class name path.")
    }

    if (this.pathPrefix) path = this.pathPrefix + '/' + path

    this._constructRouteForPage(path, className, constraints, options)
  }

  _constructRouteForPage(path, className, constraints, options) {
    options = options || {}

    let route = {}

    route.path = path
    route.keys = this._.extractKeys(path)
    route.regexp = this._.constructRegexp(path, constraints)
    route.namespace = this.namespacePath || null
    route.action = options.action || null
    this._setComponentAndContainer(route, path, className, constraints)
    this._setResource(route, options)

    this.router.routes.push(route)
  }

  _setComponentAndContainer(route, path, className, constraints) {
    let fullClassName
    if (this.classNamePrefix)
      fullClassName = this.classNamePrefix + '.' + className
    else
      fullClassName = className

    let fragments = fullClassName.split('.')
    route.component = fragments.pop()
    route.container = fragments.length ? fragments.join('.') : null
  }

  _setResource(route, options) {
    let resourceNames = []
    if (this.resourcePath) resourceNames.push(this.resourcePath)
    if (options.resource) resourceNames.push(options.resource)
    if (resourceNames.length) route.resource = resourceNames.join('/')
    else route.resource = null
  }

  root(className) {
    this.page('', className)
  }

  many(resourceName) {
    this._many_or_one(resourceName, arguments, false)
  }

  one(resourceName) {
    this._many_or_one(resourceName, arguments, true)
  }

  _many_or_one(resourceName, args, singular) {
    let options = this._.extractOptions(args)
    let callback = this._.extractCallback(args)
    let resourcePath = this._.getResourcePath(options.path || resourceName)

    let registrar = new _PageRegistrar(this, resourceName, resourcePath, options)
    if (singular)
      registrar.addPagesForSingularResource()
    else
      registrar.addPagesForPluralResource()

    this._.executeCallback(callback, resourceName, resourcePath, singular)
  }

  collection() {
    let args

    if (this.resourcePath === undefined || this.singular)
      throw new Error("The collection method must be called within a plural resource definition.")

    args = Array.prototype.slice.call(arguments, 0)
    args.forEach(function(path) {
      this.page(this.resourcePath + '/' + path,
        this.resourcePath + '.' + path, {}, { action: path })
    }.bind(this))
  }

  member() {
    let args

    if (this.resourcePath === undefined || this.singular)
      throw new Error("The member method must be called within a plural resource definition.")

    args = Array.prototype.slice.call(arguments, 0)
    args.forEach(function(path) {
      this.page(this.resourcePath + '/:id/' + path,
        this.resourcePath + '.' + path, { id: '\\d+' }, {}, { action: path })
    }.bind(this))
  }

  new() {
    let args

    if (this.resourcePath === undefined)
      throw new Error("The member method must be called within a resource definition.")

    args = Array.prototype.slice.call(arguments, 0)
    args.forEach(function(path) {
      this.page(this.resourcePath + '/new/' + path,
        this.resourcePath + '.' + path, {}, { action: path })
    }.bind(this))
  }

  view() {
    let args

    if (this.resourcePath === undefined || !this.singular)
      throw new Error("The view method must be called within a singular resource definition.")

    args = Array.prototype.slice.call(arguments, 0)
    args.forEach(function(path) {
      this.page(this.resourcePath + '/' + path,
        this.resourcePath + '.' + path, {}, { action: path })
    }.bind(this))
  }

  namespace(className) {
    let args = Array.prototype.slice.call(arguments, 1)
    let callback = args.pop()
    let options = args.pop() || {}

    if (typeof callback !== 'function')
      throw new Error("The last argument must be a function.")
    if (callback.length === 0)
      throw new Error("Callback requires an argument.")

    let path = options.path || className

    callback(
      new RoutingMapper(this.router, {
        namespacePath: this.namespacePath ? this.namespacePath + '/' + path : path,
        pathPrefix: this.pathPrefix ? this.pathPrefix + '/' + path : path,
        classNamePrefix: this.classNamePrefix ?
          this.classNamePrefix + '.' + className : className
      })
    )
  }
}

// Internal class of Cape.Component
class _Internal {
  constructor(main) {
    this.main = main
  }

  extractKeys(path) {
    let keys = [], md

    path.split('/').forEach(function(fragment) {
      md = fragment.match(/^:(\w+)$/)
      if (md) keys.push(md[1])
    })
    return keys
  }

  constructRegexp(path, constraints) {
    let fragments = [], md

    constraints = constraints || {}
    path.split('/').forEach(function(fragment) {
      md = fragment.match(/^:(\w+)$/)
      if (md) {
        if (constraints[md[1]])
          fragments.push('(' + constraints[md[1]] + ')')
        else
          fragments.push('([^/]+)')
      }
      else if (fragment.match(/^\w+$/)) {
        fragments.push(fragment)
      }
    })
    return new RegExp('^' + fragments.join('/') +
      '(?:\\?[\\w-]+(?:=[\\w-]*)?(?:&[\\w-]+(?:=[\\w-]*)?)*)?$')
  }

  extractOptions(args) {
    if (typeof args[1] === 'function') return {}
    else return args[1] || {}
  }

  extractCallback(args) {
    if (typeof args[1] === 'function') return args[1]
    else return args[2]
  }

  getResourcePath(path) {
    if (this.main.resourcePath) {
      if (this.main.singular) {
        path = this.main.resourcePath + '/' + path
      }
      else {
        path = this.main.resourcePath
          + '/:' + Inflector.singularize(this.main.resourcePath) + '_id/' + path
      }
    }
    return path
  }

  executeCallback(callback, resourceName, resourcePath, singular) {
    if (typeof callback === 'function') {
      if (callback.length === 0)
        throw new Error("Callback requires an argument.")
      return callback(
        new RoutingMapper(this.main.router, {
          singular: singular,
          pathPrefix: this.main.pathPrefix,
          resourcePath: resourcePath,
          classNamePrefix: this.main.classNamePrefix,
          resourceClassName: resourceName
        })
      )
    }
  }
}

// Internal class of Cape.Component
class _PageRegistrar {
  constructor(main, resourceName, resourcePath, options) {
    this.main = main
    this.resourceName = resourceName
    this.resourcePath = resourcePath
    this.options = options || {}
  }

  addPagesForPluralResource() {
    let actions = [ 'index', 'new', 'show', 'edit' ]

    this._filterActions(actions)

    this.options.pathNames = this.options.pathNames || {}

    if (actions.indexOf('index') !== -1)
      this.main.page(this.resourcePath, this.resourceName + '.list', {},
        { resource: this.resourceName, action: 'index' })

    this._addSingularFormPage(actions, 'new')

    if (actions.indexOf('show') !== -1)
      this.main.page(this.resourcePath + '/:id', this.resourceName + '.item', { id: '\\d+' },
        { resource: this.resourceName, action: 'show' })

    if (actions.indexOf('edit') !== -1) {
      let pathName = this.options.pathNames.edit ? this.options.pathNames.edit : 'edit'
      this.main.page(this.resourcePath + '/:id/' + pathName, this.resourceName + '.form',
        { id: '\\d+' }, { resource: this.resourceName, action: 'edit' })
    }
  }

  addPagesForSingularResource() {
    let actions = [ 'new', 'show', 'edit' ], pathName

    this._filterActions(actions)

    this.options.pathNames = this.options.pathNames || {}

    if (actions.indexOf('show') !== -1)
      this.main.page(this.resourcePath, this.resourceName + '.content', {},
        { resource: this.resourceName, action: 'show' })

    this._addSingularFormPage(actions, 'new')
    this._addSingularFormPage(actions, 'edit')
  }

  _addSingularFormPage(actions, actionName) {
    if (actions.indexOf(actionName) !== -1) {
      let pathName = this.options.pathNames[actionName] ?
        this.options.pathNames[actionName] : actionName
      this.main.page(this.resourcePath + '/' + pathName,
        this.resourceName + '.form', {},
        { resource: this.resourceName, action: actionName })
    }
  }

  _filterActions(actions) {
    this._keepActions(actions)
    this._excludeActions(actions)
  }

  _keepActions(actions) {
    if (typeof this.options['only'] === 'string') {
      actions.length = 0
      actions.push(this.options['only'])
    }

    if (Array.isArray(this.options['only'])) {
      actions.length = 0
      this.options['only'].forEach(function(name) { actions.push(name) })
    }
  }

  _excludeActions(actions) {
    let idx

    if (typeof this.options['except'] === 'string') {
      idx = actions.indexOf(this.options['except'])
      if (idx !== -1) actions.splice(idx, 1)
    }

    if (Array.isArray(this.options['except'])) {
      this.options['except'].forEach(function(name) {
        idx = actions.indexOf(name)
        if (idx !== -1) actions.splice(idx, 1)
      })
    }
  }
}

module.exports = RoutingMapper
<commit_msg>Refactor RoutingMapper#member, #new, #view<commit_after>'use strict'

let Inflector = require('inflected')
let Cape = require('./utilities')

// Cape.RoutingMapper
class RoutingMapper {
  constructor(router, options) {
    this._ = new _Internal(this)
    this.router = router
    if (options) {
      // The namespace part of URL hash
      this.namespacePath = options.namespacePath
      this.singular = options.singular
      this.pathPrefix = options.pathPrefix
      this.resourcePath = options.resourcePath
      this.classNamePrefix = options.classNamePrefix
      this.resourceClassName = options.resourceClassName
    }
  }

  page(path, className, constraints, options) {
    if (path === undefined) throw new Error("Missing hash pattern.")

    if (className === undefined) {
      if (path.match(/^\w+(\/\w+)*$/)) className = path.replace('/', '.')
      else throw new Error("Missing class name path.")
    }

    if (this.pathPrefix) path = this.pathPrefix + '/' + path

    this._constructRouteForPage(path, className, constraints, options)
  }

  _constructRouteForPage(path, className, constraints, options) {
    options = options || {}

    let route = {}

    route.path = path
    route.keys = this._.extractKeys(path)
    route.regexp = this._.constructRegexp(path, constraints)
    route.namespace = this.namespacePath || null
    route.action = options.action || null
    this._setComponentAndContainer(route, path, className, constraints)
    this._setResource(route, options)

    this.router.routes.push(route)
  }

  _setComponentAndContainer(route, path, className, constraints) {
    let fullClassName
    if (this.classNamePrefix)
      fullClassName = this.classNamePrefix + '.' + className
    else
      fullClassName = className

    let fragments = fullClassName.split('.')
    route.component = fragments.pop()
    route.container = fragments.length ? fragments.join('.') : null
  }

  _setResource(route, options) {
    let resourceNames = []
    if (this.resourcePath) resourceNames.push(this.resourcePath)
    if (options.resource) resourceNames.push(options.resource)
    if (resourceNames.length) route.resource = resourceNames.join('/')
    else route.resource = null
  }

  root(className) {
    this.page('', className)
  }

  many(resourceName) {
    this._many_or_one(resourceName, arguments, false)
  }

  one(resourceName) {
    this._many_or_one(resourceName, arguments, true)
  }

  _many_or_one(resourceName, args, singular) {
    let options = this._.extractOptions(args)
    let callback = this._.extractCallback(args)
    let resourcePath = this._.getResourcePath(options.path || resourceName)

    let registrar = new _PageRegistrar(this, resourceName, resourcePath, options)
    if (singular)
      registrar.addPagesForSingularResource()
    else
      registrar.addPagesForPluralResource()

    this._.executeCallback(callback, resourceName, resourcePath, singular)
  }

  collection() {
    let args

    if (this.resourcePath === undefined || this.singular)
      throw new Error("The collection method must be called within a plural resource definition.")

    args = Array.prototype.slice.call(arguments, 0)
    args.forEach(path => {
      this.page(this.resourcePath + '/' + path,
        this.resourcePath + '.' + path, {}, { action: path })
    })
  }

  member() {
    if (this.resourcePath === undefined || this.singular)
      throw new Error("The member method must be called within a plural resource definition.")

    this._defineRoutesForPaths(arguments, '/:id/')
  }

  new() {
    if (this.resourcePath === undefined)
      throw new Error("The member method must be called within a resource definition.")

    this._defineRoutesForPaths(arguments, '/new/')
  }

  view() {
    if (this.resourcePath === undefined || !this.singular)
      throw new Error("The view method must be called within a singular resource definition.")

    this._defineRoutesForPaths(arguments, '/')
  }

  _defineRoutesForPaths(args, connector) {
    let paths = Array.prototype.slice.call(args, 0)

    let constraints = {}
    if (connector === '/:id/') constraints.id = '\\d+'

    paths.forEach(path => {
      this.page(this.resourcePath + connector + path,
        this.resourcePath + '.' + path, constraints, { action: path })
    })
  }

  namespace(className) {
    let args = Array.prototype.slice.call(arguments, 1)
    let callback = args.pop()
    let options = args.pop() || {}

    if (typeof callback !== 'function')
      throw new Error("The last argument must be a function.")
    if (callback.length === 0)
      throw new Error("Callback requires an argument.")

    let path = options.path || className

    callback(
      new RoutingMapper(this.router, {
        namespacePath: this.namespacePath ? this.namespacePath + '/' + path : path,
        pathPrefix: this.pathPrefix ? this.pathPrefix + '/' + path : path,
        classNamePrefix: this.classNamePrefix ?
          this.classNamePrefix + '.' + className : className
      })
    )
  }
}

// Internal class of Cape.Component
class _Internal {
  constructor(main) {
    this.main = main
  }

  extractKeys(path) {
    let keys = [], md

    path.split('/').forEach(function(fragment) {
      md = fragment.match(/^:(\w+)$/)
      if (md) keys.push(md[1])
    })
    return keys
  }

  constructRegexp(path, constraints) {
    let fragments = [], md

    constraints = constraints || {}
    path.split('/').forEach(function(fragment) {
      md = fragment.match(/^:(\w+)$/)
      if (md) {
        if (constraints[md[1]])
          fragments.push('(' + constraints[md[1]] + ')')
        else
          fragments.push('([^/]+)')
      }
      else if (fragment.match(/^\w+$/)) {
        fragments.push(fragment)
      }
    })
    return new RegExp('^' + fragments.join('/') +
      '(?:\\?[\\w-]+(?:=[\\w-]*)?(?:&[\\w-]+(?:=[\\w-]*)?)*)?$')
  }

  extractOptions(args) {
    if (typeof args[1] === 'function') return {}
    else return args[1] || {}
  }

  extractCallback(args) {
    if (typeof args[1] === 'function') return args[1]
    else return args[2]
  }

  getResourcePath(path) {
    if (this.main.resourcePath) {
      if (this.main.singular) {
        path = this.main.resourcePath + '/' + path
      }
      else {
        path = this.main.resourcePath
          + '/:' + Inflector.singularize(this.main.resourcePath) + '_id/' + path
      }
    }
    return path
  }

  executeCallback(callback, resourceName, resourcePath, singular) {
    if (typeof callback === 'function') {
      if (callback.length === 0)
        throw new Error("Callback requires an argument.")
      return callback(
        new RoutingMapper(this.main.router, {
          singular: singular,
          pathPrefix: this.main.pathPrefix,
          resourcePath: resourcePath,
          classNamePrefix: this.main.classNamePrefix,
          resourceClassName: resourceName
        })
      )
    }
  }
}

// Internal class of Cape.Component
class _PageRegistrar {
  constructor(main, resourceName, resourcePath, options) {
    this.main = main
    this.resourceName = resourceName
    this.resourcePath = resourcePath
    this.options = options || {}
  }

  addPagesForPluralResource() {
    let actions = [ 'index', 'new', 'show', 'edit' ]

    this._filterActions(actions)

    this.options.pathNames = this.options.pathNames || {}

    if (actions.indexOf('index') !== -1)
      this.main.page(this.resourcePath, this.resourceName + '.list', {},
        { resource: this.resourceName, action: 'index' })

    this._addSingularFormPage(actions, 'new')

    if (actions.indexOf('show') !== -1)
      this.main.page(this.resourcePath + '/:id', this.resourceName + '.item', { id: '\\d+' },
        { resource: this.resourceName, action: 'show' })

    if (actions.indexOf('edit') !== -1) {
      let pathName = this.options.pathNames.edit ? this.options.pathNames.edit : 'edit'
      this.main.page(this.resourcePath + '/:id/' + pathName, this.resourceName + '.form',
        { id: '\\d+' }, { resource: this.resourceName, action: 'edit' })
    }
  }

  addPagesForSingularResource() {
    let actions = [ 'new', 'show', 'edit' ], pathName

    this._filterActions(actions)

    this.options.pathNames = this.options.pathNames || {}

    if (actions.indexOf('show') !== -1)
      this.main.page(this.resourcePath, this.resourceName + '.content', {},
        { resource: this.resourceName, action: 'show' })

    this._addSingularFormPage(actions, 'new')
    this._addSingularFormPage(actions, 'edit')
  }

  _addSingularFormPage(actions, actionName) {
    if (actions.indexOf(actionName) !== -1) {
      let pathName = this.options.pathNames[actionName] ?
        this.options.pathNames[actionName] : actionName
      this.main.page(this.resourcePath + '/' + pathName,
        this.resourceName + '.form', {},
        { resource: this.resourceName, action: actionName })
    }
  }

  _filterActions(actions) {
    this._keepActions(actions)
    this._excludeActions(actions)
  }

  _keepActions(actions) {
    if (typeof this.options['only'] === 'string') {
      actions.length = 0
      actions.push(this.options['only'])
    }

    if (Array.isArray(this.options['only'])) {
      actions.length = 0
      this.options['only'].forEach(function(name) { actions.push(name) })
    }
  }

  _excludeActions(actions) {
    let idx

    if (typeof this.options['except'] === 'string') {
      idx = actions.indexOf(this.options['except'])
      if (idx !== -1) actions.splice(idx, 1)
    }

    if (Array.isArray(this.options['except'])) {
      this.options['except'].forEach(function(name) {
        idx = actions.indexOf(name)
        if (idx !== -1) actions.splice(idx, 1)
      })
    }
  }
}

module.exports = RoutingMapper
<|endoftext|>