<commit_before>/*!
 * Copyright 2012 The Toolkitchen Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file.
 */

/**
 * This module contains the handlers for native platform events.
 * From here, the dispatcher is called to create unified pointer events.
 * Included are touch events (v1), mouse events, and MSPointerEvents.
 */
(function(scope) {
  var dispatcher = scope.dispatcher;
  var installer = scope.installer;
  var pointermap = dispatcher.pointermap;
  var touchMap = Array.prototype.map.call.bind(Array.prototype.map);
  // handler block for native touch events
  var touchEvents = {
    events: [
      'touchstart',
      'touchmove',
      'touchend',
      'touchcancel'
    ],
    POINTER_TYPE: 'touch',
    firstTouch: null,
    isPrimaryTouch: function(inTouch) {
      return this.firstTouch === inTouch.identifier;
    },
    setPrimaryTouch: function(inTouch) {
      if (this.firstTouch === null) {
        this.firstTouch = inTouch.identifier;
      }
    },
    removePrimaryTouch: function(inTouch) {
      if (this.isPrimaryTouch(inTouch)) {
        this.firstTouch = null;
      }
    },
    touchToPointer: function(inTouch) {
      var e = dispatcher.cloneEvent(inTouch);
      // Spec specifies that pointerId 1 is reserved for Mouse.
      // Touch identifiers can start at 0.
      // Add 2 to the touch identifier for compatibility.
      e.pointerId = inTouch.identifier + 2;
      e.target = this.findTarget(e);
      e.bubbles = true;
      e.cancelable = true;
      e.button = 0;
      e.buttons = 1;
      e.isPrimary = this.isPrimaryTouch(inTouch);
      e.pointerType = this.POINTER_TYPE;
      return e;
    },
    processTouches: function(inEvent, inFunction) {
      var tl = inEvent.changedTouches;
      var pointers = touchMap(tl, this.touchToPointer, this);
      pointers.forEach(inFunction, this);
    },
    findTarget: function(inEvent) {
      var x = inEvent.clientX, y = inEvent.clientY;
      // find target from light dom
      var t = document.elementFromPoint(x, y);
      var st, sr, os;
      // is element a shadow host?
      sr = t && (t.webkitShadowRoot || t.shadowRoot);
      while (sr) {
        // find the the element inside the shadow root
        st = sr.elementFromPoint(x, y);
        if (!st) {
          // check for older shadows
          os = sr.querySelector('shadow');
          // check the older shadow if available
          sr = os ? os.olderShadowRoot : null;
        } else {
          // shadowed element is the target
          return st;
        }
      }
      // light dom element is the target
      return t;
    },
    touchstart: function(inEvent) {
      this.setPrimaryTouch(inEvent.changedTouches[0]);
      this.processTouches(inEvent, this.overDown);
    },
    overDown: function(inPointer) {
      var p = pointermap.set(inPointer.pointerId, {
        target: inPointer.target,
        out: inPointer,
        outTarget: inPointer.target
      });
      dispatcher.over(inPointer);
      dispatcher.down(inPointer);
    },
    touchmove: function(inEvent) {
      // must preventDefault first touchmove or document will scroll otherwise
      // Per Touch event spec section 5.6
      // http://www.w3.org/TR/touch-events/#the-touchmove-event
      inEvent.preventDefault();
      this.processTouches(inEvent, this.moveOverOut);
    },
    moveOverOut: function(inPointer) {
      var event = inPointer;
      var pointer = pointermap.get(event.pointerId);
      var outEvent = pointer.out;
      var outTarget = pointer.outTarget;
      dispatcher.move(event);
      if (outEvent && outTarget !== event.target) {
        outEvent.relatedTarget = event.target;
        event.relatedTarget = outTarget;
        // recover from retargeting by shadow
        outEvent.target = outTarget;
        dispatcher.out(outEvent);
        dispatcher.over(event);
      }
      pointer.out = event;
      pointer.outTarget = event.target;
    },
    touchend: function(inEvent) {
      this.dedupSynthMouse(inEvent);
      this.processTouches(inEvent, this.upOut);
    },
    upOut: function(inPointer) {
      dispatcher.up(inPointer);
      dispatcher.out(inPointer);
      this.cleanUpPointer(inPointer);
    },
    touchcancel: function(inEvent) {
      this.processTouches(inEvent, this.cancelOut);
    },
    cancelOut: function(inPointer) {
      dispatcher.cancel(inPointer);
      dispatcher.out(inPointer);
      this.cleanUpPointer(inPointer);
    },
    cleanUpPointer: function(inPointer) {
      pointermap.delete(inPointer.pointerId);
      this.removePrimaryTouch(inPointer);
    },
    // prevent synth mouse events from creating pointer events
    dedupSynthMouse: function(inEvent) {
      var lts = mouseEvents.lastTouches;
      var t = inEvent.changedTouches[0];
      // only the primary finger will synth mouse events
      if (this.isPrimaryTouch(t)) {
        // remember x/y of last touch
        var lt = {x: t.clientX, y: t.clientY};
        lts.push(lt);
        var fn = (function(lts, lt){
          lts.splice(lts.indexOf(lt), 1);
        }).bind(null, lts, lt);
        setTimeout(fn, 1000);
      }
    }
  };

  // handler block for native mouse events
  var mouseEvents = {
    // Mouse is required to have a pointerId of 1
    POINTER_ID: 1,
    POINTER_TYPE: 'mouse',
    events: [
      'mousedown',
      'mousemove',
      'mouseup',
      'mouseover',
      'mouseout'
    ],
    global: [
      'mousedown',
      'mouseup',
      'mouseover',
      'mouseout'
    ],
    lastTouches: [],
    isTouchEmulated: function(inEvent) {
      var lts = this.lastTouches;
      var x = inEvent.clientX, y = inEvent.clientY;
      for (var i = 0, l = lts.length, t; i < l && (t = lts[i]); i++) {
        // simulated mouse events are on the same x/y as the touchend
        if (t.x == x && t.y == y) {
          return true;
        }
      }
    },
    prepareEvent: function(inEvent) {
      var e = dispatcher.cloneEvent(inEvent);
      e.pointerId = this.POINTER_ID;
      e.isPrimary = true;
      e.pointerType = this.POINTER_TYPE;
      return e;
    },
    mousedown: function(inEvent) {
      if (this.isTouchEmulated(inEvent)) {
        return;
      }
      if (!pointermap.has(this.POINTER_ID)) {
        var e = this.prepareEvent(inEvent);
        var p = pointermap.set(this.POINTER_ID, inEvent);
        dispatcher.down(e);
        dispatcher.listen(this.global, document);
      }
    },
    mousemove: function(inEvent) {
      if (!this.isTouchEmulated(inEvent)) {
        var e = this.prepareEvent(inEvent);
        dispatcher.move(e);
      }
    },
    mouseup: function(inEvent) {
      if (this.isTouchEmulated(inEvent)) {
        return;
      }
      var p = pointermap.get(this.POINTER_ID);
      if (p && p.button === inEvent.button) {
        var e = this.prepareEvent(inEvent);
        dispatcher.up(e);
        pointermap.delete(this.POINTER_ID);
        dispatcher.unlisten(this.global, document);
      }
    },
    mouseover: function(inEvent) {
      if (this.isTouchEmulated(inEvent)) {
        return;
      }
      var e = this.prepareEvent(inEvent);
      dispatcher.over(e);
    },
    mouseout: function(inEvent) {
      if (this.isTouchEmulated(inEvent)) {
        return;
      }
      var e = this.prepareEvent(inEvent);
      dispatcher.out(e);
    }
  };

  var msEvents = {
    events: [
      'MSPointerDown',
      'MSPointerMove',
      'MSPointerUp',
      'MSPointerOut',
      'MSPointerOver',
      'MSPointerCancel'
    ],
    POINTER_TYPES: [
      'NOT USED',
      'unavailable',
      'touch',
      'pen',
      'mouse'
    ],
    prepareEvent: function(inEvent) {
      var e = dispatcher.cloneEvent(inEvent);
      e.pointerType = this.POINTER_TYPES[inEvent.pointerType];
      return e;
    },
    MSPointerDown: function(inEvent) {
      var e = this.prepareEvent(inEvent);
      dispatcher.down(e);
    },
    MSPointerMove: function(inEvent) {
      var e = this.prepareEvent(inEvent);
      dispatcher.move(e);
    },
    MSPointerUp: function(inEvent) {
      var e = this.prepareEvent(inEvent);
      dispatcher.up(e);
    },
    MSPointerOut: function(inEvent) {
      var e = this.prepareEvent(inEvent);
      dispatcher.out(e);
    },
    MSPointerOver: function(inEvent) {
      var e = this.prepareEvent(inEvent);
      dispatcher.over(e);
    },
    MSPointerCancel: function(inEvent) {
      var e = this.prepareEvent(inEvent);
      dispatcher.cancel(e);
    }
  };

  // only activate if this platform does not have pointer events
  if (window.navigator.pointerEnabled === undefined) {

    if (window.navigator.msPointerEnabled) {
      var tp = window.navigator.msMaxTouchPoints;
      if (tp !== undefined) {
        Object.defineProperty(window.navigator, 'maxTouchPoints', {
          value: tp,
          enumerable: true
        });
      }
      dispatcher.registerSource('ms', msEvents);
      dispatcher.registerTarget(document);
    } else {
      dispatcher.registerSource('mouse', mouseEvents);
      if ('ontouchstart' in window) {
        dispatcher.registerSource('touch', touchEvents);
      }
      installer.enableOnSubtree(document);
      // mouse move events must be on at all times
      dispatcher.listen(['mousemove'], document);
    }

    Object.defineProperty(window.navigator, 'pointerEnabled', {value: true, enumerable: true});
  }
})(window.__PointerEventShim__);
<commit_msg>clean up dedup timeout<commit_after>/*!
 * Copyright 2012 The Toolkitchen Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file.
 */

/**
 * This module contains the handlers for native platform events.
 * From here, the dispatcher is called to create unified pointer events.
 * Included are touch events (v1), mouse events, and MSPointerEvents.
 */
