<commit_before>/*global describe, module, beforeEach, afterEach, it, expect, inject, jasmine, spyOn*/

describe('AngularJpeg', function () {
  'use strict';
  var $window, $rootScope, $q;
  var AngularJpeg, TYPES, ERRORS, FIXTURES, PREFIX;

  var readAsArrayBuffer, fileReader;
  var FileReaderMock = function() {
    fileReader = this;
    this.readAsArrayBuffer = readAsArrayBuffer;
  };
  var FileMock = function() {};

  function toBuffer(array) {
    var buffer = new $window.ArrayBuffer(array.length);
    var view = new $window.Uint8Array(buffer);
    view.set(array);
    return buffer;
  }

  beforeEach(module('angular-jpeg'));

  beforeEach(inject(function(_$window_, _$rootScope_, _$q_, _AngularJpeg_,
    _ANGULAR_JPEG_SEGMENT_TYPES_,
    _ANGULAR_JPEG_SEGMENT_PREFIX_,
    _ANGULAR_JPEG_ERRORS_) {
    $window = _$window_;
    $rootScope = _$rootScope_;
    $q = _$q_;
    AngularJpeg = _AngularJpeg_;
    ERRORS = _ANGULAR_JPEG_ERRORS_;
    TYPES = _ANGULAR_JPEG_SEGMENT_TYPES_;
    PREFIX = _ANGULAR_JPEG_SEGMENT_PREFIX_;

    FIXTURES = {
      withoutSegments: [PREFIX, PREFIX],
      withoutStartMarker: [PREFIX, TYPES.endOfImage.marker],
      withoutEndMarker: [PREFIX, TYPES.startOfImage.marker],
      withStartAndEndMarker: [PREFIX, TYPES.startOfImage.marker, PREFIX, TYPES.endOfImage.marker],
      withUnsupportedMarker: [
        PREFIX, TYPES.startOfImage.marker,
        PREFIX, TYPES.startOfFrameExtendedSequentialDCT.marker, 0x0, 0x2,
        PREFIX, TYPES.endOfImage.marker
      ],
      withUnrecognisedMarker: [
        PREFIX, TYPES.startOfImage.marker,
        PREFIX, 0x02,
        PREFIX, TYPES.endOfImage.marker
      ],
      withSegmentData: [
        PREFIX, TYPES.startOfImage.marker,
        PREFIX, TYPES.comment.marker, 0x0, 0x3, 0x0,
        PREFIX, TYPES.endOfImage.marker
      ],
      withScanData: [
        PREFIX, TYPES.startOfImage.marker,
        PREFIX, TYPES.startOfScan.marker, 0x0, 0x2, 0x0,
        PREFIX, TYPES.endOfImage.marker
      ]
    };
  }));

  describe('loadSegmentsFromBuffer', function() {
    it('should reject data without a start marker', function() {
      var error;
      AngularJpeg.loadSegmentsFromBuffer(toBuffer(FIXTURES.withoutStartMarker)).catch(function(_error_) {
        error = _error_;
      });
      $rootScope.$digest();
      expect(error).toBe(ERRORS.missingStartOfImageMarker);
    });

    it('should reject data without an end marker', function() {
      var error;
      AngularJpeg.loadSegmentsFromBuffer(toBuffer(FIXTURES.withoutEndMarker)).catch(function(_error_) {
        error = _error_;
      });
      $rootScope.$digest();
      expect(error).toBe(ERRORS.missingEndOfImageMarker);
    });

    it('reject data without any segments', function() {
      var error;
      AngularJpeg.loadSegmentsFromBuffer(toBuffer(FIXTURES.withoutSegments)).catch(function(_error_) {
        error = _error_;
      });
      $rootScope.$digest();
      expect(error).toBe(ERRORS.noSegments);
    });

    it('reject data with unsupported marker', function() {
      var error;
      AngularJpeg.loadSegmentsFromBuffer(toBuffer(FIXTURES.withUnsupportedMarker)).catch(function(_error_) {
        error = _error_;
      });
      $rootScope.$digest();
      expect(error).toBe(ERRORS.unsupportedMarker + ': ' + TYPES.startOfFrameExtendedSequentialDCT.marker);
    });

    it('reject data with unrecogised marker', function() {
      var error;
      AngularJpeg.loadSegmentsFromBuffer(toBuffer(FIXTURES.withUnrecognisedMarker)).catch(function(_error_) {
        error = _error_;
      });
      $rootScope.$digest();
      expect(error).toBe(ERRORS.unrecognisedMarker + ': ' + 0x02);
    });

    it('should load data with start and end markers', function() {
      var results;
      AngularJpeg.loadSegmentsFromBuffer(toBuffer(FIXTURES.withStartAndEndMarker)).then(function(_results_) {
        results = _results_;
      });
      $rootScope.$digest();
      expect(results).toEqual({
        startOfImage: [{
          type: TYPES.startOfImage,
          segmentOffset: 2,
          segmentSize: 0,
          segmentContents: new $window.Uint8Array(),
          dataOffset: 2,
          dataSize: 0,
          dataContents: new $window.Uint8Array()
        }],
        endOfImage: [{
          type: TYPES.endOfImage,
          segmentOffset: 4,
          segmentSize: 0,
          segmentContents: new $window.Uint8Array(),
          dataOffset: 4,
          dataSize: 0,
          dataContents: new $window.Uint8Array()
        }]
      });
    });

    it('should load data with non empty segment', function() {
      var results;
      var buffer = toBuffer(FIXTURES.withSegmentData);
      AngularJpeg.loadSegmentsFromBuffer(buffer).then(function(_results_) {
        results = _results_;
      });
      $rootScope.$digest();
      expect(results).toEqual({
        startOfImage: [{
          type: TYPES.startOfImage,
          segmentOffset: 2,
          segmentSize: 0,
          segmentContents: new $window.Uint8Array(),
          dataOffset: 2,
          dataSize: 0,
          dataContents: new $window.Uint8Array()
        }],
        comment: [{
          type: TYPES.comment,
          segmentOffset: 6,
          segmentSize: 1,
          segmentContents: new $window.Uint8Array(buffer, 6, 1),
          dataOffset: 7,
          dataSize: 0,
          dataContents: new $window.Uint8Array()
        }],
        endOfImage: [{
          type: TYPES.endOfImage,
          segmentOffset: 9,
          segmentSize: 0,
          segmentContents: new $window.Uint8Array(),
          dataOffset: 9,
          dataSize: 0,
          dataContents: new $window.Uint8Array()
        }]
      });
    });

    it('should load data with scan data', function() {
      var results;
      var buffer = toBuffer(FIXTURES.withScanData);
      AngularJpeg.loadSegmentsFromBuffer(toBuffer(FIXTURES.withScanData)).then(function(_results_) {
        results = _results_;
      });
      $rootScope.$digest();
      expect(results).toEqual({
        startOfImage: [{
          type: TYPES.startOfImage,
          segmentOffset: 2,
          segmentSize: 0,
          segmentContents: new $window.Uint8Array(),
          dataOffset: 2,
          dataSize: 0,
          dataContents: new $window.Uint8Array()
        }],
        startOfScan: [{
          type: TYPES.startOfScan,
          segmentOffset: 6,
          segmentSize: 0,
          segmentContents: new $window.Uint8Array(),
          dataOffset: 6,
          dataSize: 1,
          dataContents: new $window.Uint8Array(buffer, 6, 1)
        }],
        endOfImage: [{
          type: TYPES.endOfImage,
          segmentOffset: 9,
          segmentSize: 0,
          segmentContents: new $window.Uint8Array(),
          dataOffset: 9,
          dataSize: 0,
          dataContents: new $window.Uint8Array()
        }]
      });
    });
  });

  describe('loadSegmentsFromFile', function() {
    var loadSegmentsFromBufferDeferred;
    var readAsArrayBufferResults;
    var loadSegmentsFromBufferResults;
    var loadSegmentsFromBufferError;
    var loadSegmentsFromFileResults;
    var loadSegmentsFromFileError;
    var originalFileReader;

    beforeEach(function() {
      originalFileReader = $window.FileReader;
      $window.FileReader = FileReaderMock;
    });

    afterEach(function() {
      $window.FileReader = originalFileReader;
      originalFileReader = null;
    });

    beforeEach(function() {
      loadSegmentsFromBufferDeferred = $q.defer();
      spyOn(AngularJpeg, 'loadSegmentsFromBuffer').and.returnValue(loadSegmentsFromBufferDeferred.promise);
      readAsArrayBufferResults = {};
      loadSegmentsFromBufferResults = {};
      loadSegmentsFromBufferError = {};
      loadSegmentsFromFileResults = null;
      loadSegmentsFromFileError = null;
    });

    it('should reject if no file passed', function() {
      AngularJpeg.loadSegmentsFromFile(null).catch(function(_loadSegmentsFromFileError_) {
        loadSegmentsFromFileError = _loadSegmentsFromFileError_;
      });
      $rootScope.$digest();
      expect(loadSegmentsFromFileError).toBe(ERRORS.noFile);
    });

    it('should pass the file to readAsArrayBuffer', function() {
      readAsArrayBuffer = jasmine.createSpy('readAsArrayBuffer');
      var file = new FileMock();
      AngularJpeg.loadSegmentsFromFile(file);
      expect(readAsArrayBuffer).toHaveBeenCalledWith(file);
    });

    describe('on file read error', function() {
      it('should reject the promise on readFromBuffer error', function() {
        readAsArrayBuffer = function() {
          fileReader.onerror();
        };
        AngularJpeg.loadSegmentsFromFile(new FileMock()).catch(function(_loadSegmentsFromFileError_) {
          loadSegmentsFromFileError = _loadSegmentsFromFileError_;
        });
        $rootScope.$digest();
        expect(loadSegmentsFromFileError).toBe(ERRORS.fileReadError);
      });
    });

    describe('on file read success', function() {
      beforeEach(function() {
        readAsArrayBuffer = function() {
          fileReader.onload({
            target: {
              result: readAsArrayBufferResults
            }
          });
        };
        AngularJpeg.loadSegmentsFromFile(new FileMock()).then(function(_loadSegmentsFromFileResults_) {
          loadSegmentsFromFileResults = _loadSegmentsFromFileResults_;
        }, function(_loadSegmentsFromFileError_) {
          loadSegmentsFromFileError = _loadSegmentsFromFileError_;
        });
      });

      it('should pass the results of readAsArrayBuffer to loadSegmentsFromBuffer', function() {
        expect(AngularJpeg.loadSegmentsFromBuffer).toHaveBeenCalledWith(readAsArrayBufferResults);
      });

      describe('and on validation error', function() {
        it('should reject with the error from loadSegmentsFromBuffer', function() {
          loadSegmentsFromBufferDeferred.reject(loadSegmentsFromBufferError);
          $rootScope.$digest();
          expect(loadSegmentsFromFileError).toBe(loadSegmentsFromBufferError);
        });
      });

      describe('and on loadSegmentsFromBufferSuccess', function() {
        it('should resolve with the results from loadSegmentsFromBuffer', function() {
          loadSegmentsFromBufferDeferred.resolve(loadSegmentsFromBufferResults);
          $rootScope.$digest();
          expect(loadSegmentsFromFileResults).toBe(loadSegmentsFromBufferResults);
        });
      });
    });
  });

  describe('_huffmanTreeFromTable', function() {
    it('should decode a trivial tree', function() {
      var table = [
        [1],
        [2, 3]
      ];
      var tree = {
        0: 1,
        1: {
          0: 2,
          1: 3
        }
      };
      expect(AngularJpeg._huffmanTreeFromTable(table)).toEqual(tree);
    });

    it('should decode a complex tree', function() {
      var table = [
        [],
        [2,3],
        [],
        [4,5,6],
        [7,8],
        [],
        [9,10,11,12]
      ];
      var tree = {
        0: {
          0: 2,
          1: 3
        },
        1: {
          0: {
            0: {
              0: 4,
              1: 5
            },
            1: {
              0: 6,
              1: {
                0: 7,
                1: 8
              }
            }
          },
          1: {
            0: {
              0: {
                0: {
                  0: {
                    0: {
                      0: 9,
                      1: 10
                    },
                    1: {
                      0: 11,
                      1: 12
                    }
                  }
                }
              }
            }
          }
        }
      };
      expect(AngularJpeg._huffmanTreeFromTable(table)).toEqual(tree);
    });
  });
});<commit_msg>Object structure for Huffman table format (avoids empty arrays<commit_after>/*global describe, module, beforeEach, afterEach, it, expect, inject, jasmine, spyOn*/

describe('AngularJpeg', function () {
  'use strict';
  var $window, $rootScope, $q;
  var AngularJpeg, TYPES, ERRORS, FIXTURES, PREFIX;

  var readAsArrayBuffer, fileReader;
  var FileReaderMock = function() {
    fileReader = this;
    this.readAsArrayBuffer = readAsArrayBuffer;
  };
  var FileMock = function() {};

  function toBuffer(array) {
    var buffer = new $window.ArrayBuffer(array.length);
    var view = new $window.Uint8Array(buffer);
    view.set(array);
    return buffer;
  }

  beforeEach(module('angular-jpeg'));

  beforeEach(inject(function(_$window_, _$rootScope_, _$q_, _AngularJpeg_,
    _ANGULAR_JPEG_SEGMENT_TYPES_,
    _ANGULAR_JPEG_SEGMENT_PREFIX_,
    _ANGULAR_JPEG_ERRORS_) {
    $window = _$window_;
    $rootScope = _$rootScope_;
    $q = _$q_;
    AngularJpeg = _AngularJpeg_;
    ERRORS = _ANGULAR_JPEG_ERRORS_;
    TYPES = _ANGULAR_JPEG_SEGMENT_TYPES_;
    PREFIX = _ANGULAR_JPEG_SEGMENT_PREFIX_;

    FIXTURES = {
      withoutSegments: [PREFIX, PREFIX],
      withoutStartMarker: [PREFIX, TYPES.endOfImage.marker],
      withoutEndMarker: [PREFIX, TYPES.startOfImage.marker],
      withStartAndEndMarker: [PREFIX, TYPES.startOfImage.marker, PREFIX, TYPES.endOfImage.marker],
      withUnsupportedMarker: [
        PREFIX, TYPES.startOfImage.marker,
        PREFIX, TYPES.startOfFrameExtendedSequentialDCT.marker, 0x0, 0x2,
        PREFIX, TYPES.endOfImage.marker
      ],
      withUnrecognisedMarker: [
        PREFIX, TYPES.startOfImage.marker,
        PREFIX, 0x02,
        PREFIX, TYPES.endOfImage.marker
      ],
      withSegmentData: [
        PREFIX, TYPES.startOfImage.marker,
        PREFIX, TYPES.comment.marker, 0x0, 0x3, 0x0,
        PREFIX, TYPES.endOfImage.marker
      ],
      withScanData: [
        PREFIX, TYPES.startOfImage.marker,
        PREFIX, TYPES.startOfScan.marker, 0x0, 0x2, 0x0,
        PREFIX, TYPES.endOfImage.marker
      ]
    };
  }));

  describe('loadSegmentsFromBuffer', function() {
    it('should reject data without a start marker', function() {
      var error;
      AngularJpeg.loadSegmentsFromBuffer(toBuffer(FIXTURES.withoutStartMarker)).catch(function(_error_) {
        error = _error_;
      });
      $rootScope.$digest();
      expect(error).toBe(ERRORS.missingStartOfImageMarker);
    });

    it('should reject data without an end marker', function() {
      var error;
      AngularJpeg.loadSegmentsFromBuffer(toBuffer(FIXTURES.withoutEndMarker)).catch(function(_error_) {
        error = _error_;
      });
      $rootScope.$digest();
      expect(error).toBe(ERRORS.missingEndOfImageMarker);
    });

    it('reject data without any segments', function() {
      var error;
      AngularJpeg.loadSegmentsFromBuffer(toBuffer(FIXTURES.withoutSegments)).catch(function(_error_) {
        error = _error_;
      });
      $rootScope.$digest();
      expect(error).toBe(ERRORS.noSegments);
    });

    it('reject data with unsupported marker', function() {
      var error;
      AngularJpeg.loadSegmentsFromBuffer(toBuffer(FIXTURES.withUnsupportedMarker)).catch(function(_error_) {
        error = _error_;
      });
      $rootScope.$digest();
      expect(error).toBe(ERRORS.unsupportedMarker + ': ' + TYPES.startOfFrameExtendedSequentialDCT.marker);
    });

    it('reject data with unrecogised marker', function() {
      var error;
      AngularJpeg.loadSegmentsFromBuffer(toBuffer(FIXTURES.withUnrecognisedMarker)).catch(function(_error_) {
        error = _error_;
      });
      $rootScope.$digest();
      expect(error).toBe(ERRORS.unrecognisedMarker + ': ' + 0x02);
    });

    it('should load data with start and end markers', function() {
      var results;
      AngularJpeg.loadSegmentsFromBuffer(toBuffer(FIXTURES.withStartAndEndMarker)).then(function(_results_) {
        results = _results_;
      });
      $rootScope.$digest();
      expect(results).toEqual({
        startOfImage: [{
          type: TYPES.startOfImage,
          segmentOffset: 2,
          segmentSize: 0,
          segmentContents: new $window.Uint8Array(),
          dataOffset: 2,
          dataSize: 0,
          dataContents: new $window.Uint8Array()
        }],
        endOfImage: [{
          type: TYPES.endOfImage,
          segmentOffset: 4,
          segmentSize: 0,
          segmentContents: new $window.Uint8Array(),
          dataOffset: 4,
          dataSize: 0,
          dataContents: new $window.Uint8Array()
        }]
      });
    });

    it('should load data with non empty segment', function() {
      var results;
      var buffer = toBuffer(FIXTURES.withSegmentData);
      AngularJpeg.loadSegmentsFromBuffer(buffer).then(function(_results_) {
        results = _results_;
      });
      $rootScope.$digest();
      expect(results).toEqual({
        startOfImage: [{
          type: TYPES.startOfImage,
          segmentOffset: 2,
          segmentSize: 0,
          segmentContents: new $window.Uint8Array(),
          dataOffset: 2,
          dataSize: 0,
          dataContents: new $window.Uint8Array()
        }],
        comment: [{
          type: TYPES.comment,
          segmentOffset: 6,
          segmentSize: 1,
          segmentContents: new $window.Uint8Array(buffer, 6, 1),
          dataOffset: 7,
          dataSize: 0,
          dataContents: new $window.Uint8Array()
        }],
        endOfImage: [{
          type: TYPES.endOfImage,
          segmentOffset: 9,
          segmentSize: 0,
          segmentContents: new $window.Uint8Array(),
          dataOffset: 9,
          dataSize: 0,
          dataContents: new $window.Uint8Array()
        }]
      });
    });

    it('should load data with scan data', function() {
      var results;
      var buffer = toBuffer(FIXTURES.withScanData);
      AngularJpeg.loadSegmentsFromBuffer(toBuffer(FIXTURES.withScanData)).then(function(_results_) {
        results = _results_;
      });
      $rootScope.$digest();
      expect(results).toEqual({
        startOfImage: [{
          type: TYPES.startOfImage,
          segmentOffset: 2,
          segmentSize: 0,
          segmentContents: new $window.Uint8Array(),
          dataOffset: 2,
          dataSize: 0,
          dataContents: new $window.Uint8Array()
        }],
        startOfScan: [{
          type: TYPES.startOfScan,
          segmentOffset: 6,
          segmentSize: 0,
          segmentContents: new $window.Uint8Array(),
          dataOffset: 6,
          dataSize: 1,
          dataContents: new $window.Uint8Array(buffer, 6, 1)
        }],
        endOfImage: [{
          type: TYPES.endOfImage,
          segmentOffset: 9,
          segmentSize: 0,
          segmentContents: new $window.Uint8Array(),
          dataOffset: 9,
          dataSize: 0,
          dataContents: new $window.Uint8Array()
        }]
      });
    });
  });

  describe('loadSegmentsFromFile', function() {
    var loadSegmentsFromBufferDeferred;
    var readAsArrayBufferResults;
    var loadSegmentsFromBufferResults;
    var loadSegmentsFromBufferError;
    var loadSegmentsFromFileResults;
    var loadSegmentsFromFileError;
    var originalFileReader;

    beforeEach(function() {
      originalFileReader = $window.FileReader;
      $window.FileReader = FileReaderMock;
    });

    afterEach(function() {
      $window.FileReader = originalFileReader;
      originalFileReader = null;
    });

    beforeEach(function() {
      loadSegmentsFromBufferDeferred = $q.defer();
      spyOn(AngularJpeg, 'loadSegmentsFromBuffer').and.returnValue(loadSegmentsFromBufferDeferred.promise);
      readAsArrayBufferResults = {};
      loadSegmentsFromBufferResults = {};
      loadSegmentsFromBufferError = {};
      loadSegmentsFromFileResults = null;
      loadSegmentsFromFileError = null;
    });

    it('should reject if no file passed', function() {
      AngularJpeg.loadSegmentsFromFile(null).catch(function(_loadSegmentsFromFileError_) {
        loadSegmentsFromFileError = _loadSegmentsFromFileError_;
      });
      $rootScope.$digest();
      expect(loadSegmentsFromFileError).toBe(ERRORS.noFile);
    });

    it('should pass the file to readAsArrayBuffer', function() {
      readAsArrayBuffer = jasmine.createSpy('readAsArrayBuffer');
      var file = new FileMock();
      AngularJpeg.loadSegmentsFromFile(file);
      expect(readAsArrayBuffer).toHaveBeenCalledWith(file);
    });

    describe('on file read error', function() {
      it('should reject the promise on readFromBuffer error', function() {
        readAsArrayBuffer = function() {
          fileReader.onerror();
        };
        AngularJpeg.loadSegmentsFromFile(new FileMock()).catch(function(_loadSegmentsFromFileError_) {
          loadSegmentsFromFileError = _loadSegmentsFromFileError_;
        });
        $rootScope.$digest();
        expect(loadSegmentsFromFileError).toBe(ERRORS.fileReadError);
      });
    });

    describe('on file read success', function() {
      beforeEach(function() {
        readAsArrayBuffer = function() {
          fileReader.onload({
            target: {
              result: readAsArrayBufferResults
            }
          });
        };
        AngularJpeg.loadSegmentsFromFile(new FileMock()).then(function(_loadSegmentsFromFileResults_) {
          loadSegmentsFromFileResults = _loadSegmentsFromFileResults_;
        }, function(_loadSegmentsFromFileError_) {
          loadSegmentsFromFileError = _loadSegmentsFromFileError_;
        });
      });

      it('should pass the results of readAsArrayBuffer to loadSegmentsFromBuffer', function() {
        expect(AngularJpeg.loadSegmentsFromBuffer).toHaveBeenCalledWith(readAsArrayBufferResults);
      });

      describe('and on validation error', function() {
        it('should reject with the error from loadSegmentsFromBuffer', function() {
          loadSegmentsFromBufferDeferred.reject(loadSegmentsFromBufferError);
          $rootScope.$digest();
          expect(loadSegmentsFromFileError).toBe(loadSegmentsFromBufferError);
        });
      });

      describe('and on loadSegmentsFromBufferSuccess', function() {
        it('should resolve with the results from loadSegmentsFromBuffer', function() {
          loadSegmentsFromBufferDeferred.resolve(loadSegmentsFromBufferResults);
          $rootScope.$digest();
          expect(loadSegmentsFromFileResults).toBe(loadSegmentsFromBufferResults);
        });
      });
    });
  });

  describe('_huffmanTreeFromTable', function() {
    it('should decode a trivial tree', function() {
      var table = {
        1: [1],
        2: [2, 3]
      };
      var tree = {
        0: 1,
        1: {
          0: 2,
          1: 3
        }
      };
      expect(AngularJpeg._huffmanTreeFromTable(table)).toEqual(tree);
    });

    it('should decode a complex tree', function() {
      var table = {
        2: [2, 3],
        4: [4, 5, 6],
        5: [7, 8],
        7: [9,10,11,12]
      };
      var tree = {
        0: {
          0: 2,
          1: 3
        },
        1: {
          0: {
            0: {
              0: 4,
              1: 5
            },
            1: {
              0: 6,
              1: {
                0: 7,
                1: 8
              }
            }
          },
          1: {
            0: {
              0: {
                0: {
                  0: {
                    0: {
                      0: 9,
                      1: 10
                    },
                    1: {
                      0: 11,
                      1: 12
                    }
                  }
                }
              }
            }
          }
        }
      };
      expect(AngularJpeg._huffmanTreeFromTable(table)).toEqual(tree);
    });
  });
});<|endoftext|>


<commit_before>/*---------------------------------------------------------
 * OpenERP base_gantt
 *---------------------------------------------------------*/

openerp.base_gantt = function (openerp) {
QWeb.add_template('/base_gantt/static/src/xml/base_gantt.xml');
openerp.base.views.add('gantt', 'openerp.base_gantt.GanttView');
openerp.base_gantt.GanttView = openerp.base.Controller.extend({

init: function(view_manager, session, element_id, dataset, view_id) {

        this._super(session, element_id);
        this.view_manager = view_manager;
        this.dataset = dataset;
        this.model = dataset.model;
        this.view_id = view_id;
        this.fields_views = {};
        this.widgets = {};
        this.widgets_counter = 0;
        this.fields = this.dataset.fields ? this.dataset.fields: {};
        this.ids = this.dataset.ids;
        this.name = "";
        this.date_start = "";
        this.date_delay = "";
        this.date_stop = "";
        this.color_field = "";
        this.day_lenth = 8;
        this.colors = [];
        this.color_values = [];
        this.calendar_fields = {};
        this.info_fields = [];
        this.domain = this.dataset._domain ? this.dataset._domain: [];
        this.context = {};
    },

    start: function() {
        this.rpc("/base_gantt/ganttview/load",
        {"model": this.model, "view_id": this.view_id}, this.on_loaded);
    },

    on_loaded: function(data) {

        var self = this;
        this.fields_view = data.fields_view;

        this.name = this.fields_view.name || this.fields_view.arch.attrs.string;
        this.view_id = this.fields_view.view_id;

        this.date_start = this.fields_view.arch.attrs.date_start;
        this.date_delay = this.fields_view.arch.attrs.date_delay;
        this.date_stop = this.fields_view.arch.attrs.date_stop;

        this.color_field = this.fields_view.arch.attrs.color;
        this.day_length = this.fields_view.arch.attrs.day_length || 8;
        this.colors = this.fields_view.arch.attrs.colors;

        this.text = this.fields_view.arch.children[0].children[0].attrs.name;
        this.parent = this.fields_view.arch.children[0].attrs.link;

        this.format = "yyyy-MM-dd";

        self.create_gantt();
        self.get_events();

        this.$element.html(QWeb.render("GanttView", {"view": this, "fields_view": this.fields_view}));

    },

    create_gantt: function() {

        ganttChartControl = new GanttChart(this.day_length);
        ganttChartControl.setImagePath("/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/");
        ganttChartControl.setEditable(true);
        ganttChartControl.showTreePanel(true);
        ganttChartControl.showContextMenu(true);
        ganttChartControl.showDescTask(true,'d,s-f');
        ganttChartControl.showDescProject(true,'n,d');

    },

    get_events: function() {

        var self = this;
        this.dataset.read_ids(this.dataset.ids, {}, function(result) {
            self.load_event(result);
        });

    },

    load_event: function(events) {

        var self = this;

        var result = events;
        var project = {};
        var project_smalldate = {};
        var proj_id = [];
        var proj_id_text = [];

        COLOR_PALETTE = ['#ccccff', '#cc99ff', '#75507b', '#3465a4', '#73d216', '#c17d11', '#edd400',
                 '#fcaf3e', '#ef2929', '#ff00c9', '#ad7fa8', '#729fcf', '#8ae234', '#e9b96e', '#fce94f',
                 '#ff8e00', '#ff0000', '#b0008c', '#9000ff', '#0078ff', '#00ff00', '#e6ff00', '#ffff00',
                 '#905000', '#9b0000', '#840067', '#510090', '#0000c9', '#009b00', '#9abe00', '#ffc900']

        //Smallest date of child is parent start date
        for (i in result){
            var res = result[i];

            if (res[this.date_start] != false){

                var parent_id =  res[this.parent][0] || res[this.parent];
                var parent_name = res[this.parent][1];
                var start_date = this.convert_str_date(res[this.date_start]);

                if (project_smalldate[parent_id] == undefined){
                    project_smalldate[parent_id] = start_date;
                    proj_id.push(parent_id);

                    if (parent_name != undefined){
                        proj_id_text.push(res[this.parent]);
                    }
                }
                else{
                    if (start_date < project_smalldate[parent_id]){
                        project_smalldate[parent_id] = start_date;
                    }
                }

            }
        }

        //get parent text
        if (parent_name == undefined){

            var ajax = {
                url: '/base/dataset/call',
                async: false
            };

            this.rpc(ajax, {
                model: this.dataset.model,
                method: "name_get",
                ids: proj_id,
                args: ""
            }, function(response) {
               proj_id_text = response.result;

            });
        }

        //create parents
        for (i in proj_id){

            var id = proj_id_text[i][0];
            var text = proj_id_text[i][1];

            project[id] = new GanttProjectInfo(id, text, project_smalldate[id]);
        }

        //create childs
        var k = 0;
        var color_box = {};
        for (i in result) {

            var res = result[i];
            if (res[this.date_start] != false){

                var parent_id = res[this.parent][0] || res[this.parent];
                var id = res['id'];
                var text = res[this.text];

                var start_date = this.convert_str_date(res[this.date_start]);

                var color = res[this.color_field][0] || res[this.color_field];
                if (color_box[color] == undefined){
                    color_box[color] = COLOR_PALETTE[k];
                    k = k + 1;
                }

                if (this.date_stop != undefined){
                    if (res[this.date_stop] != false){
                        var stop_date = this.convert_str_date(res[this.date_stop]);
                        var duration= self.hours_between(start_date, stop_date);
                    }
                    else{
                        var duration = 0;
                    }
                }
                else{
                    var duration = res[this.date_delay];
                }
                if (duration == false)
                    duration = 0
                task = new GanttTaskInfo(id, text, start_date, duration, 100, "", color_box[color]);
                project[parent_id].addTask(task);

            }
        }

        //Add parent
        for (i in proj_id){
            ganttChartControl.addProject(project[proj_id[i]]);
        }

        ganttChartControl.create("GanttDiv");
        ganttChartControl.attachEvent("onTaskStartDrag", function(task) {self.on_drag_start(task);});
        ganttChartControl.attachEvent("onTaskEndResize", function(task) {self.on_resize_drag_end(task, "resize");});
        ganttChartControl.attachEvent("onTaskEndDrag", function(task) {self.on_resize_drag_end(task, "drag");});
        ganttChartControl.attachEvent("onTaskDblClick", function(task) {self.open_popup(task);});

    },

    hours_between: function(date1, date2) {

        var ONE_DAY = 1000 * 60 * 60 * 24;
        var date1_ms = date1.getTime();
        var date2_ms = date2.getTime();
        var difference_ms = Math.abs(date1_ms - date2_ms);

        d = Math.round(difference_ms / ONE_DAY);
        h = Math.round((difference_ms % ONE_DAY)/(1000 * 60 * 60));

        return (d * this.day_length) + h;

    },

    open_popup : function(task) {
        var event_id = task.getId();
        if (event_id) {
            event_id = parseInt(event_id, 10);
            var dataset_event_index = jQuery.inArray(event_id, this.ids);
        } else  {
            var dataset_event_index = null;
        }
        this.dataset.index = dataset_event_index;
        var element_id = _.uniqueId("act_window_dialog");
        var dialog = jQuery('<div>',
                        {'id': element_id
                    }).dialog({
                        title: 'Gantt Chart',
                        modal: true,
                        minWidth: 800,
                        position: 'top'
                    });
        var event_form = new openerp.base.FormView(this.view_manager, this.session, element_id, this.dataset, false);
        event_form.start();
    },

    on_drag_start : function(task){
        st_date = task.getEST();
        if(st_date.getHours()){
            self.hh = st_date.getHours();
            self.mm = st_date.getMinutes();
        }
    },

    on_resize_drag_end : function(task, evt){

        var event_id = task.getId();
        var data = {};

        if (evt == "drag"){
            full_date = task.getEST().set({hour: self.hh, minute : self.mm, second:0});
            data[this.date_start] = this.convert_date_str(full_date);
        }
        if (this.date_stop != undefined){
            tm = (task.getDuration() % this.day_length);
            stp = task.getFinishDate().add(tm).hour();
            data[this.date_stop] = this.convert_date_str(stp);
        }else{
            data[this.date_delay] = task.getDuration();
        }
        this.dataset.write(event_id, data, function(result) {});

    },

    do_show: function () {
        this.$element.show();
    },

    do_hide: function () {
        this.$element.hide();
    },

    convert_str_date: function (str){
        if (str.length == 19){
            this.format = "yyyy-MM-dd HH:mm:ss";
            return openerp.base.parse_datetime(str);
        } else if (str.length == 10){
            this.format = "yyyy-MM-dd";
            return openerp.base.parse_date(str);
        } else if (str.length == 8){
            this.format = "HH:mm:ss";
            return openerp.base.parse_time(str);
        }
        throw "Unrecognized date/time format";
    },

    convert_date_str: function(full_date) {
        if (this.format == "yyyy-MM-dd HH:mm:ss"){
            return openerp.base.format_datetime(full_date);
        } else if (this.format == "yyyy-MM-dd"){
            return openerp.base.format_date(full_date);
        } else if (this.format == "HH:mm:ss"){
            return openerp.base.format_time(full_date);
        }
        throw "Unrecognized date/time format";
    },

    reload_gantt: function(domain) {
        var self = this;
        var ajax = {
                url: '/base/dataset/search_read',
                async: false
            };
            this.rpc(ajax, {
                model: this.dataset.model,
                domain: self.dataset.domain,
                context :self.dataset.context
            }, function(response) {
                ganttChartControl.clearAll();
                jQuery("#GanttDiv").children().remove();
                self.load_event(response);
            });
    },

    do_search: function (domains, contexts, groupbys) {

        var self = this;

        return this.rpc('/base/session/eval_domain_and_context', {
            domains: domains,
            contexts: contexts,
            group_by_seq: groupbys
        }, function (results) {
            self.dataset.context = results.context;
            self.dataset.domain = results.domain;
            return self.reload_gantt(self.dataset.domain);
        });
    }

});

// here you may tweak globals object, if any, and play with on_* or do_* callbacks on them

};
// vim:et fdc=0 fdl=0:
<commit_msg>[imp] gantt view improvements.<commit_after>/*---------------------------------------------------------
 * OpenERP base_gantt
 *---------------------------------------------------------*/

openerp.base_gantt = function (openerp) {
QWeb.add_template('/base_gantt/static/src/xml/base_gantt.xml');
openerp.base.views.add('gantt', 'openerp.base_gantt.GanttView');
openerp.base_gantt.GanttView = openerp.base.Controller.extend({

init: function(view_manager, session, element_id, dataset, view_id) {

        this._super(session, element_id);
        this.view_manager = view_manager;
        this.dataset = dataset;
        this.model = dataset.model;
        this.view_id = view_id;
        this.fields_views = {};
        this.widgets = {};
        this.widgets_counter = 0;
        this.fields = this.dataset.fields ? this.dataset.fields: {};
        this.ids = this.dataset.ids;
        this.name = "";
        this.date_start = "";
        this.date_delay = "";
        this.date_stop = "";
        this.color_field = "";
        this.day_lenth = 8;
        this.colors = [];
        this.color_values = [];
        this.calendar_fields = {};
        this.info_fields = [];
        this.domain = this.dataset._domain ? this.dataset._domain: [];
        this.context = {};
    },

    start: function() {
        this.rpc("/base_gantt/ganttview/load",
        {"model": this.model, "view_id": this.view_id}, this.on_loaded);
    },

    on_loaded: function(data) {

        var self = this;
        this.fields_view = data.fields_view;

        this.name =  this.fields_view.arch.attrs.string;
        this.view_id = this.fields_view.view_id;

        this.date_start = this.fields_view.arch.attrs.date_start;
        this.date_delay = this.fields_view.arch.attrs.date_delay;
        this.date_stop = this.fields_view.arch.attrs.date_stop;

        this.color_field = this.fields_view.arch.attrs.color;
        this.day_length = this.fields_view.arch.attrs.day_length || 8;
        this.colors = this.fields_view.arch.attrs.colors;

        this.text = this.fields_view.arch.children[0].children[0].attrs.name;
        this.parent = this.fields_view.arch.children[0].attrs.link;

        this.format = "yyyy-MM-dd";

        self.create_gantt();
        self.get_events();

        this.$element.html(QWeb.render("GanttView", {"view": this, "fields_view": this.fields_view}));

    },

    create_gantt: function() {

        ganttChartControl = new GanttChart(this.day_length);
        ganttChartControl.setImagePath("/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/");
        ganttChartControl.setEditable(true);
        ganttChartControl.showTreePanel(true);
        ganttChartControl.showContextMenu(true);
        ganttChartControl.showDescTask(true,'d,s-f');
        ganttChartControl.showDescProject(true,'n,d');

    },

    get_events: function() {

        var self = this;
        this.dataset.read_ids(this.dataset.ids, {}, function(result) {
            self.load_event(result);
        });

    },

    load_event: function(events) {

        var self = this;
        var result = events;
        var project = {};
        var smalldate = "";

        COLOR_PALETTE = ['#ccccff', '#cc99ff', '#75507b', '#3465a4', '#73d216', '#c17d11', '#edd400',
                 '#fcaf3e', '#ef2929', '#ff00c9', '#ad7fa8', '#729fcf', '#8ae234', '#e9b96e', '#fce94f',
                 '#ff8e00', '#ff0000', '#b0008c', '#9000ff', '#0078ff', '#00ff00', '#e6ff00', '#ffff00',
                 '#905000', '#9b0000', '#840067', '#510090', '#0000c9', '#009b00', '#9abe00', '#ffc900']

        if (result.length != 0){
            var show_event = [];
            for (i in result){
                var res = result[i];
                if (res[this.date_start] != false){

                    var start_date = this.convert_str_date(res[this.date_start]);
                    res[this.date_start] = start_date;
                    show_event.push(res);
                    if (smalldate == ""){
                        smalldate = start_date;
                    }
                    else{
                        if (start_date < smalldate){
                            smalldate = start_date;
                        }
                    }
                }
            }
        project = new GanttProjectInfo(1, self.name, smalldate);
        ganttChartControl.addProject(project);
        }

        //create child
        var k = 0;
        var color_box = {};
        for (i in show_event) {

            var res = show_event[i];

            var id = res['id'];
            var text = res[this.text];
            var start_date = res[this.date_start];

            var color = res[this.color_field][0] || res[this.color_field];
            if (color_box[color] == undefined){
                color_box[color] = COLOR_PALETTE[k];
                k = k + 1;
            }

            if (this.date_stop != undefined){
                if (res[this.date_stop] != false){
                    var stop_date = this.convert_str_date(res[this.date_stop]);
                    var duration= self.hours_between(start_date, stop_date);
                }
                else{
                    var duration = 0;
                }
            }
            else{
                var duration = res[this.date_delay];
            }
            if (duration == false)
                duration = 0
            task = new GanttTaskInfo(id, text, start_date, duration, 100, "", color_box[color]);
            project.addTask(task);
        }

        ganttChartControl.create("GanttDiv");
        ganttChartControl.attachEvent("onTaskStartDrag", function(task) {self.on_drag_start(task);});
        ganttChartControl.attachEvent("onTaskEndResize", function(task) {self.on_resize_drag_end(task, "resize");});
        ganttChartControl.attachEvent("onTaskEndDrag", function(task) {self.on_resize_drag_end(task, "drag");});
        ganttChartControl.attachEvent("onTaskDblClick", function(task) {self.open_popup(task);});

    },

    hours_between: function(date1, date2) {

        var ONE_DAY = 1000 * 60 * 60 * 24;
        var date1_ms = date1.getTime();
        var date2_ms = date2.getTime();
        var difference_ms = Math.abs(date1_ms - date2_ms);

        d = Math.round(difference_ms / ONE_DAY);
        h = Math.round((difference_ms % ONE_DAY)/(1000 * 60 * 60));

        return (d * this.day_length) + h;

    },

    open_popup : function(task) {
        var event_id = task.getId();
        if (event_id) {
            event_id = parseInt(event_id, 10);
            var dataset_event_index = jQuery.inArray(event_id, this.ids);
        } else  {
            var dataset_event_index = null;
        }
        this.dataset.index = dataset_event_index;
        var element_id = _.uniqueId("act_window_dialog");
        var dialog = jQuery('<div>',
                        {'id': element_id
                    }).dialog({
                        title: 'Gantt Chart',
                        modal: true,
                        minWidth: 800,
                        position: 'top'
                    });
        var event_form = new openerp.base.FormView(this.view_manager, this.session, element_id, this.dataset, false);
        event_form.start();
    },

    on_drag_start : function(task){
        st_date = task.getEST();
        if(st_date.getHours()){
            self.hh = st_date.getHours();
            self.mm = st_date.getMinutes();
        }
    },

    on_resize_drag_end : function(task, evt){

        var event_id = task.getId();
        var data = {};

        if (evt == "drag"){
            full_date = task.getEST().set({hour: self.hh, minute : self.mm, second:0});
            data[this.date_start] = this.convert_date_str(full_date);
        }
        if (this.date_stop != undefined){
            tm = (task.getDuration() % this.day_length);
            stp = task.getFinishDate().add(tm).hour();
            data[this.date_stop] = this.convert_date_str(stp);
        }else{
            data[this.date_delay] = task.getDuration();
        }
        this.dataset.write(event_id, data, function(result) {});

    },

    do_show: function () {
        this.$element.show();
    },

    do_hide: function () {
        this.$element.hide();
    },

    convert_str_date: function (str){
        if (str.length == 19){
            this.format = "yyyy-MM-dd HH:mm:ss";
            return openerp.base.parse_datetime(str);
        } else if (str.length == 10){
            this.format = "yyyy-MM-dd";
            return openerp.base.parse_date(str);
        } else if (str.length == 8){
            this.format = "HH:mm:ss";
            return openerp.base.parse_time(str);
        }
        throw "Unrecognized date/time format";
    },

    convert_date_str: function(full_date) {
        if (this.format == "yyyy-MM-dd HH:mm:ss"){
            return openerp.base.format_datetime(full_date);
        } else if (this.format == "yyyy-MM-dd"){
            return openerp.base.format_date(full_date);
        } else if (this.format == "HH:mm:ss"){
            return openerp.base.format_time(full_date);
        }
        throw "Unrecognized date/time format";
    },

    reload_gantt: function(domain) {
        var self = this;
        var ajax = {
                url: '/base/dataset/search_read',
                async: false
            };
            this.rpc(ajax, {
                model: this.dataset.model,
                domain: self.dataset.domain,
                context :self.dataset.context
            }, function(response) {
                ganttChartControl.clearAll();
                jQuery("#GanttDiv").children().remove();
                self.load_event(response);
            });
    },

    do_search: function (domains, contexts, groupbys) {

        var self = this;

        return this.rpc('/base/session/eval_domain_and_context', {
            domains: domains,
            contexts: contexts,
            group_by_seq: groupbys
        }, function (results) {
            self.dataset.context = results.context;
            self.dataset.domain = results.domain;
            return self.reload_gantt(self.dataset.domain);
        });
    }

});

// here you may tweak globals object, if any, and play with on_* or do_* callbacks on them

};
// vim:et fdc=0 fdl=0:
<|endoftext|>


<commit_before>
'use strict';

import React, {
    AppRegistry,
    Component,
    StyleSheet,
    Text,
    Image,
    View,
    TouchableHighlight,
    TouchableNativeFeedback,
    Platform,
} from 'react-native';

import GridView from 'react-native-grid-view';
import SimpleStore from 'react-native-simple-store';

import AnswerScreen from './answer-screen';

var TouchableElement = TouchableHighlight;
if (Platform.OS === 'android') {
    TouchableElement = TouchableNativeFeedback;
}

const questions = {
    '06f9bff5-c51e-4087-ab88-2497bb7516c3': {
        uuid: '06f9bff5-c51e-4087-ab88-2497bb7516c3',
        text: '.@FLOTUS @funnyordie @billyeichner: I actually own three tuxedos!',
        options: [
            {
                name: 'Big Bird',
                handle: 'BigBird',
                image: require('../assets/bigbird.png'),
                isAuthor: true,
            },
            {
                name: 'Jason Calacanis',
                handle: 'Jason',
                image: require('../assets/jason.jpg'),
            },
            {
                name: 'John Lilly',
                handle: 'johnolilly',
                image: require('../assets/johnolilly.jpeg'),
            },
            {
                name: 'Benedict Evans',
                handle: 'BenedictEvans',
                image: require('../assets/benedictevans.jpeg'),
            }
        ]
    },
    '06f9bff5-c51e-4087-ab88-djdjdjdjdj': {
        text: 'monkies',
        options: [
            {
                name: 'Benedict Evans',
                handle: 'BenedictEvans',
                image: require('../assets/benedictevans.jpeg'),
            },
            {
                name: 'Jason Calacanis',
                handle: 'Jason',
                image: require('../assets/jason.jpg'),
            },
            {
                name: 'Big Bird',
                handle: 'BigBird',
                image: require('../assets/bigbird.png'),
                isAuthor: true,
            },
            {
                name: 'John Lilly',
                handle: 'johnolilly',
                image: require('../assets/johnolilly.jpeg'),
            },
        ]
    }
};

SimpleStore.save('questions', questions);

class QuestionScreen extends Component {
    constructor(props) {
        super(props);
        this.state = { question: null };
    }

    componentWillMount() {
        SimpleStore.get('questions').then((questions) => {
            for (var id in questions) {
                var question = questions[id];

                if (!question.answered) {
                    this.setState({ question: question });
                    break;
                }
            }
        });
    }

    render() {
        if (!this.state.question) {
            return (
                <View>
                </View>
            );
        }

        return (
            <View style={styles.gameScreen}>
                <Question question={this.state.question} />
                <Answers question={this.state.question} navigator={this.props.navigator}/>
            </View>
        )
    }
}

class Question extends Component {
    render() {
        return (
            <View style={styles.questionBox}>
                <View>
                    <Image
                        style={styles.profilePic}
                        source={require('../assets/egg-profile.jpeg')}
                    />
                </View>

                <View style={styles.questionContent}>
                    <Text style={styles.headText}>
                        ???
                    </Text>
                    <Text style={styles.bodyText}>
                        {this.props.question.text}
                    </Text>
                </View>
            </View>
        )
    }
}

class Answers extends Component {
    render() {
        return (
            <View style={styles.answerBox}>

                <GridView
                    items={this.props.question.options}
                    itemsPerRow={2}
                    renderItem={this.renderOption.bind(this)}
                />

            </View>
        )
    }

    renderOption(option) {
        return (
            <Option
                option={option}
                question={this.props.question}
                navigator={this.props.navigator}
                key={option.handle}
            />
        );
    }
}

class Option extends Component {
    render() {
        return (
            <TouchableElement onPress={this.onSelectOption.bind(this)}>
                <View style={styles.answerOption}>
                        <Image
                            style={styles.profilePic}
                            source={this.props.option.image}
                        />
                    <View style={styles.optionContent}>
                        <Text style={styles.optionName}>
                            {this.props.option.name}
                        </Text>
                        <Text style={styles.optionHandle}>
                            @{this.props.option.handle}
                        </Text>
                    </View>
                </View>
            </TouchableElement>
        );
    }

    onSelectOption() {
        this.props.navigator.push({
            name: 'AnswerScreen',
            component: (props) => {
                return new AnswerScreen(props, this.props.question, this.props.option);
            }
        });
    }
}

const styles = StyleSheet.create({
    gameScreen: {
        flex: 1,
    },
    questionBox: {
        flex: 1,
        flexDirection: 'row',
        alignItems: 'center',
        padding: 20,
    },
    questionContent: {
        flex: 1,
        padding: 8,
        flexDirection: 'column',
    },
    answerBox: {
        flex: 2,
        // backgroundColor:'#ebeef0',
        flexDirection: 'column',
    },
    answerRow: {
        flex:1,
        flexDirection: 'row',
        alignItems: 'center',
        justifyContent: 'center',
    },
    answerOption: {
        width: 160,
        height: 160,
        justifyContent: 'center',
        alignItems: 'center',
        flexDirection: 'column',
    },
    optionContent: {
        padding: 8,
        flexDirection: 'column',
        alignItems: 'center',
    },
    headText: {
        fontSize: 20,
        textAlign: 'left',
        margin: 10,
    },
    bodyText: {
        fontSize: 16,
        textAlign: 'left',
    },
    optionName: {
        fontSize: 16,
        textAlign: 'center',
    },
    optionHandle: {
        fontSize: 12,
        textAlign: 'center',
    },
    profilePic: {
        width: 64,
        height: 64,
    },
});

export default QuestionScreen;
<commit_msg>pass callback through to button, keep logic in question screen<commit_after>
'use strict';

import React, {
    AppRegistry,
    Component,
    StyleSheet,
    Text,
    Image,
    View,
    TouchableHighlight,
    TouchableNativeFeedback,
    Platform,
} from 'react-native';

import GridView from 'react-native-grid-view';
import SimpleStore from 'react-native-simple-store';

import AnswerScreen from './answer-screen';

var TouchableElement = TouchableHighlight;
if (Platform.OS === 'android') {
    TouchableElement = TouchableNativeFeedback;
}

const questions = {
    '06f9bff5-c51e-4087-ab88-2497bb7516c3': {
        uuid: '06f9bff5-c51e-4087-ab88-2497bb7516c3',
        text: '.@FLOTUS @funnyordie @billyeichner: I actually own three tuxedos!',
        options: [
            {
                name: 'Big Bird',
                handle: 'BigBird',
                image: require('../assets/bigbird.png'),
                isAuthor: true,
            },
            {
                name: 'Jason Calacanis',
                handle: 'Jason',
                image: require('../assets/jason.jpg'),
            },
            {
                name: 'John Lilly',
                handle: 'johnolilly',
                image: require('../assets/johnolilly.jpeg'),
            },
            {
                name: 'Benedict Evans',
                handle: 'BenedictEvans',
                image: require('../assets/benedictevans.jpeg'),
            }
        ]
    },
    '06f9bff5-c51e-4087-ab88-djdjdjdjdj': {
        text: 'monkies',
        options: [
            {
                name: 'Benedict Evans',
                handle: 'BenedictEvans',
                image: require('../assets/benedictevans.jpeg'),
            },
            {
                name: 'Jason Calacanis',
                handle: 'Jason',
                image: require('../assets/jason.jpg'),
            },
            {
                name: 'Big Bird',
                handle: 'BigBird',
                image: require('../assets/bigbird.png'),
                isAuthor: true,
            },
            {
                name: 'John Lilly',
                handle: 'johnolilly',
                image: require('../assets/johnolilly.jpeg'),
            },
        ]
    }
};

SimpleStore.save('questions', questions);

class QuestionScreen extends Component {
    constructor(props) {
        super(props);
        this.state = { question: null };
    }

    componentWillMount() {
        SimpleStore.get('questions').then((questions) => {
            for (var id in questions) {
                var question = questions[id];

                if (!question.answered) {
                    this.setState({ question: question });
                    break;
                }
            }
        });
    }

    render() {
        if (!this.state.question) {
            return (
                <View>
                </View>
            );
        }

        return (
            <View style={styles.gameScreen}>
                <Question question={this.state.question} />
                <Answers
                    question={this.state.question}
                    navigator={this.props.navigator}
                    selectCallback={this.onSelectedAnswer.bind(this)}/>
            </View>
        )
    }

    onSelectedAnswer(selectedOption) {
        this.props.navigator.push({
            name: 'AnswerScreen',
            component: (props) => {
                return new AnswerScreen(props, this.props.question, selectedOption);
            }
        });
    }
}

class Question extends Component {
    render() {
        return (
            <View style={styles.questionBox}>
                <View>
                    <Image
                        style={styles.profilePic}
                        source={require('../assets/egg-profile.jpeg')}
                    />
                </View>

                <View style={styles.questionContent}>
                    <Text style={styles.headText}>
                        ???
                    </Text>
                    <Text style={styles.bodyText}>
                        {this.props.question.text}
                    </Text>
                </View>
            </View>
        )
    }
}

class Answers extends Component {
    render() {
        return (
            <View style={styles.answerBox}>

                <GridView
                    items={this.props.question.options}
                    itemsPerRow={2}
                    renderItem={this.renderOption.bind(this)}
                />

            </View>
        )
    }

    renderOption(option) {
        return (
            <Option
                option={option}
                question={this.props.question}
                navigator={this.props.navigator}
                selectCallback={this.props.selectCallback}
                key={option.handle}
            />
        );
    }
}

class Option extends Component {
    render() {
        return (
            <TouchableElement onPress={() => this.props.selectCallback(this.props.option)}>
                <View style={styles.answerOption}>
                        <Image
                            style={styles.profilePic}
                            source={this.props.option.image}
                        />
                    <View style={styles.optionContent}>
                        <Text style={styles.optionName}>
                            {this.props.option.name}
                        </Text>
                        <Text style={styles.optionHandle}>
                            @{this.props.option.handle}
                        </Text>
                    </View>
                </View>
            </TouchableElement>
        );
    }
}

const styles = StyleSheet.create({
    gameScreen: {
        flex: 1,
    },
    questionBox: {
        flex: 1,
        flexDirection: 'row',
        alignItems: 'center',
        padding: 20,
    },
    questionContent: {
        flex: 1,
        padding: 8,
        flexDirection: 'column',
    },
    answerBox: {
        flex: 2,
        // backgroundColor:'#ebeef0',
        flexDirection: 'column',
    },
    answerRow: {
        flex:1,
        flexDirection: 'row',
        alignItems: 'center',
        justifyContent: 'center',
    },
    answerOption: {
        width: 160,
        height: 160,
        justifyContent: 'center',
        alignItems: 'center',
        flexDirection: 'column',
    },
    optionContent: {
        padding: 8,
        flexDirection: 'column',
        alignItems: 'center',
    },
    headText: {
        fontSize: 20,
        textAlign: 'left',
        margin: 10,
    },
    bodyText: {
        fontSize: 16,
        textAlign: 'left',
    },
    optionName: {
        fontSize: 16,
        textAlign: 'center',
    },
    optionHandle: {
        fontSize: 12,
        textAlign: 'center',
    },
    profilePic: {
        width: 64,
        height: 64,
    },
});

export default QuestionScreen;
<|endoftext|>


<commit_before>"use strict";

import fs from "fs";
import path from "path";

import chai, { expect } from "chai";
import del from "del";
import jwt from "jsonwebtoken";
import restify from "restify";
import sinon from "sinon";
import sinonChai from "sinon-chai";
import stream from "stream";
import supertest from "supertest";

chai.use(sinonChai);

import Application from "../src/application";
import Router from "../src/router";
import { connection } from "./fixtures";

describe("Application", function () {
  let application;

  describe("#map", function () {
    this.timeout(5000);

    beforeEach(function () {
      application = new Application({
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        }
      });
    });

    it("gets called with a Router instance", function (done) {
      application.map(function () {
        expect(this).to.have.property("resource");
        done();
      });
    });

    it("maps routes to their controller", function (done) {
      application.map(function () {
        this.resource("foo");
      });

      supertest(application.getApp())
        .get("/foos")
        .expect(200)
        .end(done);
    });
  });

  describe("#start", function () {
    this.timeout(5000);

    const mockRestify = restify.createServer();

    beforeEach(function () {
      sinon.spy(mockRestify, "listen");
      application = new Application({
        app: mockRestify,
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: { connection, models: { dir: path.resolve(__dirname, "fixtures/models") }}
      });
    });

    afterEach(function () {
      mockRestify.listen.restore();
    });

    it("starts the application", function () {
      return application.start().then(() => {
        expect(mockRestify.listen).to.have.been.calledWith(5000);
      });
    });
  });

  describe("authentication", function () {
    this.timeout(5000);

    beforeEach(function (done) {
      application = new Application({
        authentication: {
          unauthenticated: [/\/resetPassword/]
        },
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        }
      });

      application.map(function () {
        this.resource("user");
        this.route("/users/resetPassword", { using: "user:resetPassword", method: "post" });

        done();
      });
    });

    it("authenticates users via jwt", function (done) {
      const token = jwt.sign({ foo: "bar" }, "secret");

      supertest(application.getApp())
        .get("/users")
        .set("Authorization", `Bearer ${token}`)
        .expect(200)
        .end(done);
    });

    it("skips 'unauthenticated' routes", function (done) {
      supertest(application.getApp())
        .post("/users/resetPassword")
        .expect(200)
        .end(done);
    });

    it("disables auth if not set by the user", function (done) {
      application = new Application({
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        }
      });
      application.map(function () {
        this.resource("user");
      });

      supertest(application.getApp())
        .get("/users")
        .expect(200)
        .end(done);
    });

    it("can be enabled by setting to true", function (done) {
      application = new Application({
        authentication: true,
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        }
      });
      application.map(function () {
        this.resource("user");
      });
      supertest(application.getApp())
        .get("/users")
        .expect(401)
        .end(done);
    });
  });

  describe.skip("logging", function () {
    let loggingDir, messages, writable;

    beforeEach(function () {
      loggingDir = path.resolve(__dirname, "fixtures/custom-logs");
      messages = [];
      stream.write = message => {
        messages.push(JSON.parse(message));
      };
    });

    afterEach(function () {
      return del([`${loggingDir}/**/*.log`, `!${loggingDir}`]);
    });

    it("allows for a custom directory", function (done) {
      application = new Application({
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        },
        logging: { dir: loggingDir }
      });

      application.map(function () {
        this.resource("user");
      });

      supertest(application.getApp())
        .get("/users")
        .end(function (err, res) {
          if (err) { return done(err); }

          fs.readdir(loggingDir, (err2, files) => {
            if (err2) { return done(err2); }

            const file = files.filter(f => f.match(/\.log/));
            let log;

            expect(file).to.be.ok;
            expect(file).to.have.length.gt(0);

            const fileData = fs.readFileSync(path.resolve(loggingDir, file[0]));
            const lines = fileData
              .toString()
              .split("\n")
              .filter(line => line.length);
            const line = lines[lines.length - 1];

            try {
              log = JSON.parse(line);
            } catch (err) {
              console.log(fileData.toString().split("\n"));
              throw err;
            }

            expect(log.res.statusCode).to.eql(200);

            done();
          });
        });
    });

    it("allows for custom request serializer", function (done) {
      application = new Application({
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        },
        logging: {
          serializers: {
            req(req) {
              return { url: req.url };
            }
          }
        }
      });

      application.logger.addStream({
        type: "stream",
        stream
      });
      application.map(function () {
        this.resource("user");
      });
      supertest(application.getApp())
        .get("/users")
        .end(function (err, res) {
          if (err) { return done(err); }

          expect(messages[0].req.url).to.eql("/users");
          expect(messages[0].req).to.not.have.any.keys("httpVersion", "method");
          done();
        });
    });

    it("allows for custom response serializer", function (done) {
      application = new Application({
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        },
        logging: {
          serializers: {
            res(res) {
              return { statusCode: res.statusCode };
            }
          }
        }
      });

      application.logger.addStream({
        type: "stream",
        stream
      });
      application.map(function () {
        this.resource("user");
      });
      supertest(application.getApp())
        .get("/users")
        .end(function (err, res) {
          if (err) { return done(err); }

          expect(messages[0].res.statusCode).to.eql(200);
          expect(messages[0].req).to.not.have.any.keys("headers");
          done();
        });
    });
  });
});
<commit_msg>test(application): bump timeout<commit_after>"use strict";

import fs from "fs";
import path from "path";

import chai, { expect } from "chai";
import del from "del";
import jwt from "jsonwebtoken";
import restify from "restify";
import sinon from "sinon";
import sinonChai from "sinon-chai";
import stream from "stream";
import supertest from "supertest";

chai.use(sinonChai);

import Application from "../src/application";
import Router from "../src/router";
import { connection } from "./fixtures";

describe("Application", function () {
  let application;

  describe("#map", function () {
    this.timeout(5000);

    beforeEach(function () {
      application = new Application({
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        }
      });
    });

    it("gets called with a Router instance", function (done) {
      application.map(function () {
        expect(this).to.have.property("resource");
        done();
      });
    });

    it("maps routes to their controller", function (done) {
      application.map(function () {
        this.resource("foo");
      });

      supertest(application.getApp())
        .get("/foos")
        .expect(200)
        .end(done);
    });
  });

  describe("#start", function () {
    this.timeout(5000);

    const mockRestify = restify.createServer();

    beforeEach(function () {
      sinon.spy(mockRestify, "listen");
      application = new Application({
        app: mockRestify,
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: { connection, models: { dir: path.resolve(__dirname, "fixtures/models") }}
      });
    });

    afterEach(function () {
      mockRestify.listen.restore();
    });

    it("starts the application", function () {
      return application.start().then(() => {
        expect(mockRestify.listen).to.have.been.calledWith(3000);
      });
    });
  });

  describe("authentication", function () {
    this.timeout(5000);

    beforeEach(function (done) {
      application = new Application({
        authentication: {
          unauthenticated: [/\/resetPassword/]
        },
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        }
      });

      application.map(function () {
        this.resource("user");
        this.route("/users/resetPassword", { using: "user:resetPassword", method: "post" });

        done();
      });
    });

    it("authenticates users via jwt", function (done) {
      const token = jwt.sign({ foo: "bar" }, "secret");

      supertest(application.getApp())
        .get("/users")
        .set("Authorization", `Bearer ${token}`)
        .expect(200)
        .end(done);
    });

    it("skips 'unauthenticated' routes", function (done) {
      supertest(application.getApp())
        .post("/users/resetPassword")
        .expect(200)
        .end(done);
    });

    it("disables auth if not set by the user", function (done) {
      application = new Application({
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        }
      });
      application.map(function () {
        this.resource("user");
      });

      supertest(application.getApp())
        .get("/users")
        .expect(200)
        .end(done);
    });

    it("can be enabled by setting to true", function (done) {
      application = new Application({
        authentication: true,
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        }
      });
      application.map(function () {
        this.resource("user");
      });
      supertest(application.getApp())
        .get("/users")
        .expect(401)
        .end(done);
    });
  });

  describe.skip("logging", function () {
    let loggingDir, messages, writable;

    beforeEach(function () {
      loggingDir = path.resolve(__dirname, "fixtures/custom-logs");
      messages = [];
      stream.write = message => {
        messages.push(JSON.parse(message));
      };
    });

    afterEach(function () {
      return del([`${loggingDir}/**/*.log`, `!${loggingDir}`]);
    });

    it("allows for a custom directory", function (done) {
      application = new Application({
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        },
        logging: { dir: loggingDir }
      });

      application.map(function () {
        this.resource("user");
      });

      supertest(application.getApp())
        .get("/users")
        .end(function (err, res) {
          if (err) { return done(err); }

          fs.readdir(loggingDir, (err2, files) => {
            if (err2) { return done(err2); }

            const file = files.filter(f => f.match(/\.log/));
            let log;

            expect(file).to.be.ok;
            expect(file).to.have.length.gt(0);

            const fileData = fs.readFileSync(path.resolve(loggingDir, file[0]));
            const lines = fileData
              .toString()
              .split("\n")
              .filter(line => line.length);
            const line = lines[lines.length - 1];

            try {
              log = JSON.parse(line);
            } catch (err) {
              console.log(fileData.toString().split("\n"));
              throw err;
            }

            expect(log.res.statusCode).to.eql(200);

            done();
          });
        });
    });

    it("allows for custom request serializer", function (done) {
      application = new Application({
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        },
        logging: {
          serializers: {
            req(req) {
              return { url: req.url };
            }
          }
        }
      });

      application.logger.addStream({
        type: "stream",
        stream
      });
      application.map(function () {
        this.resource("user");
      });
      supertest(application.getApp())
        .get("/users")
        .end(function (err, res) {
          if (err) { return done(err); }

          expect(messages[0].req.url).to.eql("/users");
          expect(messages[0].req).to.not.have.any.keys("httpVersion", "method");
          done();
        });
    });

    it("allows for custom response serializer", function (done) {
      application = new Application({
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        },
        logging: {
          serializers: {
            res(res) {
              return { statusCode: res.statusCode };
            }
          }
        }
      });

      application.logger.addStream({
        type: "stream",
        stream
      });
      application.map(function () {
        this.resource("user");
      });
      supertest(application.getApp())
        .get("/users")
        .end(function (err, res) {
          if (err) { return done(err); }

          expect(messages[0].res.statusCode).to.eql(200);
          expect(messages[0].req).to.not.have.any.keys("headers");
          done();
        });
    });
  });
});
<|endoftext|>