(function(scope) {
  var dispatcher = scope.dispatcher;
  var installer = scope.installer;
  var pointermap = dispatcher.pointermap;
  var touchMap = Array.prototype.map.call.bind(Array.prototype.map);
  // This should be long enough to ignore compat mouse events made by touch
  var DEDUP_TIMEOUT = 1000;
  // handler block for native touch events
  var touchEvents = {
    events: [
      'touchstart',
      'touchmove',
      'touchend',
      'touchcancel'
    ],
    POINTER_TYPE: 'touch',
    firstTouch: null,
    isPrimaryTouch: function(inTouch) {
      return this.firstTouch === inTouch.identifier;
    },
    setPrimaryTouch: function(inTouch) {
      if (this.firstTouch === null) {
        this.firstTouch = inTouch.identifier;
      }
    },
    removePrimaryTouch: function(inTouch) {
      if (this.isPrimaryTouch(inTouch)) {
        this.firstTouch = null;
      }
    },
    touchToPointer: function(inTouch) {
      var e = dispatcher.cloneEvent(inTouch);
      // Spec specifies that pointerId 1 is reserved for Mouse.
      // Touch identifiers can start at 0.
      // Add 2 to the touch identifier for compatibility.
      e.pointerId = inTouch.identifier + 2;
      e.target = this.findTarget(e);
      e.bubbles = true;
      e.cancelable = true;
      e.button = 0;
      e.buttons = 1;
      e.isPrimary = this.isPrimaryTouch(inTouch);
      e.pointerType = this.POINTER_TYPE;
      return e;
    },
    processTouches: function(inEvent, inFunction) {
      var tl = inEvent.changedTouches;
      var pointers = touchMap(tl, this.touchToPointer, this);
      pointers.forEach(inFunction, this);
    },
    findTarget: function(inEvent) {
      var x = inEvent.clientX, y = inEvent.clientY;
      // find target from light dom
      var t = document.elementFromPoint(x, y);
      var st, sr, os;
      // is element a shadow host?
      sr = t && (t.webkitShadowRoot || t.shadowRoot);
      while (sr) {
        // find the the element inside the shadow root
        st = sr.elementFromPoint(x, y);
        if (!st) {
          // check for older shadows
          os = sr.querySelector('shadow');
          // check the older shadow if available
          sr = os ? os.olderShadowRoot : null;
        } else {
          // shadowed element is the target
          return st;
        }
      }
      // light dom element is the target
      return t;
    },
    touchstart: function(inEvent) {
      this.setPrimaryTouch(inEvent.changedTouches[0]);
      this.processTouches(inEvent, this.overDown);
    },
    overDown: function(inPointer) {
      var p = pointermap.set(inPointer.pointerId, {
        target: inPointer.target,
        out: inPointer,
        outTarget: inPointer.target
      });
      dispatcher.over(inPointer);
      dispatcher.down(inPointer);
    },
    touchmove: function(inEvent) {
      // must preventDefault first touchmove or document will scroll otherwise
      // Per Touch event spec section 5.6
      // http://www.w3.org/TR/touch-events/#the-touchmove-event
      inEvent.preventDefault();
      this.processTouches(inEvent, this.moveOverOut);
    },
    moveOverOut: function(inPointer) {
      var event = inPointer;
      var pointer = pointermap.get(event.pointerId);
      var outEvent = pointer.out;
      var outTarget = pointer.outTarget;
      dispatcher.move(event);
      if (outEvent && outTarget !== event.target) {
        outEvent.relatedTarget = event.target;
        event.relatedTarget = outTarget;
        // recover from retargeting by shadow
        outEvent.target = outTarget;
        dispatcher.out(outEvent);
        dispatcher.over(event);
      }
      pointer.out = event;
      pointer.outTarget = event.target;
    },
    touchend: function(inEvent) {
      this.dedupSynthMouse(inEvent);
      this.processTouches(inEvent, this.upOut);
    },
    upOut: function(inPointer) {
      dispatcher.up(inPointer);
      dispatcher.out(inPointer);
      this.cleanUpPointer(inPointer);
    },
    touchcancel: function(inEvent) {
      this.processTouches(inEvent, this.cancelOut);
    },
    cancelOut: function(inPointer) {
      dispatcher.cancel(inPointer);
      dispatcher.out(inPointer);
      this.cleanUpPointer(inPointer);
    },
    cleanUpPointer: function(inPointer) {
      pointermap.delete(inPointer.pointerId);
      this.removePrimaryTouch(inPointer);
    },
    // prevent synth mouse events from creating pointer events
    dedupSynthMouse: function(inEvent) {
      var lts = mouseEvents.lastTouches;
      var t = inEvent.changedTouches[0];
      // only the primary finger will synth mouse events
      if (this.isPrimaryTouch(t)) {
        // remember x/y of last touch
        var lt = {x: t.clientX, y: t.clientY};
        lts.push(lt);
        var fn = (function(lts, lt){
          var i = lts.indexOf(lt);
          if (i > -1) {
            lts.splice(i, 1)
          }
        }).bind(null, lts, lt);
        setTimeout(fn, DEDUP_TIMEOUT);
      }
    }
  };

  // handler block for native mouse events
  var mouseEvents = {
    // Mouse is required to have a pointerId of 1
    POINTER_ID: 1,
    POINTER_TYPE: 'mouse',
    events: [
      'mousedown',
      'mousemove',
      'mouseup',
      'mouseover',
      'mouseout'
    ],
    global: [
      'mousedown',
      'mouseup',
      'mouseover',
      'mouseout'
    ],
    lastTouches: [],
    isTouchEmulated: function(inEvent) {
      var lts = this.lastTouches;
      var x = inEvent.clientX, y = inEvent.clientY;
      for (var i = 0, l = lts.length, t; i < l && (t = lts[i]); i++) {
        // simulated mouse events are on the same x/y as the touchend
        if (t.x == x && t.y == y) {
          return true;
        }
      }
    },
    prepareEvent: function(inEvent) {
      var e = dispatcher.cloneEvent(inEvent);
      e.pointerId = this.POINTER_ID;
      e.isPrimary = true;
      e.pointerType = this.POINTER_TYPE;
      return e;
    },
    mousedown: function(inEvent) {
      if (this.isTouchEmulated(inEvent)) {
        return;
      }
      if (!pointermap.has(this.POINTER_ID)) {
        var e = this.prepareEvent(inEvent);
        var p = pointermap.set(this.POINTER_ID, inEvent);
        dispatcher.down(e);
        dispatcher.listen(this.global, document);
      }
    },
    mousemove: function(inEvent) {
      if (!this.isTouchEmulated(inEvent)) {
        var e = this.prepareEvent(inEvent);
        dispatcher.move(e);
      }
    },
    mouseup: function(inEvent) {
      if (this.isTouchEmulated(inEvent)) {
        return;
      }
      var p = pointermap.get(this.POINTER_ID);
      if (p && p.button === inEvent.button) {
        var e = this.prepareEvent(inEvent);
        dispatcher.up(e);
        pointermap.delete(this.POINTER_ID);
        dispatcher.unlisten(this.global, document);
      }
    },
    mouseover: function(inEvent) {
      if (this.isTouchEmulated(inEvent)) {
        return;
      }
      var e = this.prepareEvent(inEvent);
      dispatcher.over(e);
    },
    mouseout: function(inEvent) {
      if (this.isTouchEmulated(inEvent)) {
        return;
      }
      var e = this.prepareEvent(inEvent);
      dispatcher.out(e);
    }
  };

  var msEvents = {
    events: [
      'MSPointerDown',
      'MSPointerMove',
      'MSPointerUp',
      'MSPointerOut',
      'MSPointerOver',
      'MSPointerCancel'
    ],
    POINTER_TYPES: [
      'NOT USED',
      'unavailable',
      'touch',
      'pen',
      'mouse'
    ],
    prepareEvent: function(inEvent) {
      var e = dispatcher.cloneEvent(inEvent);
      e.pointerType = this.POINTER_TYPES[inEvent.pointerType];
      return e;
    },
    MSPointerDown: function(inEvent) {
      var e = this.prepareEvent(inEvent);
      dispatcher.down(e);
    },
    MSPointerMove: function(inEvent) {
      var e = this.prepareEvent(inEvent);
      dispatcher.move(e);
    },
    MSPointerUp: function(inEvent) {
      var e = this.prepareEvent(inEvent);
      dispatcher.up(e);
    },
    MSPointerOut: function(inEvent) {
      var e = this.prepareEvent(inEvent);
      dispatcher.out(e);
    },
    MSPointerOver: function(inEvent) {
      var e = this.prepareEvent(inEvent);
      dispatcher.over(e);
    },
    MSPointerCancel: function(inEvent) {
      var e = this.prepareEvent(inEvent);
      dispatcher.cancel(e);
    }
  };

  // only activate if this platform does not have pointer events
  if (window.navigator.pointerEnabled === undefined) {

    if (window.navigator.msPointerEnabled) {
      var tp = window.navigator.msMaxTouchPoints;
      if (tp !== undefined) {
        Object.defineProperty(window.navigator, 'maxTouchPoints', {
          value: tp,
          enumerable: true
        });
      }
      dispatcher.registerSource('ms', msEvents);
      dispatcher.registerTarget(document);
    } else {
      dispatcher.registerSource('mouse', mouseEvents);
      if ('ontouchstart' in window) {
        dispatcher.registerSource('touch', touchEvents);
      }
      installer.enableOnSubtree(document);
      // mouse move events must be on at all times
      dispatcher.listen(['mousemove'], document);
    }

    Object.defineProperty(window.navigator, 'pointerEnabled', {value: true, enumerable: true});
  }
})(window.__PointerEventShim__);
<|endoftext|>


<commit_before>
// install   :      cordova plugin add phonegap-plugin-push
// link      :      https://github.com/phonegap/phonegap-plugin-push

angular.module('ngCordova.plugins.push_v5', [])
  .factory('$cordovaPushV5',['$q', '$rootScope', '$timeout', function ($q, $rootScope, $timeout) {
   /*global PushNotification*/

    var push;
    return {
      initialize : function (options) {
        var q = $q.defer();
        push = PushNotification.init(options);
        q.resolve(push);
        return q.promise;
      },
      onNotification : function () {
        $timeout(function () {
          push.on('notification', function (notification) {
            $rootScope.$emit('$cordovaPushV5:notificationReceived', notification);
          });
        });
      },
      onError : function () {
        $timeout(function () {
          push.on('error', function (error) { $rootScope.$emit('$cordovaPushV5:errorOccurred', error);});
        });
      },
      register : function () {
        var q = $q.defer();
        if (push === undefined) {
          q.reject(new Error('init must be called before any other operation'));
        } else {
          push.on('registration', function (data) {
            q.resolve(data.registrationId);
          });
        }
        return q.promise;
      },
      unregister : function () {
        var q = $q.defer();
        if (push === undefined) {
          q.reject(new Error('init must be called before any other operation'));
        } else {
          push.unregister(function (success) {
            q.resolve(success);
          },function (error) {
            q.reject(error);
          });
        }
        return q.promise;
      },
      setBadgeNumber : function (number) {
        var q = $q.defer();
        if (push === undefined) {
          q.reject(new Error('init must be called before any other operation'));
        } else {
          push.setApplicationIconBadgeNumber(function (success) {
            q.resolve(success);
          }, function (error) {
            q.reject(error);
          }, number);
        }
        return q.promise;
      }
    };
  }]);
<commit_msg>Adding push.finish() method - required in iOS <commit_after>
// install   :      cordova plugin add phonegap-plugin-push
// link      :      https://github.com/phonegap/phonegap-plugin-push

angular.module('ngCordova.plugins.push_v5', [])
  .factory('$cordovaPushV5',['$q', '$rootScope', '$timeout', function ($q, $rootScope, $timeout) {
   /*global PushNotification*/

    var push;
    return {
      initialize : function (options) {
        var q = $q.defer();
        push = PushNotification.init(options);
        q.resolve(push);
        return q.promise;
      },
      onNotification : function () {
        $timeout(function () {
          push.on('notification', function (notification) {
            $rootScope.$emit('$cordovaPushV5:notificationReceived', notification);
          });
        });
      },
      onError : function () {
        $timeout(function () {
          push.on('error', function (error) { $rootScope.$emit('$cordovaPushV5:errorOccurred', error);});
        });
      },
      register : function () {
        var q = $q.defer();
        if (push === undefined) {
          q.reject(new Error('init must be called before any other operation'));
        } else {
          push.on('registration', function (data) {
            q.resolve(data.registrationId);
          });
        }
        return q.promise;
      },
      unregister : function () {
        var q = $q.defer();
        if (push === undefined) {
          q.reject(new Error('init must be called before any other operation'));
        } else {
          push.unregister(function (success) {
            q.resolve(success);
          },function (error) {
            q.reject(error);
          });
        }
        return q.promise;
      },
      setBadgeNumber : function (number) {
        var q = $q.defer();
        if (push === undefined) {
          q.reject(new Error('init must be called before any other operation'));
        } else {
          push.setApplicationIconBadgeNumber(function (success) {
            q.resolve(success);
          }, function (error) {
            q.reject(error);
          }, number);
        }
        return q.promise;
      },
      finish: function(){
        var q = $q.defer();
        if (push === undefined) {
          q.reject(new Error('init must be called before any other operation'));
        } else {
          push.finish(function (success) {
            q.resolve(success);
          }, function (error) {
            q.reject(error);
          });
        }
        return q.promise;
      }
    };
  }]);