<commit_before>// Plumbing code tp launch a constructor form for a DE value and return it back to the main form

function goodValue(element) {
    var indicator = $(element).next(".validationindicator");
    if (indicator.hasClass("validity invalid")) {
        indicator.removeClass('validity invalid');
    }
    indicator.addClass("validity valid");
}

function badValue(element) {
    var indicator = $(element).next(".validationindicator");
    if (indicator.hasClass("validity valid")) {
        indicator.removeClass('validity valid');
    }
    indicator.addClass("validity invalid");
}

function generic_constructor(element, constructorName, constructorFormUrl) {
   // element here is the constructor button next to the input field - we have
   // to use navigate via jquery traversal as the field may be in a multisection and have been cloned
   function updateValue(value) {
       var textField = $(element).closest("td").find("input[type='text']");
       textField.val(value);  // we assume that the DE is text input field
       textField.trigger("keyup");
   }
   // NB IE 8 doesn't like spaces in window name
   var w = window.open(constructorFormUrl, constructorName.replace(/ /g, ''), "location=no,width=800,height=600,scrollbars=yes,top=100,left=700,resizable = no");
   // NB this function is/must be called on the child form to allow the constructed data value to be passed back to the form
   w.updateParentForm = updateValue;

}

function generic_validate(element, rpcEndPoint, rpcCommand) {
    // element is the text box
    var value = $(element).val();
    var csrfToken = $("input[name='csrfmiddlewaretoken']").val(); // this will/must appear on our django form

    var rpc = new RPC.RPC(rpcEndPoint, csrfToken);
    rpc.send(rpcCommand, [value], function (response) {
        var isValid = response.result;
        if (isValid) {
            goodValue(element);
        }
        else {
            badValue(element);
        }
    });
}<commit_msg>RDR-914 generic constructor form code calls call back which propulates the main form - this code was assuming that the input field was inside a table cell which is no longer true after redesign of the multisection code (now inside a div element)<commit_after>// Plumbing code tp launch a constructor form for a DE value and return it back to the main form