<|endoftext|>


<commit_before>"use strict";

var gulp     = require('gulp'),
    eslint   = require('gulp-eslint'),
    plumber  = require('gulp-plumber'),
    notifier = require('node-notifier'),
    uglify   = require('gulp-uglify'),
    rename   = require('gulp-rename'),
    jade     = require('gulp-jade');

// 共通エラーハンドラー
var error_handler = {
   // タスクネーム
   task: '',
   // エラーをハンドル
   errorHandler: function(error) {
      var task_name = task;
      var title     = '[task]' + task_name + ' ' + error.plugin;
      var error_msg = 'error: ' + error.message;
      // コンソールにエラーを出力
      console.error(title + '\n' + error_msg);
      // エラーを通知
      notifier.notify({
        title  : title,
        message: error_msg,
        time: 3000
      });
   }
};

// eslint タスク
gulp.task('lint', function() {
   error_handler.task = 'lint';
   return gulp.src(['js/*.js'])
      .pipe(plumber(error_handler))
      .pipe(eslint.format())
      .pipe(eslint.failOnError())
      .pipe(plumber.stop());
});

// scss タスク
gulp.task('scss', function() {
   error_handler.task = 'scss';
   return gulp.src(['scss/*.scss'])
      .pipe(plumber(error_handler))
      .pipe(sass({ outputStyle: 'extended' }))
      .pipe(gulp.dest('css'))
      .pipe(plumber.stop());
});

// jade タスク
gulp.task('jade', function() {
   error_handler.task = 'jade';
   return gulp.src(['jade/*.jade'])
      .pipe(plumber(error_handler))
      .pipe(jade({ pretty: true }))
      .pipe(gulp.dest('html'))
      .pipe(plumber.stop());
});

// min タスク(css)
gulp.task('cssmin', function() {
   return gulp.src(['css/*.css'])
      .pipe(uglify())
      .pipe(rename({ suffix: '.min' }))
      .pipe(gulp.dest('css/min/'));
});

// min タスク(js)
gulp.task('jsmin', function() {
   return gulp.src(['js/*.js'])
      .pipe(uglify())
      .pipe(rename({suffix: '.min'}))
      .pipe(gulp.dest('js/min'));
});

// watch タスク
gulp.task('watch', function() {
    gulp.watch('js/*.js', function() {
        gulp.run('lint');
    });

   gulp.watch('scss/*.scss', function() {
      gulp.run('scss');
   });

   gulp.watch('jade/*.jade', function() {
      gulp.run('jade');
   });
});

gulp.task('default', ['watch']);
<commit_msg>minor modification<commit_after>"use strict";

var gulp     = require('gulp'),
    sass     = require('gulp-sass'),
    eslint   = require('gulp-eslint'),
    plumber  = require('gulp-plumber'),
    notifier = require('node-notifier'),
    uglify   = require('gulp-uglify'),
    rename   = require('gulp-rename'),
    jade     = require('gulp-jade');

// 共通エラーハンドラー
var error_handler = {
   // タスクネーム
   task: '',
   // エラーをハンドル
   errorHandler: function(error) {
      var title     = '[task]' + task + ' ' + error.plugin;
      var error_msg = 'error: ' + error.message;
      // コンソールにエラーを出力
      console.error(title + '\n' + error_msg);
      // エラーを通知
      notifier.notify({
        title  : title,
        message: error_msg,
        time: 3000
      });
   }
};

// eslint タスク
gulp.task('lint', function() {
   error_handler.task = 'lint';
   return gulp.src(['js/*.js'])
      .pipe(plumber(error_handler))
      .pipe(eslint.format())
      .pipe(eslint.failOnError())
      .pipe(plumber.stop());
});

// scss タスク
gulp.task('scss', function() {
   error_handler.task = 'scss';
   return gulp.src(['scss/*.scss'])
      .pipe(plumber(error_handler))
      .pipe(sass({ outputStyle: 'extended' }))
      .pipe(gulp.dest('css'))
      .pipe(plumber.stop());
});

// jade タスク
gulp.task('jade', function() {
   error_handler.task = 'jade';
   return gulp.src(['jade/*.jade'])
      .pipe(plumber(error_handler))
      .pipe(jade({ pretty: true }))
      .pipe(gulp.dest('html'))
      .pipe(plumber.stop());
});

// min タスク(css)
gulp.task('cssmin', function() {
   return gulp.src(['css/*.css'])
      .pipe(uglify())
      .pipe(rename({ suffix: '.min' }))
      .pipe(gulp.dest('css/min/'));
});

// min タスク(js)
gulp.task('jsmin', function() {
   return gulp.src(['js/*.js'])
      .pipe(uglify())
      .pipe(rename({suffix: '.min'}))
      .pipe(gulp.dest('js/min'));
});

// watch タスク
gulp.task('watch', function() {
    gulp.watch('js/*.js', function() {
        gulp.run('lint');
    });

   gulp.watch('scss/*.scss', function() {
      gulp.run('scss');
   });

   gulp.watch('jade/*.jade', function() {
      gulp.run('jade');
   });
});

// derfault タスク
gulp.task('default', ['watch']);
<|endoftext|>


<commit_before>const exec = require('shell-utils').exec;

function e2e() {
  try {
    exec.execSync(`echo 'travis_fold:start:android-e2e'`);
    exec.execSync(`yarn run uninstall-android`);
    exec.execSync(`yarn run install-android`);
    exec.execSync(`cd AndroidE2E && ./gradlew connectedDebugAndroidTest`);
  } finally {
    exec.execSync(`echo 'travis_fold:end:android-e2e'`);
  }
}

function run() {
  if (process.env.CI) {
    exec.execSync(`./scripts/installAndroidSDK.sh`);
  }

  exec.execSync(`cd lib/android && ./gradlew clean testDebugUnitTest`);

  if (!process.env.CI) {
    e2e();
  }
}

run();
<commit_msg>refactor<commit_after>const exec = require('shell-utils').exec;

function unitTests() {
  exec.execSync(`cd lib/android && ./gradlew clean testDebugUnitTest`);
}

function e2e() {
  if (!process.env.CI) {
    console.log(`e2e disabled on CI`); //eslint-disable-line
    return;
  }

  try {
    exec.execSync(`echo 'travis_fold:start:android-e2e'`);
    exec.execSync(`yarn run uninstall-android`);
    exec.execSync(`yarn run install-android`);
    exec.execSync(`cd AndroidE2E && ./gradlew connectedDebugAndroidTest`);
  } finally {
    exec.execSync(`echo 'travis_fold:end:android-e2e'`);
  }
}

function run() {
  if (process.env.CI) {
    exec.execSync(`./scripts/installAndroidSDK.sh`);
  }
  unitTests();
  e2e();
}

run();
<|endoftext|>


<commit_before>/** ## jquery.flot.composeImages.js

This plugin is used to expose a function used to overlap several canvases and
SVGs, for the purpose of creating a snaphot out of them.

### When composeImages is used:
When multiple canvases and SVGs have to be overlapped into a single image
and their offset on the page, must be preserved.

### Where can be used:
In creating a downloadable snapshot of the plots, axes, cursors etc of a graph.

### How it works:
The entry point is composeImages function. It expects an array of objects,
which should be either canvases or SVGs (or a mix). It does a prevalidation
of them, by verifying if they will be usable or not, later in the flow.
After selecting only usable sources, it passes them to getGenerateTempImg
function, which generates temporary images out of them. This function
expects that some of the passed sources (canvas or SVG) may still have
problems being converted to an image and makes sure the promises system,
used by composeImages function, moves forward. As an example, SVGs with
missing information from header or with unsupported content, may lead to
failure in generating the temporary image. Temporary images are required
mostly on extracting content from SVGs, but this is also where the x/y
offsets are extracted for each image which will be added. For SVGs in
particular, their CSS rules have to be applied.
After all temporary images are generated, they are overlapped using
getExecuteImgComposition function. This is where the destination canvas
is set to the proper dimensions. It is then output by composeImages.
This function returns a promise, which can be used to wait for the whole
composition process. It requires to be asynchronous, because this is how
temporary images load their data.
*/

(function($) {
    "use strict";
    const GENERALFAILURECALLBACKERROR = -100; //simply a negative number
    const SUCCESSFULIMAGEPREPARATION = 0;
    const EMPTYARRAYOFIMAGESOURCES = -1;
    const NEGATIVEIMAGESIZE = -2;
    var pixelRatio = 1;
    var browser = $.plot.browser;
    var getPixelRatio = browser.getPixelRatio;

    function composeImages(canvasOrSvgSources, destinationCanvas) {
        var validCanvasOrSvgSources = canvasOrSvgSources.filter(isValidSource);
        pixelRatio = getPixelRatio(destinationCanvas.getContext('2d'));

        var allImgCompositionPromises = validCanvasOrSvgSources.map(function(validCanvasOrSvgSource) {
            var tempImg = new Image();
            var currentPromise = new Promise(getGenerateTempImg(tempImg, validCanvasOrSvgSource));
            return currentPromise;
        });

        var lastPromise = Promise.all(allImgCompositionPromises).then(getExecuteImgComposition(destinationCanvas), failureCallback);
        return lastPromise;
    }

    function isValidSource(canvasOrSvgSource) {
        var isValidFromCanvas = true;
        var isValidFromContent = true;
        if ((canvasOrSvgSource === null) || (canvasOrSvgSource === undefined)) {
            isValidFromContent = false;
        } else {
            if (canvasOrSvgSource.tagName === 'CANVAS') {
                if ((canvasOrSvgSource.getBoundingClientRect().right === canvasOrSvgSource.getBoundingClientRect().left) ||
                    (canvasOrSvgSource.getBoundingClientRect().bottom === canvasOrSvgSource.getBoundingClientRect().top)) {
                    isValidFromCanvas = false;
                }
            }
        }
        return isValidFromContent && isValidFromCanvas && (window.getComputedStyle(canvasOrSvgSource).visibility === 'visible');
    }

    function getGenerateTempImg(tempImg, canvasOrSvgSource) {
        tempImg.sourceDescription = '<info className="' + canvasOrSvgSource.className + '" tagName="' + canvasOrSvgSource.tagName + '" id="' + canvasOrSvgSource.id + '">';
        tempImg.sourceComponent = canvasOrSvgSource;

        return function doGenerateTempImg(successCallbackFunc, failureCallbackFunc) {
            tempImg.onload = function(evt) {
                tempImg.successfullyLoaded = true;
                successCallbackFunc(tempImg);
            };

            tempImg.onabort = function(evt) {
                tempImg.successfullyLoaded = false;
                console.log('Can\'t generate temp image from ' + tempImg.sourceDescription + '. It is possible that it is missing some properties or its content is not supported by this browser. Source component:', tempImg.sourceComponent);
                successCallbackFunc(tempImg); //call successCallback, to allow snapshot of all working images
            };

            tempImg.onerror = function(evt) {
                tempImg.successfullyLoaded = false;
                console.log('Can\'t generate temp image from ' + tempImg.sourceDescription + '. It is possible that it is missing some properties or its content is not supported by this browser. Source component:', tempImg.sourceComponent);
                successCallbackFunc(tempImg); //call successCallback, to allow snapshot of all working images
            };

            generateTempImageFromCanvasOrSvg(canvasOrSvgSource, tempImg);
        };
    }

    function getExecuteImgComposition(destinationCanvas) {
        return function executeImgComposition(tempImgs) {
            var compositionResult = copyImgsToCanvas(tempImgs, destinationCanvas);
            return compositionResult;
        };
    }

    function copyCanvasToImg(canvas, img) {
        img.src = canvas.toDataURL('image/png');
    }

    function getCSSRules(document) {
        var styleSheets = document.styleSheets,
            rulesList = [];
        for (var i = 0; i < styleSheets.length; i++) {
            // in Chrome, the external CSS files are empty when the page is directly loaded from disk
            var rules = styleSheets[i].cssRules || [];
            for (var j = 0; j < rules.length; j++) {
                var rule = rules[j];
                rulesList.push(rule.cssText);
            }
        }
        return rulesList;
    }

    function embedCSSRulesInSVG(rules, svg) {
        var text = [
            '<svg class="snapshot ' + svg.classList + '" width="' + svg.width.baseVal.value * pixelRatio + '" height="' + svg.height.baseVal.value * pixelRatio + '" viewBox="0 0 ' + svg.width.baseVal.value + ' ' + svg.height.baseVal.value + '" xmlns="http://www.w3.org/2000/svg">',
            '<style>',
            '/* <![CDATA[ */',
            rules.join('\n'),
            '/* ]]> */',
            '</style>',
            svg.innerHTML,
            '</svg>'
        ].join('\n');
        return text;
    }

    function copySVGToImgMostBrowsers(svg, img) {
        var rules = getCSSRules(document),
            source = embedCSSRulesInSVG(rules, svg);

        source = patchSVGSource(source);

        var blob = new Blob([source], {type: "image/svg+xml;charset=utf-8"}),
            domURL = self.URL || self.webkitURL || self,
            url = domURL.createObjectURL(blob);
        img.src = url;
    }

    function copySVGToImgSafari(svg, img) {
        // Use this method to convert a string buffer array to a binary string.
        // Do so by breaking up large strings into smaller substrings; this is necessary to avoid the
        // "maximum call stack size exceeded" exception that can happen when calling 'String.fromCharCode.apply'
        // with a very long array.
        function buildBinaryString (arrayBuffer) {
            var binaryString = "";
            const utf8Array = new Uint8Array(arrayBuffer);
            const blockSize = 16384;
            for (var i = 0; i < utf8Array.length; i = i + blockSize) {
                const binarySubString = String.fromCharCode.apply(null, utf8Array.subarray(i, i + blockSize));
                binaryString = binaryString + binarySubString;
            }
            return binaryString;
        };

        var rules = getCSSRules(document),
            source = embedCSSRulesInSVG(rules, svg),
            data,
            utf8BinaryString;

        source = patchSVGSource(source);

        // Encode the string as UTF-8 and convert it to a binary string. The UTF-8 encoding is required to
        // capture unicode characters correctly.
        utf8BinaryString = buildBinaryString(new (TextEncoder || TextEncoderLite)('utf-8').encode(source));

        data = "data:image/svg+xml;base64," + btoa(source);
        img.src = data;
    }

    function patchSVGSource(svgSource) {
        var source = '';
        //add name spaces.
        if (!svgSource.match(/^<svg[^>]+xmlns="http:\/\/www\.w3\.org\/2000\/svg"/)) {
            source = svgSource.replace(/^<svg/, '<svg xmlns="http://www.w3.org/2000/svg"');
        }
        if (!svgSource.match(/^<svg[^>]+"http:\/\/www\.w3\.org\/1999\/xlink"/)) {
            source = svgSource.replace(/^<svg/, '<svg xmlns:xlink="http://www.w3.org/1999/xlink"');
        }

        //add xml declaration
        return '<?xml version="1.0" standalone="no"?>\r\n' + source;
    }

    function copySVGToImg(svg, img) {
        if (browser.isSafari() || browser.isMobileSafari()) {
            copySVGToImgSafari(svg, img);
        } else {
            copySVGToImgMostBrowsers(svg, img);
        }
    }

    function adaptDestSizeToZoom(destinationCanvas, sources) {
        function containsSVGs(source) {
            return source.srcImgTagName === 'svg';
        }

        if (sources.find(containsSVGs) !== undefined) {
            if (pixelRatio < 1) {
                destinationCanvas.width = destinationCanvas.width * pixelRatio;
                destinationCanvas.height = destinationCanvas.height * pixelRatio;
            }
        }
    }

    function prepareImagesToBeComposed(sources, destination) {
        var result = SUCCESSFULIMAGEPREPARATION;
        if (sources.length === 0) {
            result = EMPTYARRAYOFIMAGESOURCES; //nothing to do if called without sources
        } else {
            var minX = sources[0].genLeft;
            var minY = sources[0].genTop;
            var maxX = sources[0].genRight;
            var maxY = sources[0].genBottom;
            var i = 0;

            for (i = 1; i < sources.length; i++) {
                if (minX > sources[i].genLeft) {
                    minX = sources[i].genLeft;
                }

                if (minY > sources[i].genTop) {
                    minY = sources[i].genTop;
                }
            }

            for (i = 1; i < sources.length; i++) {
                if (maxX < sources[i].genRight) {
                    maxX = sources[i].genRight;
                }

                if (maxY < sources[i].genBottom) {
                    maxY = sources[i].genBottom;
                }
            }

            if ((maxX - minX <= 0) || (maxY - minY <= 0)) {
                result = NEGATIVEIMAGESIZE; //this might occur on hidden images
            } else {
                destination.width = Math.round(maxX - minX);
                destination.height = Math.round(maxY - minY);

                for (i = 0; i < sources.length; i++) {
                    sources[i].xCompOffset = sources[i].genLeft - minX;
                    sources[i].yCompOffset = sources[i].genTop - minY;
                }

                adaptDestSizeToZoom(destination, sources);
            }
        }
        return result;
    }

    function copyImgsToCanvas(sources, destination) {
        var prepareImagesResult = prepareImagesToBeComposed(sources, destination);
        if (prepareImagesResult === SUCCESSFULIMAGEPREPARATION) {
            var destinationCtx = destination.getContext('2d');

            for (var i = 0; i < sources.length; i++) {
                if (sources[i].successfullyLoaded === true) {
                    destinationCtx.drawImage(sources[i], sources[i].xCompOffset * pixelRatio, sources[i].yCompOffset * pixelRatio);
                }
            }
        }
        return prepareImagesResult;
    }

    function adnotateDestImgWithBoundingClientRect(srcCanvasOrSvg, destImg) {
        destImg.genLeft = srcCanvasOrSvg.getBoundingClientRect().left;
        destImg.genTop = srcCanvasOrSvg.getBoundingClientRect().top;

        if (srcCanvasOrSvg.tagName === 'CANVAS') {
            destImg.genRight = destImg.genLeft + srcCanvasOrSvg.width;
            destImg.genBottom = destImg.genTop + srcCanvasOrSvg.height;
        }

        if (srcCanvasOrSvg.tagName === 'svg') {
            destImg.genRight = srcCanvasOrSvg.getBoundingClientRect().right;
            destImg.genBottom = srcCanvasOrSvg.getBoundingClientRect().bottom;
        }
    }

    function generateTempImageFromCanvasOrSvg(srcCanvasOrSvg, destImg) {
        if (srcCanvasOrSvg.tagName === 'CANVAS') {
            copyCanvasToImg(srcCanvasOrSvg, destImg);
        }

        if (srcCanvasOrSvg.tagName === 'svg') {
            copySVGToImg(srcCanvasOrSvg, destImg);
        }

        destImg.srcImgTagName = srcCanvasOrSvg.tagName;
        adnotateDestImgWithBoundingClientRect(srcCanvasOrSvg, destImg);
    }

    function failureCallback() {
        return GENERALFAILURECALLBACKERROR;
    }

    // used for testing
    $.plot.composeImages = composeImages;

    function init(plot) {
        // used to extend the public API of the plot
        plot.composeImages = composeImages;
    }

    $.plot.plugins.push({
        init: init,
        name: 'composeImages',
        version: '1.0'
    });
})(jQuery);
<commit_msg>fixing typo<commit_after>/** ## jquery.flot.composeImages.js

This plugin is used to expose a function used to overlap several canvases and
SVGs, for the purpose of creating a snaphot out of them.

### When composeImages is used:
When multiple canvases and SVGs have to be overlapped into a single image
and their offset on the page, must be preserved.

### Where can be used:
In creating a downloadable snapshot of the plots, axes, cursors etc of a graph.

### How it works:
The entry point is composeImages function. It expects an array of objects,
which should be either canvases or SVGs (or a mix). It does a prevalidation
of them, by verifying if they will be usable or not, later in the flow.
After selecting only usable sources, it passes them to getGenerateTempImg
function, which generates temporary images out of them. This function
expects that some of the passed sources (canvas or SVG) may still have
problems being converted to an image and makes sure the promises system,
used by composeImages function, moves forward. As an example, SVGs with
missing information from header or with unsupported content, may lead to
failure in generating the temporary image. Temporary images are required
mostly on extracting content from SVGs, but this is also where the x/y
offsets are extracted for each image which will be added. For SVGs in
particular, their CSS rules have to be applied.
After all temporary images are generated, they are overlapped using
getExecuteImgComposition function. This is where the destination canvas
is set to the proper dimensions. It is then output by composeImages.
This function returns a promise, which can be used to wait for the whole
composition process. It requires to be asynchronous, because this is how
temporary images load their data.
*/