function goodValue(element) {
    var indicator = $(element).next(".validationindicator");
    if (indicator.hasClass("validity invalid")) {
        indicator.removeClass('validity invalid');
    }
    indicator.addClass("validity valid");
}

function badValue(element) {
    var indicator = $(element).next(".validationindicator");
    if (indicator.hasClass("validity valid")) {
        indicator.removeClass('validity valid');
    }
    indicator.addClass("validity invalid");
}

function generic_constructor(element, constructorName, constructorFormUrl) {
   // element here is the constructor button next to the input field - we have
   // to use navigate via jquery traversal as the field may be in a multisection and have been cloned

   function updateValue(value) {
       var textField = $(element).closest("div").find("input[type='text']");
       textField.val(value);  // we assume that the DE is text input field
       textField.trigger("keyup");
   }
   // NB IE 8 doesn't like spaces in window name
   var w = window.open(constructorFormUrl, constructorName.replace(/ /g, ''), "location=no,width=800,height=600,scrollbars=yes,top=100,left=700,resizable = no");
   // NB this function is/must be called on the child form to allow the constructed data value to be passed back to the form
   w.updateParentForm = updateValue;

}

function generic_validate(element, rpcEndPoint, rpcCommand) {
    // element is the text box
    var value = $(element).val();
    var csrfToken = $("input[name='csrfmiddlewaretoken']").val(); // this will/must appear on our django form

    var rpc = new RPC.RPC(rpcEndPoint, csrfToken);
    rpc.send(rpcCommand, [value], function (response) {
        var isValid = response.result;
        if (isValid) {
            goodValue(element);
        }
        else {
            badValue(element);
        }
    });
}<|endoftext|>