(function($) {
    "use strict";
    const GENERALFAILURECALLBACKERROR = -100; //simply a negative number
    const SUCCESSFULIMAGEPREPARATION = 0;
    const EMPTYARRAYOFIMAGESOURCES = -1;
    const NEGATIVEIMAGESIZE = -2;
    var pixelRatio = 1;
    var browser = $.plot.browser;
    var getPixelRatio = browser.getPixelRatio;

    function composeImages(canvasOrSvgSources, destinationCanvas) {
        var validCanvasOrSvgSources = canvasOrSvgSources.filter(isValidSource);
        pixelRatio = getPixelRatio(destinationCanvas.getContext('2d'));

        var allImgCompositionPromises = validCanvasOrSvgSources.map(function(validCanvasOrSvgSource) {
            var tempImg = new Image();
            var currentPromise = new Promise(getGenerateTempImg(tempImg, validCanvasOrSvgSource));
            return currentPromise;
        });

        var lastPromise = Promise.all(allImgCompositionPromises).then(getExecuteImgComposition(destinationCanvas), failureCallback);
        return lastPromise;
    }

    function isValidSource(canvasOrSvgSource) {
        var isValidFromCanvas = true;
        var isValidFromContent = true;
        if ((canvasOrSvgSource === null) || (canvasOrSvgSource === undefined)) {
            isValidFromContent = false;
        } else {
            if (canvasOrSvgSource.tagName === 'CANVAS') {
                if ((canvasOrSvgSource.getBoundingClientRect().right === canvasOrSvgSource.getBoundingClientRect().left) ||
                    (canvasOrSvgSource.getBoundingClientRect().bottom === canvasOrSvgSource.getBoundingClientRect().top)) {
                    isValidFromCanvas = false;
                }
            }
        }
        return isValidFromContent && isValidFromCanvas && (window.getComputedStyle(canvasOrSvgSource).visibility === 'visible');
    }

    function getGenerateTempImg(tempImg, canvasOrSvgSource) {
        tempImg.sourceDescription = '<info className="' + canvasOrSvgSource.className + '" tagName="' + canvasOrSvgSource.tagName + '" id="' + canvasOrSvgSource.id + '">';
        tempImg.sourceComponent = canvasOrSvgSource;

        return function doGenerateTempImg(successCallbackFunc, failureCallbackFunc) {
            tempImg.onload = function(evt) {
                tempImg.successfullyLoaded = true;
                successCallbackFunc(tempImg);
            };

            tempImg.onabort = function(evt) {
                tempImg.successfullyLoaded = false;
                console.log('Can\'t generate temp image from ' + tempImg.sourceDescription + '. It is possible that it is missing some properties or its content is not supported by this browser. Source component:', tempImg.sourceComponent);
                successCallbackFunc(tempImg); //call successCallback, to allow snapshot of all working images
            };

            tempImg.onerror = function(evt) {
                tempImg.successfullyLoaded = false;
                console.log('Can\'t generate temp image from ' + tempImg.sourceDescription + '. It is possible that it is missing some properties or its content is not supported by this browser. Source component:', tempImg.sourceComponent);
                successCallbackFunc(tempImg); //call successCallback, to allow snapshot of all working images
            };

            generateTempImageFromCanvasOrSvg(canvasOrSvgSource, tempImg);
        };
    }

    function getExecuteImgComposition(destinationCanvas) {
        return function executeImgComposition(tempImgs) {
            var compositionResult = copyImgsToCanvas(tempImgs, destinationCanvas);
            return compositionResult;
        };
    }

    function copyCanvasToImg(canvas, img) {
        img.src = canvas.toDataURL('image/png');
    }

    function getCSSRules(document) {
        var styleSheets = document.styleSheets,
            rulesList = [];
        for (var i = 0; i < styleSheets.length; i++) {
            // in Chrome, the external CSS files are empty when the page is directly loaded from disk
            var rules = styleSheets[i].cssRules || [];
            for (var j = 0; j < rules.length; j++) {
                var rule = rules[j];
                rulesList.push(rule.cssText);
            }
        }
        return rulesList;
    }

    function embedCSSRulesInSVG(rules, svg) {
        var text = [
            '<svg class="snapshot ' + svg.classList + '" width="' + svg.width.baseVal.value * pixelRatio + '" height="' + svg.height.baseVal.value * pixelRatio + '" viewBox="0 0 ' + svg.width.baseVal.value + ' ' + svg.height.baseVal.value + '" xmlns="http://www.w3.org/2000/svg">',
            '<style>',
            '/* <![CDATA[ */',
            rules.join('\n'),
            '/* ]]> */',
            '</style>',
            svg.innerHTML,
            '</svg>'
        ].join('\n');
        return text;
    }

    function copySVGToImgMostBrowsers(svg, img) {
        var rules = getCSSRules(document),
            source = embedCSSRulesInSVG(rules, svg);

        source = patchSVGSource(source);

        var blob = new Blob([source], {type: "image/svg+xml;charset=utf-8"}),
            domURL = self.URL || self.webkitURL || self,
            url = domURL.createObjectURL(blob);
        img.src = url;
    }

    function copySVGToImgSafari(svg, img) {
        // Use this method to convert a string buffer array to a binary string.
        // Do so by breaking up large strings into smaller substrings; this is necessary to avoid the
        // "maximum call stack size exceeded" exception that can happen when calling 'String.fromCharCode.apply'
        // with a very long array.
        function buildBinaryString (arrayBuffer) {
            var binaryString = "";
            const utf8Array = new Uint8Array(arrayBuffer);
            const blockSize = 16384;
            for (var i = 0; i < utf8Array.length; i = i + blockSize) {
                const binarySubString = String.fromCharCode.apply(null, utf8Array.subarray(i, i + blockSize));
                binaryString = binaryString + binarySubString;
            }
            return binaryString;
        };

        var rules = getCSSRules(document),
            source = embedCSSRulesInSVG(rules, svg),
            data,
            utf8BinaryString;

        source = patchSVGSource(source);

        // Encode the string as UTF-8 and convert it to a binary string. The UTF-8 encoding is required to
        // capture unicode characters correctly.
        utf8BinaryString = buildBinaryString(new (TextEncoder || TextEncoderLite)('utf-8').encode(source));

        data = "data:image/svg+xml;base64," + btoa(utf8BinaryString);
        img.src = data;
    }

    function patchSVGSource(svgSource) {
        var source = '';
        //add name spaces.
        if (!svgSource.match(/^<svg[^>]+xmlns="http:\/\/www\.w3\.org\/2000\/svg"/)) {
            source = svgSource.replace(/^<svg/, '<svg xmlns="http://www.w3.org/2000/svg"');
        }
        if (!svgSource.match(/^<svg[^>]+"http:\/\/www\.w3\.org\/1999\/xlink"/)) {
            source = svgSource.replace(/^<svg/, '<svg xmlns:xlink="http://www.w3.org/1999/xlink"');
        }

        //add xml declaration
        return '<?xml version="1.0" standalone="no"?>\r\n' + source;
    }

    function copySVGToImg(svg, img) {
        if (browser.isSafari() || browser.isMobileSafari()) {
            copySVGToImgSafari(svg, img);
        } else {
            copySVGToImgMostBrowsers(svg, img);
        }
    }

    function adaptDestSizeToZoom(destinationCanvas, sources) {
        function containsSVGs(source) {
            return source.srcImgTagName === 'svg';
        }

        if (sources.find(containsSVGs) !== undefined) {
            if (pixelRatio < 1) {
                destinationCanvas.width = destinationCanvas.width * pixelRatio;
                destinationCanvas.height = destinationCanvas.height * pixelRatio;
            }
        }
    }

    function prepareImagesToBeComposed(sources, destination) {
        var result = SUCCESSFULIMAGEPREPARATION;
        if (sources.length === 0) {
            result = EMPTYARRAYOFIMAGESOURCES; //nothing to do if called without sources
        } else {
            var minX = sources[0].genLeft;
            var minY = sources[0].genTop;
            var maxX = sources[0].genRight;
            var maxY = sources[0].genBottom;
            var i = 0;

            for (i = 1; i < sources.length; i++) {
                if (minX > sources[i].genLeft) {
                    minX = sources[i].genLeft;
                }

                if (minY > sources[i].genTop) {
                    minY = sources[i].genTop;
                }
            }

            for (i = 1; i < sources.length; i++) {
                if (maxX < sources[i].genRight) {
                    maxX = sources[i].genRight;
                }

                if (maxY < sources[i].genBottom) {
                    maxY = sources[i].genBottom;
                }
            }

            if ((maxX - minX <= 0) || (maxY - minY <= 0)) {
                result = NEGATIVEIMAGESIZE; //this might occur on hidden images
            } else {
                destination.width = Math.round(maxX - minX);
                destination.height = Math.round(maxY - minY);

                for (i = 0; i < sources.length; i++) {
                    sources[i].xCompOffset = sources[i].genLeft - minX;
                    sources[i].yCompOffset = sources[i].genTop - minY;
                }

                adaptDestSizeToZoom(destination, sources);
            }
        }
        return result;
    }

    function copyImgsToCanvas(sources, destination) {
        var prepareImagesResult = prepareImagesToBeComposed(sources, destination);
        if (prepareImagesResult === SUCCESSFULIMAGEPREPARATION) {
            var destinationCtx = destination.getContext('2d');

            for (var i = 0; i < sources.length; i++) {
                if (sources[i].successfullyLoaded === true) {
                    destinationCtx.drawImage(sources[i], sources[i].xCompOffset * pixelRatio, sources[i].yCompOffset * pixelRatio);
                }
            }
        }
        return prepareImagesResult;
    }

    function adnotateDestImgWithBoundingClientRect(srcCanvasOrSvg, destImg) {
        destImg.genLeft = srcCanvasOrSvg.getBoundingClientRect().left;
        destImg.genTop = srcCanvasOrSvg.getBoundingClientRect().top;

        if (srcCanvasOrSvg.tagName === 'CANVAS') {
            destImg.genRight = destImg.genLeft + srcCanvasOrSvg.width;
            destImg.genBottom = destImg.genTop + srcCanvasOrSvg.height;
        }

        if (srcCanvasOrSvg.tagName === 'svg') {
            destImg.genRight = srcCanvasOrSvg.getBoundingClientRect().right;
            destImg.genBottom = srcCanvasOrSvg.getBoundingClientRect().bottom;
        }
    }

    function generateTempImageFromCanvasOrSvg(srcCanvasOrSvg, destImg) {
        if (srcCanvasOrSvg.tagName === 'CANVAS') {
            copyCanvasToImg(srcCanvasOrSvg, destImg);
        }

        if (srcCanvasOrSvg.tagName === 'svg') {
            copySVGToImg(srcCanvasOrSvg, destImg);
        }

        destImg.srcImgTagName = srcCanvasOrSvg.tagName;
        adnotateDestImgWithBoundingClientRect(srcCanvasOrSvg, destImg);
    }

    function failureCallback() {
        return GENERALFAILURECALLBACKERROR;
    }

    // used for testing
    $.plot.composeImages = composeImages;

    function init(plot) {
        // used to extend the public API of the plot
        plot.composeImages = composeImages;
    }

    $.plot.plugins.push({
        init: init,
        name: 'composeImages',
        version: '1.0'
    });
})(jQuery);
<|endoftext|>


<commit_before>// Copyright 2014-2018, University of Colorado Boulder

/**
 * Button for selecting a game level.
 * Also depicts the progress made on each level.
 * See specification in https://github.com/phetsims/vegas/issues/59.
 *
 * @author John Blanco
 * @author Chris Malley
 * @author Andrea Lin
 */
define( function( require ) {
  'use strict';

  // modules
  var Dimension2 = require( 'DOT/Dimension2' );
  var GameTimer = require( 'VEGAS/GameTimer' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Node = require( 'SCENERY/nodes/Node' );
  var PhetFont = require( 'SCENERY_PHET/PhetFont' );
  var ScoreDisplayDiscreteStars = require( 'VEGAS/ScoreDisplayDiscreteStars' );
  var ScoreDisplayNumberAndStar = require( 'VEGAS/ScoreDisplayNumberAndStar' );
  var ScoreDisplayTextAndNumber = require( 'VEGAS/ScoreDisplayTextAndNumber' );
  var Rectangle = require( 'SCENERY/nodes/Rectangle' );
  var RectangularPushButton = require( 'SUN/buttons/RectangularPushButton' );
  var Tandem = require( 'TANDEM/Tandem' );
  var Text = require( 'SCENERY/nodes/Text' );
  var vegas = require( 'VEGAS/vegas' );

  // constants
  var SCALING_TOLERANCE = 1E-4; // Empirically chosen as something the human eye is unlikely to notice.

  /**
   * @param {Node} icon Scenery node that appears on the button above the score display, scaled to fit
   * @param {Node} scoreDisplay - displays the score
   * @param {Object} [options]
   * @constructor
   */
  function LevelSelectionItemNode( icon, scoreDisplay, options ) {

    assert && assert( icon instanceof Node );

    options = _.extend( {

      // score display type
      numStars: 1,

      listener: null, // {function}

      // button size and appearance
      buttonWidth: 150,
      buttonHeight: 150,
      cornerRadius: 10,
      baseColor: 'rgb( 242, 255, 204 )',
      buttonXMargin: 10,
      buttonYMargin: 10,

      // layout of scoreDisplay
      scoreDisplayProportion: 0.2, // percentage of the button height occupied by scoreDisplay, (0,0.5]
      scoreDisplayMinXMargin: 10, // horizontal margin between scoreDisplay and its background
      scoreDisplayMinYMargin: 5,  // vertical margin between scoreDisplay and its background
      iconToScoreDisplayYSpace: 10, // vertical space between icon and score display

      // best time (optional)
      bestTimeProperty: null, // null if no best time || {Property.<number>} best time in seconds
      bestTimeVisibleProperty: null, // null || Property.<boolean>} controls visibility of best time
      bestTimeFill: 'black',
      bestTimeFont: new PhetFont( 24 ),
      bestTimeYSpacing: 10,  // vertical space between drop shadow and best time

      // Tandem
      tandem: Tandem.required
    }, options );

    Node.call( this );

    assert && assert(
    options.scoreDisplayProportion > 0 && options.scoreDisplayProportion <= 0.5,
      'scoreDisplayProportion value out of range'
    );

    var maxContentWidth = options.buttonWidth - 2 * options.buttonXMargin;

    // Background behind scoreDisplay
    var scoreDisplayBackground = new Rectangle( 0, 0, maxContentWidth,
      options.buttonHeight * options.scoreDisplayProportion, options.cornerRadius, options.cornerRadius, {
        fill: 'white',
        stroke: 'black',
        lineWidth: 1,
        pickable: false
      } );

    // constrain scoreDisplay to fit in scoreDisplayBackground
    scoreDisplay.maxWidth = scoreDisplayBackground.width - 2 * options.scoreDisplayMinXMargin;
    scoreDisplay.maxHeight = scoreDisplayBackground.height - 2 * options.scoreDisplayMinYMargin;

    // Icon, scaled and padded to fit and to make the button size correct.
    var iconSize = new Dimension2( maxContentWidth, options.buttonHeight - scoreDisplayBackground.height -
                                                    2 * options.buttonYMargin - options.iconToScoreDisplayYSpace );
    var adjustedIcon = LevelSelectionItemNode.createSizedImageNode( icon, iconSize );

    // Assemble the content for the button.
    var buttonContent = new Node();
    if ( scoreDisplayBackground.width > adjustedIcon.width ) {
      adjustedIcon.centerX = scoreDisplayBackground.centerX;
    }
    else {
      scoreDisplayBackground.centerX = adjustedIcon.centerX;
    }
    scoreDisplayBackground.top = adjustedIcon.bottom + options.iconToScoreDisplayYSpace;
    buttonContent.addChild( adjustedIcon );
    buttonContent.addChild( scoreDisplayBackground );
    buttonContent.addChild( scoreDisplay );

    // Keep the score display centered when its bounds change
    var scoreDisplayUpdateLayout = function() {
      scoreDisplay.center = scoreDisplayBackground.center;
    };
    scoreDisplay.on( 'bounds', scoreDisplayUpdateLayout );
    scoreDisplayUpdateLayout();

    // Create the button
    var button = new RectangularPushButton( {
      content: buttonContent,
      xMargin: options.buttonXMargin,
      yMargin: options.buttonYMargin,
      baseColor: options.baseColor,
      cornerRadius: options.cornerRadius,
      listener: options.listener,

      // TODO: if LevelSelectionItemNode changes to inheritance, this will have to change,
      // see https://github.com/phetsims/vegas/issues/56
      tandem: options.tandem.createTandem( 'button' )
    } );
    this.addChild( button );

    // Best time (optional), centered below the button, does not move when button is pressed
    if ( options.bestTimeProperty ) {
      var bestTimeNode = new Text( '', { font: options.bestTimeFont, fill: options.bestTimeFill } );
      this.addChild( bestTimeNode );
      options.bestTimeProperty.link( function( bestTime ) {
        bestTimeNode.text = ( bestTime ? GameTimer.formatTime( bestTime ) : '' );
        bestTimeNode.centerX = button.centerX;
        bestTimeNode.top = button.bottom + options.bestTimeYSpacing;
      } );
      if ( options.bestTimeVisibleProperty ) {
        options.bestTimeVisibleProperty.linkAttribute( bestTimeNode, 'visible' );
      }
    }

    // Pass options to parent class
    this.mutate( options );

    // @private
    this.disposeLevelSelectionItemNode = function() {
      if ( scoreDisplay.hasListener( 'bounds', scoreDisplayUpdateLayout ) ) {
        scoreDisplay.off( 'bounds', scoreDisplayUpdateLayout );
      }
    };
  }

  vegas.register( 'LevelSelectionItemNode', LevelSelectionItemNode );

  return inherit( Node, LevelSelectionItemNode, {

    // @public
    dispose: function() {
      this.disposeLevelSelectionItemNode();
      Node.prototype.dispose.call( this );
    }
  }, {
    /**
     * Creates a new icon with the same dimensions as the specified icon. The new icon will be scaled to fit,
     * and a background with the specified size may be added to ensure that the bounds of the returned node are correct.
     * @public
     *
     * @param {Node} icon
     * @param {Dimension2} size
     * @returns {Node}
     */
    createSizedImageNode: function( icon, size ) {
      icon.scale( Math.min( size.width / icon.bounds.width, size.height / icon.bounds.height ) );
      if ( Math.abs( icon.bounds.width - size.width ) < SCALING_TOLERANCE &&
           Math.abs( icon.bounds.height - size.height ) < SCALING_TOLERANCE ) {
        // The aspect ratio of the icon matched that of the specified size, so no padding is necessary.
        return icon;
      }
      // else padding is needed in either the horizontal or vertical direction.
      var background = Rectangle.dimension( size, { fill: null } );
      icon.center = background.center;
      background.addChild( icon );
      return background;
    },

    /**
     * Convenience function to create a LevelSelectionItemNode with a ScoreDisplayDiscreteStars.
     * @param {Node} icon
     * @param {Property.<number>} scoreProperty
     * @param {Object} [options] - see LevelSelectionItemNode and ScoreDisplayDiscreteStars
     * @public
     * @static
     */
    createWithScoreDisplayDiscreteStars: function( icon, scoreProperty, options ) {

      options = _.extend( {
        listener: null, // {function|null} called when the button is pressed
        scoreDisplayOptions: null // see ScoreDisplayDiscreteStars options
      }, options );

      var scoreDisplay = new ScoreDisplayDiscreteStars( scoreProperty, options.scoreDisplayOptions );

      return new LevelSelectionItemNode( icon, scoreDisplay, _.omit( options, [ 'scoreDisplayOptions' ] ) );
    },

    /**
     * Convenience function to create a LevelSelectionItemNode with a ScoreDisplayNumberAndStar.
     * @param {Node} icon
     * @param {Property.<number>} scoreProperty
     * @param {Object} [options] - see LevelSelectionItemNode and ScoreDisplayNumberAndStar
     * @public
     * @static
     */
    createWithScoreDisplayNumberAndStar: function( icon, scoreProperty, options ) {

      options = _.extend( {
        listener: null, // {function|null} called when the button is pressed
        scoreDisplayOptions: null // see ScoreDisplayNumberAndStar options
      }, options );

      var scoreDisplay = new ScoreDisplayNumberAndStar( scoreProperty, options.scoreDisplayOptions );

      return new LevelSelectionItemNode( icon, scoreDisplay, _.omit( options, [ 'scoreDisplayOptions' ] ) );
    },

    /**
     * Convenience function to create a LevelSelectionItemNode with a ScoreDisplayTextAndNumber.
     * @param {Node} icon
     * @param {Property.<number>} scoreProperty
     * @param {Object} [options] - see LevelSelectionItemNode and ScoreDisplayTextAndNumber
     * @public
     * @static
     */
    createWithScoreDisplayTextAndNumber: function( icon, scoreProperty, options ) {

      options = _.extend( {
        listener: null, // {function|null} called when the button is pressed
        scoreDisplayOptions: null // see ScoreDisplayTextAndNumber options
      }, options );

      var scoreDisplay = new ScoreDisplayTextAndNumber( scoreProperty, options.scoreDisplayOptions );

      return new LevelSelectionItemNode( icon, scoreDisplay, _.omit( options, [ 'scoreDisplayOptions' ] ) );
    }
  } );
} );<commit_msg>clean up layout, #59<commit_after>// Copyright 2014-2018, University of Colorado Boulder

/**
 * Button for selecting a game level.
 * Also depicts the progress made on each level.
 * See specification in https://github.com/phetsims/vegas/issues/59.
 *
 * @author John Blanco
 * @author Chris Malley
 * @author Andrea Lin
 */
define( function( require ) {
  'use strict';

  // modules
  var Dimension2 = require( 'DOT/Dimension2' );
  var GameTimer = require( 'VEGAS/GameTimer' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Node = require( 'SCENERY/nodes/Node' );
  var PhetFont = require( 'SCENERY_PHET/PhetFont' );
  var ScoreDisplayDiscreteStars = require( 'VEGAS/ScoreDisplayDiscreteStars' );
  var ScoreDisplayNumberAndStar = require( 'VEGAS/ScoreDisplayNumberAndStar' );
  var ScoreDisplayTextAndNumber = require( 'VEGAS/ScoreDisplayTextAndNumber' );
  var Rectangle = require( 'SCENERY/nodes/Rectangle' );
  var RectangularPushButton = require( 'SUN/buttons/RectangularPushButton' );
  var Tandem = require( 'TANDEM/Tandem' );
  var Text = require( 'SCENERY/nodes/Text' );
  var vegas = require( 'VEGAS/vegas' );

  // constants
  var SCALING_TOLERANCE = 1E-4; // Empirically chosen as something the human eye is unlikely to notice.

  /**
   * @param {Node} icon Scenery node that appears on the button above the score display, scaled to fit
   * @param {Node} scoreDisplay - displays the score
   * @param {Object} [options]
   * @constructor
   */
  function LevelSelectionItemNode( icon, scoreDisplay, options ) {

    assert && assert( icon instanceof Node );

    options = _.extend( {

      // score display type
      numStars: 1,

      listener: null, // {function}

      // button size and appearance
      buttonWidth: 150,
      buttonHeight: 150,
      cornerRadius: 10,
      baseColor: 'rgb( 242, 255, 204 )',
      buttonXMargin: 10,
      buttonYMargin: 10,

      // layout of scoreDisplay
      scoreDisplayProportion: 0.2, // percentage of the button height occupied by scoreDisplay, (0,0.5]
      scoreDisplayMinXMargin: 10, // horizontal margin between scoreDisplay and its background
      scoreDisplayMinYMargin: 5,  // vertical margin between scoreDisplay and its background
      iconToScoreDisplayYSpace: 10, // vertical space between icon and score display

      // best time (optional)
      bestTimeProperty: null, // null if no best time || {Property.<number>} best time in seconds
      bestTimeVisibleProperty: null, // null || Property.<boolean>} controls visibility of best time
      bestTimeFill: 'black',
      bestTimeFont: new PhetFont( 24 ),
      bestTimeYSpacing: 10,  // vertical space between drop shadow and best time

      // Tandem
      tandem: Tandem.required
    }, options );

    Node.call( this );

    assert && assert(
    options.scoreDisplayProportion > 0 && options.scoreDisplayProportion <= 0.5,
      'scoreDisplayProportion value out of range'
    );

    var maxContentWidth = options.buttonWidth - 2 * options.buttonXMargin;

    // Background behind scoreDisplay
    var scoreDisplayBackgroundHeight = options.buttonHeight * options.scoreDisplayProportion;
    var scoreDisplayBackground = new Rectangle( 0, 0, maxContentWidth, scoreDisplayBackgroundHeight, {
      cornerRadius: options.cornerRadius,
        fill: 'white',
        stroke: 'black',
        lineWidth: 1,
        pickable: false
      } );

    // constrain scoreDisplay to fit in scoreDisplayBackground
    scoreDisplay.maxWidth = scoreDisplayBackground.width - ( 2 * options.scoreDisplayMinXMargin );
    scoreDisplay.maxHeight = scoreDisplayBackground.height - ( 2 * options.scoreDisplayMinYMargin );

    // Icon, scaled and padded to fit and to make the button size correct.
    var iconHeight = options.buttonHeight - scoreDisplayBackground.height - 2 * options.buttonYMargin - options.iconToScoreDisplayYSpace;
    var iconSize = new Dimension2( maxContentWidth, iconHeight );
    var adjustedIcon = LevelSelectionItemNode.createSizedImageNode( icon, iconSize );
    adjustedIcon.centerX = scoreDisplayBackground.centerX;
    adjustedIcon.bottom = scoreDisplayBackground.top - options.iconToScoreDisplayYSpace;

    // Keep scoreDisplay centered in its background when its bounds change
    var scoreDisplayUpdateLayout = function() {
      scoreDisplay.center = scoreDisplayBackground.center;
    };
    scoreDisplay.on( 'bounds', scoreDisplayUpdateLayout );
    scoreDisplayUpdateLayout();

    // Create the button
    var button = new RectangularPushButton( {
      content: new Node( { children: [ adjustedIcon, scoreDisplayBackground, scoreDisplay ] } ),
      xMargin: options.buttonXMargin,
      yMargin: options.buttonYMargin,
      baseColor: options.baseColor,
      cornerRadius: options.cornerRadius,
      listener: options.listener,

      // TODO: if LevelSelectionItemNode changes to inheritance, this will have to change,
      // see https://github.com/phetsims/vegas/issues/56
      tandem: options.tandem.createTandem( 'button' )
    } );
    this.addChild( button );

    // Best time (optional), centered below the button, does not move when button is pressed
    if ( options.bestTimeProperty ) {
      var bestTimeNode = new Text( '', { font: options.bestTimeFont, fill: options.bestTimeFill } );
      this.addChild( bestTimeNode );
      options.bestTimeProperty.link( function( bestTime ) {
        bestTimeNode.text = ( bestTime ? GameTimer.formatTime( bestTime ) : '' );
        bestTimeNode.centerX = button.centerX;
        bestTimeNode.top = button.bottom + options.bestTimeYSpacing;
      } );
      if ( options.bestTimeVisibleProperty ) {
        options.bestTimeVisibleProperty.linkAttribute( bestTimeNode, 'visible' );
      }
    }

    // Pass options to parent class
    this.mutate( options );

    // @private
    this.disposeLevelSelectionItemNode = function() {
      if ( scoreDisplay.hasListener( 'bounds', scoreDisplayUpdateLayout ) ) {
        scoreDisplay.off( 'bounds', scoreDisplayUpdateLayout );
      }
    };
  }

  vegas.register( 'LevelSelectionItemNode', LevelSelectionItemNode );

  return inherit( Node, LevelSelectionItemNode, {

    // @public
    dispose: function() {
      this.disposeLevelSelectionItemNode();
      Node.prototype.dispose.call( this );
    }
  }, {
    /**
     * Creates a new icon with the same dimensions as the specified icon. The new icon will be scaled to fit,
     * and a background with the specified size may be added to ensure that the bounds of the returned node are correct.
     * @public
     *
     * @param {Node} icon
     * @param {Dimension2} size
     * @returns {Node}
     */
    createSizedImageNode: function( icon, size ) {
      icon.scale( Math.min( size.width / icon.bounds.width, size.height / icon.bounds.height ) );
      if ( Math.abs( icon.bounds.width - size.width ) < SCALING_TOLERANCE &&
           Math.abs( icon.bounds.height - size.height ) < SCALING_TOLERANCE ) {
        // The aspect ratio of the icon matched that of the specified size, so no padding is necessary.
        return icon;
      }
      // else padding is needed in either the horizontal or vertical direction.
      var background = Rectangle.dimension( size, { fill: null } );
      icon.center = background.center;
      background.addChild( icon );
      return background;
    },

    /**
     * Convenience function to create a LevelSelectionItemNode with a ScoreDisplayDiscreteStars.
     * @param {Node} icon
     * @param {Property.<number>} scoreProperty
     * @param {Object} [options] - see LevelSelectionItemNode and ScoreDisplayDiscreteStars
     * @public
     * @static
     */
    createWithScoreDisplayDiscreteStars: function( icon, scoreProperty, options ) {

      options = _.extend( {
        listener: null, // {function|null} called when the button is pressed
        scoreDisplayOptions: null // see ScoreDisplayDiscreteStars options
      }, options );

      var scoreDisplay = new ScoreDisplayDiscreteStars( scoreProperty, options.scoreDisplayOptions );

      return new LevelSelectionItemNode( icon, scoreDisplay, _.omit( options, [ 'scoreDisplayOptions' ] ) );
    },

    /**
     * Convenience function to create a LevelSelectionItemNode with a ScoreDisplayNumberAndStar.
     * @param {Node} icon
     * @param {Property.<number>} scoreProperty
     * @param {Object} [options] - see LevelSelectionItemNode and ScoreDisplayNumberAndStar
     * @public
     * @static
     */
    createWithScoreDisplayNumberAndStar: function( icon, scoreProperty, options ) {

      options = _.extend( {
        listener: null, // {function|null} called when the button is pressed
        scoreDisplayOptions: null // see ScoreDisplayNumberAndStar options
      }, options );

      var scoreDisplay = new ScoreDisplayNumberAndStar( scoreProperty, options.scoreDisplayOptions );

      return new LevelSelectionItemNode( icon, scoreDisplay, _.omit( options, [ 'scoreDisplayOptions' ] ) );
    },

    /**
     * Convenience function to create a LevelSelectionItemNode with a ScoreDisplayTextAndNumber.
     * @param {Node} icon
     * @param {Property.<number>} scoreProperty
     * @param {Object} [options] - see LevelSelectionItemNode and ScoreDisplayTextAndNumber
     * @public
     * @static
     */
    createWithScoreDisplayTextAndNumber: function( icon, scoreProperty, options ) {

      options = _.extend( {
        listener: null, // {function|null} called when the button is pressed
        scoreDisplayOptions: null // see ScoreDisplayTextAndNumber options
      }, options );

      var scoreDisplay = new ScoreDisplayTextAndNumber( scoreProperty, options.scoreDisplayOptions );

      return new LevelSelectionItemNode( icon, scoreDisplay, _.omit( options, [ 'scoreDisplayOptions' ] ) );
    }
  } );
} );<|endoftext|>


<commit_before>function pageViewModel(gvm) {
    // projecttitle
    gvm.projecttitle = ko.observable("");
    gvm.projectId = $("#projectHeader").data('value');

    // Page specific i18n bindings
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("ProjectTitle") + ": " + gvm.projecttitle();}, gvm);
    gvm.pageHeader = ko.observable("Project");
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);
    gvm.projectDescription = ko.observable("Description");

    gvm.firstNameTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("firstNameTableTitle");}, gvm);
    gvm.lastNameTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("lastNameTableTitle");}, gvm);
    gvm.actionTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ActionTableTitle");}, gvm);

    gvm.scoreTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("scoreTableTitle")});
    gvm.filesTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("filesTableTitle")});

    gvm.searchStudent = ko.observable("");
    //gvm.totalCompleted = ko.observable("");
    gvm.totalStudents = ko.observable();

    gvm.getProjectInfo = function() {
        $.getJSON('/api/project/' + gvm.projectId, function(data) {
            gvm.pageHeader(data[0].code + ' - ' + data[0].name);
            gvm.projectDescription(data[0].description);
        });
    };

    gvm.getStudentList = function() {
        $.getJSON('/api/project/' + gvm.projectId + '/students/', function(data) {
            $.each(data, function(i, item) {

                $.getJSON('/api/project/' + gvm.projectid  + '/student/' + item.id + '/assessed', function(data)
                {
                    viewModel.users.removeAll();
                    data.forEach(function(element)
                    {
                        viewModel.users.push(element.firstname + " " + element.lastname);
                    });

                    viewModel.addTableData(item.id, item.firstname, item.lastname, item.mail, viewModel.users().length);
                });
            });
        });
    };

    gvm.users = ko.observableArray([]);

    gvm.assassedUsers = ko.observableArray([]);

    gvm.tabledata = ko.observableArray([]);

    gvm.tempTableData = ko.observableArray([]);

    // Add data to the table
    gvm.addTableData = function(id, firstname, lastname, email, countAssessed, completedStatus) {
        // Push data
        var data = countAssessed;
        var completed = false;

        var tblOject = {tid: id, tfirstname: firstname, tlastname: lastname, tScoreTableBtn: gvm.scoreTableTitle, tFilesTableBtn: gvm.filesTableTitle, tpid: gvm.projectId, email: email, tcountAssessed: data, tAssessedCompleted: completedStatus};
        gvm.tabledata.push(tblOject);
    };

    gvm.clearTable = function() {
        gvm.tabledata.removeAll();
    };

    /*gvm.getAllData = function() {
        $.getJSON('/api/project/getAllData/' + $("#projectHeader").data('value'), function(data) {
            console.log(data);
        });
    }*/
}

function initPage() {
    getStudentListBis();
    viewModel.getProjectInfo();
    //viewModel.getStudentList();

    $("#searchField").bind("keypress", {}, keypressInBox);
}

function keypressInBox(e) {
    var code = (e.keyCode ? e.keyCode : e.which);
    if (code == 13) { //Enter keycode
        $("#searchField").blur();
        getStudentByName();

    }
}

function createPDF(id,name,lastname,email, projectheader, projectdescription)
{
    /*$.getJSON('/api/finalscore/' + viewModel.projectId + '/' + id, function (data) {
        makePDF(id,name,lastname,email,projectheader,projectdescription,data);
        //console.log(data);
    });*/

    $.ajax({
        url: '/api/finalscore/' + viewModel.projectId + '/' + id,
        type: "GET",
        dataType: 'json',
        success: function(data) {
            makePDF(id,name,lastname,email,projectheader,projectdescription,data);
        },
        error: function()
        {
            alert("Please make sure points are given!");
        }
    });
}

function getStudentByName(){

    if(viewModel.tempTableData().length == 0) {
        viewModel.tempTableData(viewModel.tabledata.slice(0));
    }

    viewModel.tabledata([]);

    viewModel.tempTableData().forEach(function(item, element){
        var fullname = item.tfirstname + " " + item.tlastname;
        var fullnameReverse = item.tlastname + " " + item.tfirstname;

        if (item.tfirstname.toLowerCase().contains(viewModel.searchStudent().toLowerCase()) || item.tlastname.toLowerCase().contains(viewModel.searchStudent().toLowerCase()) || fullname.toLowerCase().contains(viewModel.searchStudent().toLowerCase()) || fullnameReverse.toLowerCase().contains(viewModel.searchStudent().toLowerCase())){
            viewModel.tabledata.push(item);
        }
    });
}

function showFullList()
{
    viewModel.searchStudent = ko.observable("");
    getStudentByName();
}

function getData(id)
{
    $.getJSON('/api/project/' + viewModel.projectId  + '/student/' + id + '/assessed', function(data)
    {
        viewModel.users.removeAll();
        data.forEach(function(element)
        {
            viewModel.users.push(element.firstname + " " + element.lastname);
        });
    });

    return viewModel.users();
}

function getNrOfAssessing(){
    $.ajax({
        url: '/api/project/nrOfAssessing/' + viewModel.projectId ,
        type: "GET",
        dataType: 'json',
        success: function(data) {
            data.forEach(function(item)
            {
                return item.nrOfAssessing;
            });        },
        error: function()
        {
            alert("Ooops...");
        }
    });
}

function getDataCount(projectid, id)
{
    $.getJSON('/api/project/' + projectid  + '/student/' + id + '/assessed', function(data)
    {
        viewModel.users.removeAll();
        data.forEach(function(element)
        {
            viewModel.users.push(element.firstname + " " + element.lastname);
        });

        return viewModel.users().length;
    });
}

var getStudentListBis = function() {
    $.getJSON('/api/project/' + viewModel.projectId + '/students', function(data) {
        data.forEach(function(element){
            viewModel.addTableData(element.id, element.firstname, element.lastname, element.mail, element.assessCount, element.assessCompleted);
        });

        viewModel.totalStudents = viewModel.tabledata().length;
        alert(viewModel.totalStudents);
    });
};
<commit_msg>Completed / Total<commit_after>function pageViewModel(gvm) {
    // projecttitle
    gvm.projecttitle = ko.observable("");
    gvm.projectId = $("#projectHeader").data('value');

    // Page specific i18n bindings
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("ProjectTitle") + ": " + gvm.projecttitle();}, gvm);
    gvm.pageHeader = ko.observable("Project");
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);
    gvm.projectDescription = ko.observable("Description");

    gvm.firstNameTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("firstNameTableTitle");}, gvm);
    gvm.lastNameTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("lastNameTableTitle");}, gvm);
    gvm.actionTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ActionTableTitle");}, gvm);

    gvm.scoreTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("scoreTableTitle")});
    gvm.filesTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("filesTableTitle")});

    gvm.searchStudent = ko.observable("");
    //gvm.totalCompleted = ko.observable("");
    gvm.totalStudents = ko.observable();

    gvm.getProjectInfo = function() {
        $.getJSON('/api/project/' + gvm.projectId, function(data) {
            gvm.pageHeader(data[0].code + ' - ' + data[0].name);
            gvm.projectDescription(data[0].description);
        });
    };

    gvm.getStudentList = function() {
        $.getJSON('/api/project/' + gvm.projectId + '/students/', function(data) {
            $.each(data, function(i, item) {

                $.getJSON('/api/project/' + gvm.projectid  + '/student/' + item.id + '/assessed', function(data)
                {
                    viewModel.users.removeAll();
                    data.forEach(function(element)
                    {
                        viewModel.users.push(element.firstname + " " + element.lastname);
                    });

                    viewModel.addTableData(item.id, item.firstname, item.lastname, item.mail, viewModel.users().length);
                });
            });
        });
    };

    gvm.users = ko.observableArray([]);

    gvm.assassedUsers = ko.observableArray([]);

    gvm.tabledata = ko.observableArray([]);

    gvm.tempTableData = ko.observableArray([]);

    // Add data to the table
    gvm.addTableData = function(id, firstname, lastname, email, countAssessed, completedStatus) {
        // Push data
        var data = countAssessed;
        var completed = false;

        var tblOject = {tid: id, tfirstname: firstname, tlastname: lastname, tScoreTableBtn: gvm.scoreTableTitle, tFilesTableBtn: gvm.filesTableTitle, tpid: gvm.projectId, email: email, tcountAssessed: data, tAssessedCompleted: completedStatus};
        gvm.tabledata.push(tblOject);
    };

    gvm.clearTable = function() {
        gvm.tabledata.removeAll();
    };

    /*gvm.getAllData = function() {
        $.getJSON('/api/project/getAllData/' + $("#projectHeader").data('value'), function(data) {
            console.log(data);
        });
    }*/
}

function initPage() {
    getStudentListBis();
    viewModel.getProjectInfo();
    //viewModel.getStudentList();

    $("#searchField").bind("keypress", {}, keypressInBox);

    alert("students: " + viewModel.totalStudents);
}

function keypressInBox(e) {
    var code = (e.keyCode ? e.keyCode : e.which);
    if (code == 13) { //Enter keycode
        $("#searchField").blur();
        getStudentByName();

    }
}

function createPDF(id,name,lastname,email, projectheader, projectdescription)
{
    /*$.getJSON('/api/finalscore/' + viewModel.projectId + '/' + id, function (data) {
        makePDF(id,name,lastname,email,projectheader,projectdescription,data);
        //console.log(data);
    });*/

    $.ajax({
        url: '/api/finalscore/' + viewModel.projectId + '/' + id,
        type: "GET",
        dataType: 'json',
        success: function(data) {
            makePDF(id,name,lastname,email,projectheader,projectdescription,data);
        },
        error: function()
        {
            alert("Please make sure points are given!");
        }
    });
}

function getStudentByName(){

    if(viewModel.tempTableData().length == 0) {
        viewModel.tempTableData(viewModel.tabledata.slice(0));
    }

    viewModel.tabledata([]);

    viewModel.tempTableData().forEach(function(item, element){
        var fullname = item.tfirstname + " " + item.tlastname;
        var fullnameReverse = item.tlastname + " " + item.tfirstname;

        if (item.tfirstname.toLowerCase().contains(viewModel.searchStudent().toLowerCase()) || item.tlastname.toLowerCase().contains(viewModel.searchStudent().toLowerCase()) || fullname.toLowerCase().contains(viewModel.searchStudent().toLowerCase()) || fullnameReverse.toLowerCase().contains(viewModel.searchStudent().toLowerCase())){
            viewModel.tabledata.push(item);
        }
    });
}

function showFullList()
{
    viewModel.searchStudent = ko.observable("");
    getStudentByName();
}

function getData(id)
{
    $.getJSON('/api/project/' + viewModel.projectId  + '/student/' + id + '/assessed', function(data)
    {
        viewModel.users.removeAll();
        data.forEach(function(element)
        {
            viewModel.users.push(element.firstname + " " + element.lastname);
        });
    });

    return viewModel.users();
}

function getNrOfAssessing(){
    $.ajax({
        url: '/api/project/nrOfAssessing/' + viewModel.projectId ,
        type: "GET",
        dataType: 'json',
        success: function(data) {
            data.forEach(function(item)
            {
                return item.nrOfAssessing;
            });        },
        error: function()
        {
            alert("Ooops...");
        }
    });
}

function getDataCount(projectid, id)
{
    $.getJSON('/api/project/' + projectid  + '/student/' + id + '/assessed', function(data)
    {
        viewModel.users.removeAll();
        data.forEach(function(element)
        {
            viewModel.users.push(element.firstname + " " + element.lastname);
        });

        return viewModel.users().length;
    });
}

var getStudentListBis = function() {
    $.getJSON('/api/project/' + viewModel.projectId + '/students', function(data) {
        data.forEach(function(element){
            viewModel.addTableData(element.id, element.firstname, element.lastname, element.mail, element.assessCount, element.assessCompleted);
        });

        viewModel.totalStudents = viewModel.tabledata().length;
        alert(viewModel.totalStudents);
    });
};
<|endoftext|>


<commit_before>function pageViewModel(gvm) {
    // projecttitle
    gvm.projecttitle = ko.observable("");
    gvm.projectId = $("#projectHeader").data('value');

    // Page specific i18n bindings
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("ProjectTitle") + ": " + gvm.projecttitle();}, gvm);
    gvm.pageHeader = ko.observable("Project");
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);
    gvm.projectDescription = ko.observable("Description");

    gvm.firstNameTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("firstNameTableTitle");}, gvm);
    gvm.lastNameTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("lastNameTableTitle");}, gvm);
    gvm.actionTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ActionTableTitle");}, gvm);

    gvm.scoreTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("scoreTableTitle")});
    gvm.filesTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("filesTableTitle")});

    gvm.getProjectInfo = function() {
        $.getJSON('/api/project/' + gvm.projectId, function(data) {
            gvm.pageHeader(data[0].code + ' - ' + data[0].name);
            gvm.projectDescription(data[0].description);
        });
    };

    gvm.getStudentList = function() {
        $.getJSON('/api/project/' + gvm.projectId + '/students', function(data) {
            $.each(data, function(i, item) {
                //console.log(item);
                viewModel.addTableData(item.id, item.firstname, item.lastname, item.mail);
            });
        });
    };

    gvm.users = ko.observableArray([]);

    gvm.tabledata = ko.observableArray([]);

    // Add data to the table
    gvm.addTableData = function(id, firstname, lastname, email) {
        // Push data
        var tblOject = {tid: id, tfirstname: firstname, tlastname: lastname, tScoreTableBtn: gvm.scoreTableTitle, tFilesTableBtn: gvm.filesTableTitle, tpid: gvm.projectId, email: email};
        gvm.tabledata.push(tblOject);
    };

    gvm.clearTable = function() {
        gvm.tabledata.removeAll();
    };

    /*gvm.getAllData = function() {
        $.getJSON('/api/project/getAllData/' + $("#projectHeader").data('value'), function(data) {
            console.log(data);
        });
    }*/
}

function initPage() {
    viewModel.getProjectInfo();
    viewModel.getStudentList();

    $('.popoverData').popover();

}

function createPDF(id,name,lastname,email, projectheader, projectdescription)
{
    $.getJSON('/api/finalscore/' + viewModel.projectId + '/' + id, function (data) {
        makePDF(id,name,lastname,email,projectheader,projectdescription,data);
        //console.log(data);
    });
}

function getData(id)
{
    $.getJSON('/api/project/' + viewModel.projectId  + '/student/' + id + '/assessed', function(data)
    {
        viewModel.users.empty();
        data.forEach(function(element)
        {
            viewModel.users.push(element.firstname + " " + element.lastname);
        });

    });
}<commit_msg>popup<commit_after>function pageViewModel(gvm) {
    // projecttitle
    gvm.projecttitle = ko.observable("");
    gvm.projectId = $("#projectHeader").data('value');

    // Page specific i18n bindings
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("ProjectTitle") + ": " + gvm.projecttitle();}, gvm);
    gvm.pageHeader = ko.observable("Project");
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);
    gvm.projectDescription = ko.observable("Description");

    gvm.firstNameTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("firstNameTableTitle");}, gvm);
    gvm.lastNameTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("lastNameTableTitle");}, gvm);
    gvm.actionTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ActionTableTitle");}, gvm);

    gvm.scoreTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("scoreTableTitle")});
    gvm.filesTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("filesTableTitle")});

    gvm.getProjectInfo = function() {
        $.getJSON('/api/project/' + gvm.projectId, function(data) {
            gvm.pageHeader(data[0].code + ' - ' + data[0].name);
            gvm.projectDescription(data[0].description);
        });
    };

    gvm.getStudentList = function() {
        $.getJSON('/api/project/' + gvm.projectId + '/students', function(data) {
            $.each(data, function(i, item) {
                //console.log(item);
                viewModel.addTableData(item.id, item.firstname, item.lastname, item.mail);
            });
        });
    };

    gvm.users = ko.observableArray([]);

    gvm.tabledata = ko.observableArray([]);

    // Add data to the table
    gvm.addTableData = function(id, firstname, lastname, email) {
        // Push data
        var tblOject = {tid: id, tfirstname: firstname, tlastname: lastname, tScoreTableBtn: gvm.scoreTableTitle, tFilesTableBtn: gvm.filesTableTitle, tpid: gvm.projectId, email: email};
        gvm.tabledata.push(tblOject);
    };

    gvm.clearTable = function() {
        gvm.tabledata.removeAll();
    };

    /*gvm.getAllData = function() {
        $.getJSON('/api/project/getAllData/' + $("#projectHeader").data('value'), function(data) {
            console.log(data);
        });
    }*/
}

function initPage() {
    viewModel.getProjectInfo();
    viewModel.getStudentList();

    $('.popoverData').popover();

}

function createPDF(id,name,lastname,email, projectheader, projectdescription)
{
    $.getJSON('/api/finalscore/' + viewModel.projectId + '/' + id, function (data) {
        makePDF(id,name,lastname,email,projectheader,projectdescription,data);
        //console.log(data);
    });
}

function getData(id)
{
    $.getJSON('/api/project/' + viewModel.projectId  + '/student/' + id + '/assessed', function(data)
    {
        viewModel.users.removeAll();
        console.log(viewModel.users);
        data.forEach(function(element)
        {
            viewModel.users.push(element.firstname + " " + element.lastname);
        });

    });
}<|endoftext|>