<commit_before>#!/usr/bin/env node

// process.title is read-only on OSX / darwin.
// but generally, I'll be the only user on an OSX system, so whatever.
process.title = 'guts';

var http = require('http');
var util = require('util');
var fs = require('fs');
var path = require('path');
var async = require('async');

var common = require('tillberg_common');
var _ = require('underscore')._;
_.mixin(require('underscore.string'));

var remoteUser = process.argv[2];
var remoteHost = process.argv[3];
var remoteFolder = process.argv[4];

var HTTP_PORT = 3294;

if (remoteHost === 'auto') {
  remoteHost = process.env['SSH_CLIENT'].split(' ')[0];
  console.log('auto-detected original remote host of ' + remoteHost);
} else {
  var localUser = process.env['USER'];
  var cmd = 'cd ~/guts && git pull origin master;';//' killall -q node -u ' + localUser + ';';
  cmd = cmd + 'killall -q guts -u ' + localUser + '; killall -q gutsmon -u ' + localUser + '; sleep 2; ';
  cmd = cmd + 'cd ' + remoteFolder + ' && node ~/guts/lib/guts.js ' + localUser + ' auto ' + path.resolve('./');
  console.log(cmd);
  var args = [
     '-o',
     'StrictHostKeyChecking=no',
     remoteUser + '@' + remoteHost,
     cmd
  ];
  var proc = exec('ssh', args, { cwd: './' }, function(err) {
    console.log('ssh connection terminated.');
  });
  proc.stdout.on('line', function(d) {
    console.log('[remote] ' + d);
  });
}

function time() {
  return (new Date()).getTime();
}
function throttledAsync(cb, throttleDelay, invokeDelay) {
  var timeout
    , fire = false
    , lastfire = false
    , inflight = false;
  return function() {
    if (!timeout) {
      var nextDelay = throttleDelay - (time() - lastfire);
      function callIt() {
        lastfire = time();
        inflight = true;
        setTimeout(function() {
          cb(function() {
            inflight = false;
            if (fire) {
              fire = false;
              callIt();
            }
          });
        }, invokeDelay);
      }
      function tryToCall() {
        if (inflight) {
          fire = true;
        } else {
          callIt();
        }
      }
      if (nextDelay <= 0) {
        tryToCall();
      } else {
        timeout = setTimeout(function() {
          tryToCall();
          timeout = undefined;
        }, nextDelay);
      }
    }
  };
}

function needToPull() {
  console.log('need to pull');
  pull = true;
  onChange();
}

http.createServer(function (req, res) {
  needToPull();
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('OK\n');
}).listen(HTTP_PORT);

var initted = false;
var changed = [];
var removed = [];
var pull = false;

function madeACommit() {
  console.log('We made a new commit');
  exec('curl', ['-s', remoteHost + ':' + HTTP_PORT + '/'], { cwd: './' }, function(err) {});
}

function gutUp(done) {
  if (!initted) {
    initted = true;
    exec('gut', ['init'], { cwd: './', pipe: true }, function(err) {
      exec('gut', ['add', '.'], { cwd: './', pipe: true }, function(err) {
        exec('gut', ['commit', '-a', '-m', 'post-walk commit'], { cwd: './', pipe: true }, function(err) {
          done();
          madeACommit();
          needToPull();
        });
      });
    });
  } else if (pull) {
    pull = false;
    console.log('pulling...');
    exec('gut', ['remote', 'rm', 'origin'], { cwd: './' }, function(err) {
      exec('gut', ['remote', 'add', 'origin', remoteUser + '@' + remoteHost + ':' + remoteFolder], { cwd: './' }, function(err) {
          exec('gut', ['pull', 'origin', 'master'], { cwd: './', env: { GUT_SSH: path.join(__dirname, 'gut-ssh.sh') } }, function(err) {
          donePulling();
        });
      });
    })
    function donePulling() {
      if (changed.length || removed.length) {
        onChange();
      }
      done();
    }
  } else {
    var _changed = _.uniq(changed);
    var _removed = _.uniq(removed);
    changed = [];
    removed = [];
    function add() {
      function _add(f, cb) {
        info('gut-adding ' + f);
        exec('gut', ['add', f], { cwd: './', pipe: true }, function(err) { cb(); });
      }
      if (_changed.length) {
        async.forEachSeries(_changed, _add, commit);
      } else {
        commit();
      }
    }
    function remove() {
      function _remove(f, cb) {
        exec('gut', ['rm', '--cached'].concat(_removed), { cwd: './', pipe: true }, cb);
      }
      if (_removed.length) {
        async.forEachSeries(_removed, _remove, add);
      } else {
        add();
      }
    }
    function commit() {
      exec('gut', ['rev-parse', 'HEAD'], { cwd: './' }, function(err, data) {
        exec('gut', ['commit', '--untracked-files=no', '-a', '-m', 'autocommit'], { cwd: './', pipe: true }, function(err) {
          exec('gut', ['rev-parse', 'HEAD'], { cwd: './' }, function(err, data2) {
            if (data !== data2) {
              madeACommit();
            } else {
              console.log('We did not actually make a commit');
            }
            done();
          });
        });
      })
    }
    remove();
  }
}

var onChange = throttledAsync(gutUp, 1000, 100);
onChange();

console.log('starting monitor');
var monitor = exec(path.join(__dirname, 'monitor.py'), [path.resolve('./')], { cwd: './' }, function(err, data) {
  error('monitor exited');
});
monitor.stdout.on('line', function(line) {
  var match = (/(\w+) (.*)/).exec(line);
  var event = match[1];
  var filename = match[2];
  if (event === 'deleted') {
    removed.push(filename);
  } else {
    changed.push(path.dirname(filename));
  }
  onChange();
  info(line);
});
<commit_msg>Kill processes with the remote user's name, not the local user's name<commit_after>#!/usr/bin/env node

// process.title is read-only on OSX / darwin.
// but generally, I'll be the only user on an OSX system, so whatever.
process.title = 'guts';

var http = require('http');
var util = require('util');
var fs = require('fs');
var path = require('path');
var async = require('async');

var common = require('tillberg_common');
var _ = require('underscore')._;
_.mixin(require('underscore.string'));

var remoteUser = process.argv[2];
var remoteHost = process.argv[3];
var remoteFolder = process.argv[4];

var HTTP_PORT = 3294;

if (remoteHost === 'auto') {
  remoteHost = process.env['SSH_CLIENT'].split(' ')[0];
  console.log('auto-detected original remote host of ' + remoteHost);
} else {
  var localUser = process.env['USER'];
  var cmd = 'cd ~/guts && git pull origin master;';//' killall -q node -u ' + localUser + ';';
  cmd = cmd + 'killall -q guts -u ' + remoteUser + '; killall -q gutsmon -u ' + remoteUser + '; sleep 2; ';
  cmd = cmd + 'cd ' + remoteFolder + ' && node ~/guts/lib/guts.js ' + localUser + ' auto ' + path.resolve('./');
  console.log(cmd);
  var args = [
     '-o',
     'StrictHostKeyChecking=no',
     remoteUser + '@' + remoteHost,
     cmd
  ];
  var proc = exec('ssh', args, { cwd: './' }, function(err) {
    console.log('ssh connection terminated.');
  });
  proc.stdout.on('line', function(d) {
    console.log('[remote] ' + d);
  });
}

function time() {
  return (new Date()).getTime();
}
function throttledAsync(cb, throttleDelay, invokeDelay) {
  var timeout
    , fire = false
    , lastfire = false
    , inflight = false;
  return function() {
    if (!timeout) {
      var nextDelay = throttleDelay - (time() - lastfire);
      function callIt() {
        lastfire = time();
        inflight = true;
        setTimeout(function() {
          cb(function() {
            inflight = false;
            if (fire) {
              fire = false;
              callIt();
            }
          });
        }, invokeDelay);
      }
      function tryToCall() {
        if (inflight) {
          fire = true;
        } else {
          callIt();
        }
      }
      if (nextDelay <= 0) {
        tryToCall();
      } else {
        timeout = setTimeout(function() {
          tryToCall();
          timeout = undefined;
        }, nextDelay);
      }
    }
  };
}

function needToPull() {
  console.log('need to pull');
  pull = true;
  onChange();
}

http.createServer(function (req, res) {
  needToPull();
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('OK\n');
}).listen(HTTP_PORT);

var initted = false;
var changed = [];
var removed = [];
var pull = false;

function madeACommit() {
  console.log('We made a new commit');
  exec('curl', ['-s', remoteHost + ':' + HTTP_PORT + '/'], { cwd: './' }, function(err) {});
}

function gutUp(done) {
  if (!initted) {
    initted = true;
    exec('gut', ['init'], { cwd: './', pipe: true }, function(err) {
      exec('gut', ['add', '.'], { cwd: './', pipe: true }, function(err) {
        exec('gut', ['commit', '-a', '-m', 'post-walk commit'], { cwd: './', pipe: true }, function(err) {
          done();
          madeACommit();
          needToPull();
        });
      });
    });
  } else if (pull) {
    pull = false;
    console.log('pulling...');
    exec('gut', ['remote', 'rm', 'origin'], { cwd: './' }, function(err) {
      exec('gut', ['remote', 'add', 'origin', remoteUser + '@' + remoteHost + ':' + remoteFolder], { cwd: './' }, function(err) {
          exec('gut', ['pull', 'origin', 'master'], { cwd: './', env: { GUT_SSH: path.join(__dirname, 'gut-ssh.sh') } }, function(err) {
          donePulling();
        });
      });
    })
    function donePulling() {
      if (changed.length || removed.length) {
        onChange();
      }
      done();
    }
  } else {
    var _changed = _.uniq(changed);
    var _removed = _.uniq(removed);
    changed = [];
    removed = [];
    function add() {
      function _add(f, cb) {
        info('gut-adding ' + f);
        exec('gut', ['add', f], { cwd: './', pipe: true }, function(err) { cb(); });
      }
      if (_changed.length) {
        async.forEachSeries(_changed, _add, commit);
      } else {
        commit();
      }
    }
    function remove() {
      function _remove(f, cb) {
        exec('gut', ['rm', '--cached'].concat(_removed), { cwd: './', pipe: true }, cb);
      }
      if (_removed.length) {
        async.forEachSeries(_removed, _remove, add);
      } else {
        add();
      }
    }
    function commit() {
      exec('gut', ['rev-parse', 'HEAD'], { cwd: './' }, function(err, data) {
        exec('gut', ['commit', '--untracked-files=no', '-a', '-m', 'autocommit'], { cwd: './', pipe: true }, function(err) {
          exec('gut', ['rev-parse', 'HEAD'], { cwd: './' }, function(err, data2) {
            if (data !== data2) {
              madeACommit();
            } else {
              console.log('We did not actually make a commit');
            }
            done();
          });
        });
      })
    }
    remove();
  }
}

var onChange = throttledAsync(gutUp, 1000, 100);
onChange();

console.log('starting monitor');
var monitor = exec(path.join(__dirname, 'monitor.py'), [path.resolve('./')], { cwd: './' }, function(err, data) {
  error('monitor exited');
});
monitor.stdout.on('line', function(line) {
  var match = (/(\w+) (.*)/).exec(line);
  var event = match[1];
  var filename = match[2];
  if (event === 'deleted') {
    removed.push(filename);
  } else {
    changed.push(path.dirname(filename));
  }
  onChange();
  info(line);
});
<|endoftext|>


<commit_before>/*!
 * Copyright 2002 - 2014 Webdetails, a Pentaho company.  All rights reserved.
 *
 * This software was developed by Webdetails and is provided under the terms
 * of the Mozilla Public License, Version 2.0, or any later version. You may not use
 * this file except in compliance with the license. If you need a copy of the license,
 * please go to  http://mozilla.org/MPL/2.0/. The Initial Developer is Webdetails.
 *
 * Software distributed under the Mozilla Public License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or  implied. Please refer to
 * the license for the specific language governing your rights and limitations.
 */

define(['./Dashboard', 'amd!../lib/backbone', '../lib/mustache', '../Logger', '../lib/jquery'],
  function(Dashboard, Backbone, Mustache, Logger, $) {
  /**
   * A module representing a extension to Dashboard module for storage.
   * @module Dashboard.components
   */
  Dashboard.implement({

    /**
     * Method used by the Dashboard constructor for components initialization
     * @method _initComponents
     * @for Dashboard
     * @private
     */
    _initComponents: function() {
      this.components = [];
    },

    /**
     * Gets the component with a given name
     *
     * @method getComponent
     * @for Dashboard
     * @param name of the component
     * @returns the component or undefined if it does not exists
     */
    getComponent: function(name) {
      for(var i in this.components) {
        if(this.components[i].name == name) {
          return this.components[i];
        }
      }
    },

    /**
     * Alias for  {{#crossLink "Dashboard/getComponent:method"}}getComponent{{/crossLink}}
     *
     * @method getComp
     * @for Dashboard
     * @param name of the component
     * @returns the component or undefined if it does not exists
     */
    getComp: function(name) {
      return this.getComponent(name);
    },

    /**
     * Alias for  {{#crossLink "Dashboard/getComponent:method"}}getComponent{{/crossLink}}
     *
     * @method getComponentByName
     * @for Dashboard
     * @param name of the component
     * @returns the component of undefined if it does not exists
     */
    getComponentByName: function(name) {
      if (this.globalContext) {
        return eval(name);
      } else {
        return this.getComponent(name);
      }
    },

    /**
     * Adds a set of components
     *
     * @method addComponents
     * @for Dashboard
     * @param components to add
     */
    addComponents: function(components) {
      components.forEach(function(component) { //TODO: review why addComponents just not calls addComponent
        this._bindControl(component);
        this.components.push(component);
      }, this);
    },

    /**
     * Add a component
     *
     * @method addComponent
     * @for Dashboard
     * @param component to add
     * @param options to append to the component
     */
    addComponent: function(component, options) {
      this.removeComponent(component);

      // Attempt to convert over to component implementation
      this._bindControl(component);

      var index = options && options.index;
      var L = this.components.length;
      if(index == null || index < 0 || index > L) { index = L; } // <=> push
      this.components[index] = component;
    },

    /**
     * Gets a component given a name or a index
     * @method getComponentIndex
     * @for Dashboard
     *
     * @param compOrNameOrIndex
     * @returns component index
     */
    getComponentIndex: function(compOrNameOrIndex) {
      if(compOrNameOrIndex != null) {
        switch(typeof compOrNameOrIndex) {
          case 'string':
            for(var i = 0, cs = this.components, L = cs.length ; i < L ; i++) {
              if(cs[i].name === compOrNameOrIndex) { return i; }
            }
            break;
          case 'number': //really?
            if(compOrNameOrIndex >= 0 && compOrNameOrIndex < this.components.length) {
              return compOrNameOrIndex;
            }
            break;

          default:
            return this.components.indexOf(compOrNameOrIndex);
        }
      }
      return -1;
    },

    /**
     * Remove a component
     *
     * @method removeComponent
     * @for Dashboard
     * @param compOrNameOrIndex
     * @returns the component removed
     */
    removeComponent: function(compOrNameOrIndex) {
      var index = this.getComponentIndex(compOrNameOrIndex);
      var comp = null;
      if(index >= 0) {
        var cs = this.components;
        comp = cs[index];
        cs.splice(index, 1);
        comp.dashboard = null;

        comp.off('cdf:postExecution');
        comp.off('cdf:preExecution');
        comp.off('cdf:error');
        comp.off('all');
      }

      return comp;
    },

    /**
     *
     * @param control
     * @private
     * @returns {*}
     */
    _bindControl: function(control) {

      if(!control.dashboard) {
        control.dashboard = this;
        // Add logging lifeCycle
        this._addLogLifecycleToControl(control);
      }
      return control;
    },

    /**
     *
     * @param control
     * @param Class
     * @private
     * @returns {*}
     *
     * @deprecated
     */
    _bindExistingControl: function(control, Class) {
      if(!control.dashboard) {
        control.dashboard = this;
        delete control.initInstance;

        // Ensure BaseComponent's methods
//          this._castControlToComponent(control, Class);

        // Make sure we clean all events in the case we're redefining the control.
        if(typeof control.off === "function") { control.off("all"); }

        // Endow it with the Backbone event system.
        if(!control.on) { $.extend(control, Backbone.Events); }

        // Add logging lifeCycle
        this._addLogLifecycleToControl(control);

        // For legacy dashboards, we'll automatically assign some priority for component execution.
        if(control.priority == null || control.priority === "") {
          control.priority = this.legacyPriority++;
        }
      }

      return control;
    },

    /**
     *
     * @param control
     * @param Class
     * @private
     */
    _castControlToClass: function(control, Class) {
      if(!(control instanceof Class)) {
        var controlImpl = this._makeInstance(Class);

        // Copy implementation into control
        $.extend(control, controlImpl);
      }
    },

    /**
     *
     * @param control
     * @returns {*}
     * @private
     */
    _getControlClass: function(control) {
      // see if there is a class defined for this control
      var typeName = control.type;
      if(typeof typeName === 'function') { typeName = typeName.call(control); } // <=> control.type() ; the _this_ in the call is _control_

      var TypeName = typeName.substring(0,1).toUpperCase() + typeName.substring(1);

      // try _TypeComponent_, _type_ and _Type_ as class names
      var typeNames = [TypeName + 'Component', typeName, TypeName];

      for(var i = 0, N = typeNames.length ; i < N ; i++) {
        // TODO: window represents access to the JS global object.
        // This, or a special object on which to eval types, should be provided by some FWK.

        // If the value of a name is not a function, keep on trying.
        var Class = window[typeNames[i]];
        if(Class && typeof Class === 'function') { return Class; }
      }
      // return undefined;
    },

    /**
     *
     * @param Class
     * @param args
     * @returns {Class}
     * @private
     */
    _makeInstance: function(Class, args) {
      var o = Object.create(Class.prototype);
      if(args) { Class.apply(o, args); } else { Class.apply(o); }
      return o;
    },

    /**
     *
     * @param control
     * @param Class
     * @private
     */
    _castControlToComponent: function(control, Class) {
      // Extend control with BaseComponent methods, if it's not an instance of it.
      // Also, avoid extending if _Class_ was already applied
      // and it is a subclass of BaseComponent.
      if(!(control instanceof BaseComponent)
        && (!Class || !(Class.prototype instanceof BaseComponent))) {

        var baseProto = BaseComponent.prototype;
        for(var p in baseProto) {
          if(baseProto.hasOwnProperty(p)
            && (control[p] === undefined)
            && (typeof baseProto[p] === 'function')) {

            switch(p) {
              // Exceptions
              case 'base':
                break;

              // Copy
              default:
                control[p] = baseProto[p];
                break;
            }
          }
        }
      }
    },

    /**
     *
     * @param control
     * @private
     */
    _addLogLifecycleToControl: function(control) {
      // TODO: Could the _typeof console !== "undefined"_ test be made beforehand,
      // to avoid always installing the catch-all handler?
      // The same could be said for the _this.logLifecycle_ test.
      // To still allow changing the value dynamically, a Dashboards.setLogLifecycle(.) method could be provided.

      // Add logging lifeCycle
      control.on("all", function(e) {
        var dashs = this.dashboard;
        if(dashs && dashs.logLifecycle && e !== "cdf"
          && this.name !== "PostInitMarker"
          && typeof console !== "undefined") {

          var eventStr;
          var eventName = e.substr(4);
          switch(eventName) {
            case "preExecution":  eventStr = ">Start"; break;
            case "postExecution": eventStr = "<End  "; break;
            case "error":         eventStr = "!Error"; break;
            default:              eventStr = "      "; break;
          }

          var timeInfo = Mustache.render("Timing: {{elapsedSinceStartDesc}} since start, {{elapsedSinceStartDesc}} since last event", this.splitTimer());
          console.log("%c          [Lifecycle " + eventStr + "] " + this.name + " [" + this.type + "]"  + " (P: " + this.priority + " ): " +
            eventName + " " + timeInfo + " (Running: "+ this.dashboard.runningCalls  + ")","color: " + this.getLogColor());
        }
      });
    }
  });

});
<commit_msg>[CDF-328] - Add support for Require.js in CDF 	- make addComponents call addComponent for each component 	- remove references to deprecated globalContext 	- validate if getComponent receives a valid input parameter<commit_after>/*!
 * Copyright 2002 - 2014 Webdetails, a Pentaho company.  All rights reserved.
 *
 * This software was developed by Webdetails and is provided under the terms
 * of the Mozilla Public License, Version 2.0, or any later version. You may not use
 * this file except in compliance with the license. If you need a copy of the license,
 * please go to  http://mozilla.org/MPL/2.0/. The Initial Developer is Webdetails.
 *
 * Software distributed under the Mozilla Public License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or  implied. Please refer to
 * the license for the specific language governing your rights and limitations.
 */

define(['./Dashboard', 'amd!../lib/backbone', '../lib/mustache', '../Logger', '../lib/jquery'],
  function(Dashboard, Backbone, Mustache, Logger, $) {
  /**
   * A module representing a extension to Dashboard module for storage.
   * @module Dashboard.components
   */
  Dashboard.implement({

    /**
     * Method used by the Dashboard constructor for components initialization
     * @method _initComponents
     * @for Dashboard
     * @private
     */
    _initComponents: function() {
      this.components = [];
    },

    /**
     * Gets the component with a given name
     *
     * @method getComponent
     * @for Dashboard
     * @param name of the component
     * @returns the component or undefined if it does not exists
     */
    getComponent: function(name) {
      if(!name) { return; }
      for(var i in this.components) {
        if(this.components[i].name == name) {
          return this.components[i];
        }
      }
    },

    /**
     * Alias for  {{#crossLink "Dashboard/getComponent:method"}}getComponent{{/crossLink}}
     *
     * @method getComp
     * @for Dashboard
     * @param name of the component
     * @returns the component or undefined if it does not exists
     */
    getComp: function(name) {
      return this.getComponent(name);
    },

    /**
     * Alias for  {{#crossLink "Dashboard/getComponent:method"}}getComponent{{/crossLink}}
     *
     * @method getComponentByName
     * @for Dashboard
     * @param name of the component
     * @returns the component of undefined if it does not exists
     */
    getComponentByName: function(name) {
        return this.getComponent(name);
    },

    /**
     * Adds a set of components
     *
     * @method addComponents
     * @for Dashboard
     * @param components to add
     */
    addComponents: function(components) {
      if(!$.isArray(components)) {
        Logger.warn('addComponents: components in a structure other than an array will not be added!');
        return;
      }
      components.forEach(function(component) {
        this.addComponent(component);
      }, this);
    },

    /**
     * Add a component
     *
     * @method addComponent
     * @for Dashboard
     * @param component to add
     * @param options to append to the component
     */
    addComponent: function(component, options) {
      this.removeComponent(component);

      // Attempt to convert over to component implementation
      this._bindControl(component);

      var index = options && options.index;
      var L = this.components.length;
      if(index == null || index < 0 || index > L) { index = L; } // <=> push
      this.components[index] = component;
    },

    /**
     * Gets a component given a name or a index
     * @method getComponentIndex
     * @for Dashboard
     *
     * @param compOrNameOrIndex
     * @returns component index
     */
    getComponentIndex: function(compOrNameOrIndex) {
      if(compOrNameOrIndex != null) {
        switch(typeof compOrNameOrIndex) {
          case 'string':
            for(var i = 0, cs = this.components, L = cs.length ; i < L ; i++) {
              if(cs[i].name === compOrNameOrIndex) { return i; }
            }
            break;
          case 'number': //really?
            if(compOrNameOrIndex >= 0 && compOrNameOrIndex < this.components.length) {
              return compOrNameOrIndex;
            }
            break;

          default:
            return this.components.indexOf(compOrNameOrIndex);
        }
      }
      return -1;
    },

    /**
     * Remove a component
     *
     * @method removeComponent
     * @for Dashboard
     * @param compOrNameOrIndex
     * @returns the component removed
     */
    removeComponent: function(compOrNameOrIndex) {
      var index = this.getComponentIndex(compOrNameOrIndex);
      var comp = null;
      if(index >= 0) {
        var cs = this.components;
        comp = cs[index];
        cs.splice(index, 1);
        comp.dashboard = null;

        comp.off('cdf:postExecution');
        comp.off('cdf:preExecution');
        comp.off('cdf:error');
        comp.off('all');
      }

      return comp;
    },

    /**
     *
     * @param control
     * @private
     * @returns {*}
     */
    _bindControl: function(control) {

      if(!control.dashboard) {
        control.dashboard = this;
        // Add logging lifeCycle
        this._addLogLifecycleToControl(control);
      }
      return control;
    },

    /**
     *
     * @param control
     * @param Class
     * @private
     * @returns {*}
     *
     * @deprecated
     */
    _bindExistingControl: function(control, Class) {
      if(!control.dashboard) {
        control.dashboard = this;
        delete control.initInstance;

        // Ensure BaseComponent's methods
//          this._castControlToComponent(control, Class);

        // Make sure we clean all events in the case we're redefining the control.
        if(typeof control.off === "function") { control.off("all"); }

        // Endow it with the Backbone event system.
        if(!control.on) { $.extend(control, Backbone.Events); }

        // Add logging lifeCycle
        this._addLogLifecycleToControl(control);

        // For legacy dashboards, we'll automatically assign some priority for component execution.
        if(control.priority == null || control.priority === "") {
          control.priority = this.legacyPriority++;
        }
      }

      return control;
    },

    /**
     *
     * @param control
     * @param Class
     * @private
     */
    _castControlToClass: function(control, Class) {
      if(!(control instanceof Class)) {
        var controlImpl = this._makeInstance(Class);

        // Copy implementation into control
        $.extend(control, controlImpl);
      }
    },

    /**
     *
     * @param control
     * @returns {*}
     * @private
     */
    _getControlClass: function(control) {
      // see if there is a class defined for this control
      var typeName = control.type;
      if(typeof typeName === 'function') { typeName = typeName.call(control); } // <=> control.type() ; the _this_ in the call is _control_

      var TypeName = typeName.substring(0,1).toUpperCase() + typeName.substring(1);

      // try _TypeComponent_, _type_ and _Type_ as class names
      var typeNames = [TypeName + 'Component', typeName, TypeName];

      for(var i = 0, N = typeNames.length ; i < N ; i++) {
        // TODO: window represents access to the JS global object.
        // This, or a special object on which to eval types, should be provided by some FWK.

        // If the value of a name is not a function, keep on trying.
        var Class = window[typeNames[i]];
        if(Class && typeof Class === 'function') { return Class; }
      }
      // return undefined;
    },

    /**
     *
     * @param Class
     * @param args
     * @returns {Class}
     * @private
     */
    _makeInstance: function(Class, args) {
      var o = Object.create(Class.prototype);
      if(args) { Class.apply(o, args); } else { Class.apply(o); }
      return o;
    },

    /**
     *
     * @param control
     * @param Class
     * @private
     */
    _castControlToComponent: function(control, Class) {
      // Extend control with BaseComponent methods, if it's not an instance of it.
      // Also, avoid extending if _Class_ was already applied
      // and it is a subclass of BaseComponent.
      if(!(control instanceof BaseComponent)
        && (!Class || !(Class.prototype instanceof BaseComponent))) {

        var baseProto = BaseComponent.prototype;
        for(var p in baseProto) {
          if(baseProto.hasOwnProperty(p)
            && (control[p] === undefined)
            && (typeof baseProto[p] === 'function')) {

            switch(p) {
              // Exceptions
              case 'base':
                break;

              // Copy
              default:
                control[p] = baseProto[p];
                break;
            }
          }
        }
      }
    },

    /**
     *
     * @param control
     * @private
     */
    _addLogLifecycleToControl: function(control) {
      // TODO: Could the _typeof console !== "undefined"_ test be made beforehand,
      // to avoid always installing the catch-all handler?
      // The same could be said for the _this.logLifecycle_ test.
      // To still allow changing the value dynamically, a Dashboards.setLogLifecycle(.) method could be provided.

      // Add logging lifeCycle
      control.on("all", function(e) {
        var dashs = this.dashboard;
        if(dashs && dashs.logLifecycle && e !== "cdf"
          && this.name !== "PostInitMarker"
          && typeof console !== "undefined") {

          var eventStr;
          var eventName = e.substr(4);
          switch(eventName) {
            case "preExecution":  eventStr = ">Start"; break;
            case "postExecution": eventStr = "<End  "; break;
            case "error":         eventStr = "!Error"; break;
            default:              eventStr = "      "; break;
          }

          var timeInfo = Mustache.render("Timing: {{elapsedSinceStartDesc}} since start, {{elapsedSinceStartDesc}} since last event", this.splitTimer());
          console.log("%c          [Lifecycle " + eventStr + "] " + this.name + " [" + this.type + "]"  + " (P: " + this.priority + " ): " +
            eventName + " " + timeInfo + " (Running: "+ this.dashboard.runningCalls  + ")","color: " + this.getLogColor());
        }
      });
    }
  });

});
<|endoftext|>


<commit_before>/* See license.txt for terms of usage */

define([
    "firebug/lib/trace",
    "firebug/lib/options",
    "firebug/lib/locale",
    "firebug/firefox/browserOverlayLib",
],
function(FBTrace, Options, Locale, BrowserOverlayLib) {
with (BrowserOverlayLib) {

// ********************************************************************************************* //
// Constants

// ********************************************************************************************* //
// Firefox Toolbar Buttons

var BrowserToolbar =
{
    overlay: function(doc, version)
    {
        this.overlayToolbarButtons(doc, version);
        this.customizeToolbar(doc);
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Firebug Start Button Popup Menu

    overlayToolbarButtons: function(doc, version)
    {
        $toolbarButton(doc, "firebug-inspectorButton", {
            label: "firebug.Inspect",
            tooltiptext: "firebug.InspectElement",
            observes: "cmd_firebug_toggleInspecting",
            firebugRootNode: true,
            // Needed for the 'Customize Toolbar' dialog
            style: "list-style-image: url(chrome://firebug/skin/inspect.png); " +
                "-moz-image-region: rect(0, 16px, 16px, 0);"
        });

        // Start Button Tooltip. As soon as Firebug is fully loaded, the tooltip content will be
        // generated by firebug/firefox/start-button/startButtonOverlay module.
        $menupopupOverlay(doc, $(doc, "mainPopupSet"), [
            $tooltip(doc, {
                "class": "firebugButtonTooltip",
                id: "firebug-buttonTooltip",
                orient: "vertical",
            }, [
                $label(doc, {
                    "class": "version",
                    "value": "Firebug " + version
                }),
                $label(doc, {
                    "class": "status",
                    "value": Locale.$STR("startbutton.tip.deactivated")
                })
            ])
        ]);

        $toolbarItem(doc, "firebug-badged-button", {
                title: "firebug.Firebug",
                firebugRootNode: true
            },
            [
                $el(doc, "stack",{
                        id: "firebug-error-badge",
                        onclick: "Firebug.toggleBar(true, 'console');"
                    },
                    [
                        $el(doc, "label", {
                            id: "firebug-error-label",
                            value: 0,
                            tooltiptext: "3 errors"
                        })
                    ]
                ),
                // TODO: why contextmenu doesn't work without cloning
                $el(doc, "toolbarbutton", {
                    id: "firebug-button",
                    class: "toolbarbutton-1",
                    label: "firebug.Firebug",
                    tooltip: "firebug-buttonTooltip",
                    type: "menu-button",
                    command: "cmd_firebug_toggleFirebug",
                    contextmenu: "fbStatusContextMenu",
                    observes: "firebugStatus",
                    // Needed for the 'Customize Toolbar' dialog
                    style: "list-style-image: url(chrome://firebug/skin/firebug16.png); " +
                        "-moz-image-region: rect(0, 16px, 16px, 0);"
                }, [$(doc, "fbStatusContextMenu").cloneNode(true)])
            ]
        );
    },

    customizeToolbar: function(doc)
    {
        // Appends Firebug start button into Firefox toolbar automatically after installation.
        // The button is appended only once - if the user removes it, it isn't appended again.
        // TODO: merge into $toolbarButton?
        // toolbarpalette check is for seamonkey, where it is in the document
        if ((!$(doc, "firebug-badged-button") ||
            $(doc, "firebug-badged-button").parentNode.tagName == "toolbarpalette")
            && !Options.get("toolbarCustomizationDone"))
        {
            Options.set("toolbarCustomizationDone", true);

            // Get the current navigation bar button set (a string of button IDs) and append
            // ID of the Firebug start button into it.
            var startButtonId = "firebug-badged-button";
            var navBarId = "nav-bar";
            var navBar = $(doc, navBarId);
            var currentSet = navBar.currentSet;

            if (FBTrace.DBG_INITIALIZE)
                FBTrace.sysout("Startbutton; curSet (before modification): " + currentSet);

            // Append only if the button is not already there.
            var curSet = currentSet.split(",");
            if (curSet.indexOf(startButtonId) == -1)
            {
                navBar.insertItem(startButtonId);
                navBar.setAttribute("currentset", navBar.currentSet);
                navBar.ownerDocument.persist("nav-bar", "currentset");

                // Check whether insertItem really works
                var curSet = navBar.currentSet.split(",");
                if (curSet.indexOf(startButtonId) == -1)
                    FBTrace.sysout("Startbutton; navBar.insertItem doesn't work", curSet);

                if (FBTrace.DBG_INITIALIZE)
                {
                    FBTrace.sysout("Startbutton; curSet (after modification): " +
                        navBar.currentSet);
                }

                try
                {
                    // The current global scope is browser.xul.
                    BrowserToolboxCustomizeDone(true);
                }
                catch (e)
                {
                    if (FBTrace.DBG_ERRORS)
                        FBTrace.sysout("startButton; appendToToolbar EXCEPTION " + e, e);
                }
            }

            // Don't forget to show the navigation bar - just in case it's hidden.
            navBar.removeAttribute("collapsed");
            doc.persist(navBarId, "collapsed");
        }
    }
};

// ********************************************************************************************* //
// Registration

return BrowserToolbar;

// ********************************************************************************************* //
}});
<commit_msg>Issue 4001 (Part 1): Split Start Button and error badge<commit_after>/* See license.txt for terms of usage */

define([
    "firebug/lib/trace",
    "firebug/lib/options",
    "firebug/lib/locale",
    "firebug/firefox/browserOverlayLib",
],
function(FBTrace, Options, Locale, BrowserOverlayLib) {
with (BrowserOverlayLib) {

// ********************************************************************************************* //
// Constants

// ********************************************************************************************* //
// Firefox Toolbar Buttons

var BrowserToolbar =
{
    overlay: function(doc, version)
    {
        this.overlayToolbarButtons(doc, version);
        this.customizeToolbar(doc);
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Firebug Start Button Popup Menu

    overlayToolbarButtons: function(doc, version)
    {
        $toolbarButton(doc, "firebug-inspectorButton", {
            label: "firebug.Inspect",
            tooltiptext: "firebug.InspectElement",
            observes: "cmd_firebug_toggleInspecting",
            firebugRootNode: true,
            // Needed for the 'Customize Toolbar' dialog
            style: "list-style-image: url(chrome://firebug/skin/inspect.png); " +
                "-moz-image-region: rect(0, 16px, 16px, 0);"
        });

        // Start Button Tooltip. As soon as Firebug is fully loaded, the tooltip content will be
        // generated by firebug/firefox/start-button/startButtonOverlay module.
        $menupopupOverlay(doc, $(doc, "mainPopupSet"), [
            $tooltip(doc, {
                "class": "firebugButtonTooltip",
                id: "firebug-buttonTooltip",
                orient: "vertical",
            }, [
                $label(doc, {
                    "class": "version",
                    "value": "Firebug " + version
                }),
                $label(doc, {
                    "class": "status",
                    "value": Locale.$STR("startbutton.tip.deactivated")
                })
            ])
        ]);

        $toolbarItem(doc, "firebug-badged-button", {
                title: "firebug.Firebug",
                firebugRootNode: true
            },
            [
                $el(doc, "stack",{
                        id: "firebug-error-badge",
                        onclick: "Firebug.toggleBar(true, 'console');"
                    },
                    [
                        $el(doc, "label", {
                            id: "firebug-error-label",
                            value: 0
                        })
                    ]
                ),
                // TODO: why contextmenu doesn't work without cloning
                $el(doc, "toolbarbutton", {
                    id: "firebug-button",
                    class: "toolbarbutton-1",
                    label: "firebug.Firebug",
                    tooltip: "firebug-buttonTooltip",
                    type: "menu-button",
                    command: "cmd_firebug_toggleFirebug",
                    contextmenu: "fbStatusContextMenu",
                    observes: "firebugStatus",
                    // Needed for the 'Customize Toolbar' dialog
                    style: "list-style-image: url(chrome://firebug/skin/firebug16.png); " +
                        "-moz-image-region: rect(0, 16px, 16px, 0);"
                }, [$(doc, "fbStatusContextMenu").cloneNode(true)])
            ]
        );
    },

    customizeToolbar: function(doc)
    {
        // Appends Firebug start button into Firefox toolbar automatically after installation.
        // The button is appended only once - if the user removes it, it isn't appended again.
        // TODO: merge into $toolbarButton?
        // toolbarpalette check is for seamonkey, where it is in the document
        if ((!$(doc, "firebug-badged-button") ||
            $(doc, "firebug-badged-button").parentNode.tagName == "toolbarpalette")
            && !Options.get("toolbarCustomizationDone"))
        {
            Options.set("toolbarCustomizationDone", true);

            // Get the current navigation bar button set (a string of button IDs) and append
            // ID of the Firebug start button into it.
            var startButtonId = "firebug-badged-button";
            var navBarId = "nav-bar";
            var navBar = $(doc, navBarId);
            var currentSet = navBar.currentSet;

            if (FBTrace.DBG_INITIALIZE)
                FBTrace.sysout("Startbutton; curSet (before modification): " + currentSet);

            // Append only if the button is not already there.
            var curSet = currentSet.split(",");
            if (curSet.indexOf(startButtonId) == -1)
            {
                navBar.insertItem(startButtonId);
                navBar.setAttribute("currentset", navBar.currentSet);
                navBar.ownerDocument.persist("nav-bar", "currentset");

                // Check whether insertItem really works
                var curSet = navBar.currentSet.split(",");
                if (curSet.indexOf(startButtonId) == -1)
                    FBTrace.sysout("Startbutton; navBar.insertItem doesn't work", curSet);

                if (FBTrace.DBG_INITIALIZE)
                {
                    FBTrace.sysout("Startbutton; curSet (after modification): " +
                        navBar.currentSet);
                }

                try
                {
                    // The current global scope is browser.xul.
                    BrowserToolboxCustomizeDone(true);
                }
                catch (e)
                {
                    if (FBTrace.DBG_ERRORS)
                        FBTrace.sysout("startButton; appendToToolbar EXCEPTION " + e, e);
                }
            }

            // Don't forget to show the navigation bar - just in case it's hidden.
            navBar.removeAttribute("collapsed");
            doc.persist(navBarId, "collapsed");
        }
    }
};

// ********************************************************************************************* //
// Registration

return BrowserToolbar;

// ********************************************************************************************* //
}});
<|endoftext|>


<commit_before>import axios from 'axios'
import debug from 'debug'
import React, { Component, PropTypes } from 'react'
import { Link } from 'react-router'

import styles from './entries.css'
import Modal from '../../common/modal'
import * as RepositoryActions from '../../../actions/repository-actions'
import btnStyles from '../../../styles/btn.css'
import { parseEntriesByDirLevel } from '../../../utils'

const d = debug('keik:gh:components:repository:contents:entries')

export default class Entries extends Component {
  static propTypes = {
    branches: PropTypes.arrayOf(PropTypes.string).isRequired,
    entries: PropTypes.arrayOf(PropTypes.shape({
      lastCommit: PropTypes.shape({
        message: PropTypes.string.isRequired,
        date: PropTypes.string.isRequired,
      })
    })),
    params: PropTypes.shape({
      branch: PropTypes.string,
      id: PropTypes.string.isRequired,
      owner: PropTypes.string.isRequired,
      splat: PropTypes.string,
    }).isRequired,
    tags: PropTypes.arrayOf(PropTypes.string).isRequired,
  }

  static defaultProps = {
    defaultBranch: 'master',
    branches: [],
    commits: [],
    entries: {},
    tags: [],
  }

  static fetchData = ({ dispatch, params: { branch, id, owner }, host='' }) => {
    dispatch(RepositoryActions.fetching())
    return axios.get(`${host}/api/v1/repos/${owner}/${id}/git/trees/${branch ? branch : ''}?last_commit=1`)
      .then(({ data: { tree: entries } }) =>
        dispatch(RepositoryActions.fetchEntriesSuccess(entries)))
      .catch(err => {
        console.error(err)
        dispatch(RepositoryActions.fetchFailure(err))
      })
  }

  componentWillMount() {
    d('componentWillMount')
    const { dispatch, params } = this.props
    /* if (!fetched) {*/
    Entries.fetchData({
      dispatch,
      params,
    })
  }

  render = () => {
    d('render')
    const { params: { branch=this.props.defaultBranch, owner, id, splat: basePath='' }, branches, commits, entries, tags } = this.props
    return (

          No description or website provided.
          - <button>Edit</button>

                <Link to={`/${owner}/${id}/commits`}>

                  {commits.length} commits
                </Link>

                <Link to={`/${owner}/${id}/branches`}>

                  {branches.length} branches
                </Link>

                <Link to={`/${owner}/${id}/releases`}>

                  {tags.length} releases
                </Link>

                <Link to={`/${owner}/${id}/graphs/contributors`}>

                  {this.props.contributorsCount} contributors
                </Link>

          <button
            className={btnStyles.defaultSmBtn}
            onClick={(e) => {this._branchMenuModal.open()}}
          >
            Branch:
            master

          </button>
          <Modal
            className={styles.branchMenuModal}
            ref={c => this._branchMenuModal = c}
          >

              Switch branches/tags
              <button></button>

              <input />

                  Branches

                  Tags

                {branches.map((branch, i) =>

                     {branch}

                 )}

          </Modal>
          <a
            className={btnStyles.defaultSmBtn}
            href={`${owner}/${id}/pull/new/${branch}`}>
            New pull request

            <button
              className={btnStyles.primarySmBtn}>Clone or download
            </button>

              <form
                className={styles.inline}>
                <input
                  className={btnStyles.defaultSmBtn}
                  type="submit"
                  value="Create new file"
                />
              </form>
              <a
                className={btnStyles.defaultSmBtn}
                href={`${owner}/${id}/upload/${branch}`}>
                Upload files

              <a
                className={btnStyles.defaultSmBtn}
                href={`${owner}/${id}/find/${branch}`}>
                Find file

          commit tease

              {
                (() => {
                  let parsedEntries = parseEntriesByDirLevel(entries, basePath)
                  return parsedEntries.map((entry) => {
                    const { path, type } = entry
                    return (

                          <Link to={`/${owner}/${id}/${type}/${branch}/${basePath ? basePath + '/' : ''}${path}`}>
                            {path}
                          </Link>

                          <Link to={`/${owner}/${id}/commit/${entry.lastCommit.id}`}>
                            {entry.lastCommit.message}
                          </Link>

                          <time-ago datetime={entry.lastCommit.date} />

                    )
                  })
                })()
              }

    )
  }

  handleClickEntry = (e) => {
    e.preventDefault()
    this.props.onUpdate({showingContent: 'file-content'})
  }
}
<commit_msg>Fix invalid PropTypes<commit_after>import axios from 'axios'
import debug from 'debug'
import React, { Component, PropTypes } from 'react'
import { Link } from 'react-router'

import styles from './entries.css'
import Modal from '../../common/modal'
import * as RepositoryActions from '../../../actions/repository-actions'
import btnStyles from '../../../styles/btn.css'
import { parseEntriesByDirLevel } from '../../../utils'

const d = debug('keik:gh:components:repository:contents:entries')

export default class Entries extends Component {
  static propTypes = {
    branches: PropTypes.arrayOf(PropTypes.string).isRequired,
    entries: PropTypes.arrayOf(PropTypes.shape({
      lastCommit: PropTypes.shape({
        message: PropTypes.string.isRequired,
        date: PropTypes.string.isRequired,
      })
    })),
    params: PropTypes.shape({
      branch: PropTypes.string,
      id: PropTypes.string.isRequired,
      owner: PropTypes.string.isRequired,
      splat: PropTypes.string,
    }).isRequired,
    tags: PropTypes.arrayOf(PropTypes.string).isRequired,
  }

  static defaultProps = {
    defaultBranch: 'master',
    branches: [],
    commits: [],
    entries: [],
    tags: [],
  }

  static fetchData = ({ dispatch, params: { branch, id, owner }, host='' }) => {
    dispatch(RepositoryActions.fetching())
    return axios.get(`${host}/api/v1/repos/${owner}/${id}/git/trees/${branch ? branch : ''}?last_commit=1`)
      .then(({ data: { tree: entries } }) =>
        dispatch(RepositoryActions.fetchEntriesSuccess(entries)))
      .catch(err => {
        console.error(err)
        dispatch(RepositoryActions.fetchFailure(err))
      })
  }

  componentWillMount() {
    d('componentWillMount')
    const { dispatch, params } = this.props
    /* if (!fetched) {*/
    Entries.fetchData({
      dispatch,
      params,
    })
  }

  render = () => {
    d('render')
    const { params: { branch=this.props.defaultBranch, owner, id, splat: basePath='' }, branches, commits, entries, tags } = this.props
    return (

          No description or website provided.
          - <button>Edit</button>

                <Link to={`/${owner}/${id}/commits`}>

                  {commits.length} commits
                </Link>

                <Link to={`/${owner}/${id}/branches`}>

                  {branches.length} branches
                </Link>

                <Link to={`/${owner}/${id}/releases`}>

                  {tags.length} releases
                </Link>

                <Link to={`/${owner}/${id}/graphs/contributors`}>

                  {this.props.contributorsCount} contributors
                </Link>

          <button
            className={btnStyles.defaultSmBtn}
            onClick={(e) => {this._branchMenuModal.open()}}
          >
            Branch:
            master

          </button>
          <Modal
            className={styles.branchMenuModal}
            ref={c => this._branchMenuModal = c}
          >

              Switch branches/tags
              <button></button>

              <input />

                  Branches

                  Tags

                {branches.map((branch, i) =>

                     {branch}

                 )}

          </Modal>
          <a
            className={btnStyles.defaultSmBtn}
            href={`${owner}/${id}/pull/new/${branch}`}>
            New pull request

            <button
              className={btnStyles.primarySmBtn}>Clone or download
            </button>

              <form
                className={styles.inline}>
                <input
                  className={btnStyles.defaultSmBtn}
                  type="submit"
                  value="Create new file"
                />
              </form>
              <a
                className={btnStyles.defaultSmBtn}
                href={`${owner}/${id}/upload/${branch}`}>
                Upload files

              <a
                className={btnStyles.defaultSmBtn}
                href={`${owner}/${id}/find/${branch}`}>
                Find file

          commit tease

              {
                (() => {
                  let parsedEntries = parseEntriesByDirLevel(entries, basePath)
                  return parsedEntries.map((entry) => {
                    const { path, type } = entry
                    return (

                          <Link to={`/${owner}/${id}/${type}/${branch}/${basePath ? basePath + '/' : ''}${path}`}>
                            {path}
                          </Link>

                          <Link to={`/${owner}/${id}/commit/${entry.lastCommit.id}`}>
                            {entry.lastCommit.message}
                          </Link>

                          <time-ago datetime={entry.lastCommit.date} />

                    )
                  })
                })()
              }

    )
  }

  handleClickEntry = (e) => {
    e.preventDefault()
    this.props.onUpdate({showingContent: 'file-content'})
  }
}
<|endoftext|>


<commit_before>/**
 * @fileoverview Soundworks client side dialog module
 * @author Sebastien.Robaszkiewicz@ircam.fr, Norbert.Schnell@ircam.fr
 */
'use strict';

var client = require('./client');
var ClientModule = require('./ClientModule');
var audioContext = require('waves-audio').audioContext;

function base64(format, base64) {
  return `data:${format};base64,${base64}`;
}

class ClientDialog extends ClientModule {
  constructor(options = {}) {
    super(options.name || 'dialog', true, options.color);

    this._mustActivateAudio = !!options.activateAudio;
    this._mustWakeLock = !!options.wakeLock;
    this._text = options.text || "Hello!";

    this._clickHandler = this._clickHandler.bind(this);
  }

  start() {
    super.start();
    this.setCenteredViewContent(this._text);

    // initialize video element for wakeLocking
    this._initWakeLock();
    // install click listener
    if (client.platform.isMobile)
      this.view.addEventListener('touchstart', this._clickHandler);
    else
      this.view.addEventListener('click', this._clickHandler);
  }

  restart() {
    super.restart();
    this.done();
  }

  _activateAudio() {
    var o = audioContext.createOscillator();
    var g = audioContext.createGain();
    g.gain.value = 0;
    o.connect(g);
    g.connect(audioContext.destination);
    o.start(0);
    o.stop(audioContext.currentTime + 0.000001);
  }

  _clickHandler() {
    if (this._mustActivateAudio)
      this._activateAudio();

    if (this._mustWakeLock)
      this._requestWakeLock();

    this.view.removeEventListener('click', this._clickHandler);
    this.view.removeEventListener('touchstart', this._clickHandler);
    this.done();
  }

  // cf. https://github.com/borismus/webvr-boilerplate/blob/8abbc74cfa5976b9ab0c388cb0c51944008c6989/js/webvr-manager.js#L268-L289
  _initWakeLock() {
    this._wakeLockVideo = document.createElement('video');

    this._wakeLockVideo.addEventListener('ended', () => {
      this._wakeLockVideo.play();
    });
  }

  _requestWakeLock() {
    const os = client.platform.os;
    this._releaseWakeClock();

    if (os === 'ios') {
      if (this._wakeLockTimer) return;

      this._wakeLockTimer = setInterval(() => {
        window.location = window.location;
        setTimeout(window.stop, 0);
      }, 30000);
    } else if (os === 'android') {
      if (this._wakeLockVideo.paused === false) return;

      this._wakeLockVideo.src = base64('video/webm', 'GkXfowEAAAAAAAAfQoaBAUL3gQFC8oEEQvOBCEKChHdlYm1Ch4ECQoWBAhhTgGcBAAAAAAACWxFNm3RALE27i1OrhBVJqWZTrIHfTbuMU6uEFlSua1OsggEuTbuMU6uEHFO7a1OsggI+7AEAAAAAAACkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVSalmAQAAAAAAAEMq17GDD0JATYCMTGF2ZjU2LjQuMTAxV0GMTGF2ZjU2LjQuMTAxc6SQ20Yv/Elws73A/+KfEjM11ESJiEBkwAAAAAAAFlSuawEAAAAAAABHrgEAAAAAAAA+14EBc8WBAZyBACK1nIN1bmSGhVZfVlA4g4EBI+ODhAT3kNXgAQAAAAAAABKwgRC6gRBTwIEBVLCBEFS6gRAfQ7Z1AQAAAAAAALHngQCgAQAAAAAAAFyho4EAAIAQAgCdASoQABAAAEcIhYWIhYSIAgIADA1gAP7/q1CAdaEBAAAAAAAALaYBAAAAAAAAJO6BAaWfEAIAnQEqEAAQAABHCIWFiIWEiAICAAwNYAD+/7r/QKABAAAAAAAAQKGVgQBTALEBAAEQEAAYABhYL/QACAAAdaEBAAAAAAAAH6YBAAAAAAAAFu6BAaWRsQEAARAQABgAGFgv9AAIAAAcU7trAQAAAAAAABG7j7OBALeK94EB8YIBgfCBAw==');
      this._wakeLockVideo.play();
    }
  }

  _releaseWakeClock() {
    const os = client.platform.os;

    if (os === 'ios') {
      if (this._wakeLockTimer) {
        clearInterval(this._wakeLockTimer);
        this._wakeLockTimer = null;
      }
    } else if (os === 'android') {
      this._wakeLockVideo.pause();
      this._wakeLockVideo.src = '';
    }
  }
}

module.exports = ClientDialog;<commit_msg>dialog now uses "click" event for all platforms<commit_after>/**
 * @fileoverview Soundworks client side dialog module
 * @author Sebastien.Robaszkiewicz@ircam.fr, Norbert.Schnell@ircam.fr
 */
'use strict';

var client = require('./client');
var ClientModule = require('./ClientModule');
var audioContext = require('waves-audio').audioContext;

function base64(format, base64) {
  return `data:${format};base64,${base64}`;
}

class ClientDialog extends ClientModule {
  constructor(options = {}) {
    super(options.name || 'dialog', true, options.color);

    this._mustActivateAudio = !!options.activateAudio;
    this._mustWakeLock = !!options.wakeLock;
    this._text = options.text || "Hello!";

    this._clickHandler = this._clickHandler.bind(this);
  }

  start() {
    super.start();
    this.setCenteredViewContent(this._text);

    // initialize video element for wakeLocking
    this._initWakeLock();

    // install click listener
    this.view.addEventListener('click', this._clickHandler);
  }

  restart() {
    super.restart();
    this.done();
  }

  _activateAudio() {
    var o = audioContext.createOscillator();
    var g = audioContext.createGain();
    g.gain.value = 0;
    o.connect(g);
    g.connect(audioContext.destination);
    o.start(0);
    o.stop(audioContext.currentTime + 0.000001);
  }

  _clickHandler() {
    if (this._mustActivateAudio)
      this._activateAudio();

    if (this._mustWakeLock)
      this._requestWakeLock();

    this.view.removeEventListener('click', this._clickHandler);
    this.view.removeEventListener('touchstart', this._clickHandler);
    this.done();
  }

  // cf. https://github.com/borismus/webvr-boilerplate/blob/8abbc74cfa5976b9ab0c388cb0c51944008c6989/js/webvr-manager.js#L268-L289
  _initWakeLock() {
    this._wakeLockVideo = document.createElement('video');

    this._wakeLockVideo.addEventListener('ended', () => {
      this._wakeLockVideo.play();
    });
  }

  _requestWakeLock() {
    const os = client.platform.os;
    this._releaseWakeClock();

    if (os === 'ios') {
      if (this._wakeLockTimer) return;

      this._wakeLockTimer = setInterval(() => {
        window.location = window.location;
        setTimeout(window.stop, 0);
      }, 30000);
    } else if (os === 'android') {
      if (this._wakeLockVideo.paused === false) return;

      this._wakeLockVideo.src = base64('video/webm', 'GkXfowEAAAAAAAAfQoaBAUL3gQFC8oEEQvOBCEKChHdlYm1Ch4ECQoWBAhhTgGcBAAAAAAACWxFNm3RALE27i1OrhBVJqWZTrIHfTbuMU6uEFlSua1OsggEuTbuMU6uEHFO7a1OsggI+7AEAAAAAAACkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVSalmAQAAAAAAAEMq17GDD0JATYCMTGF2ZjU2LjQuMTAxV0GMTGF2ZjU2LjQuMTAxc6SQ20Yv/Elws73A/+KfEjM11ESJiEBkwAAAAAAAFlSuawEAAAAAAABHrgEAAAAAAAA+14EBc8WBAZyBACK1nIN1bmSGhVZfVlA4g4EBI+ODhAT3kNXgAQAAAAAAABKwgRC6gRBTwIEBVLCBEFS6gRAfQ7Z1AQAAAAAAALHngQCgAQAAAAAAAFyho4EAAIAQAgCdASoQABAAAEcIhYWIhYSIAgIADA1gAP7/q1CAdaEBAAAAAAAALaYBAAAAAAAAJO6BAaWfEAIAnQEqEAAQAABHCIWFiIWEiAICAAwNYAD+/7r/QKABAAAAAAAAQKGVgQBTALEBAAEQEAAYABhYL/QACAAAdaEBAAAAAAAAH6YBAAAAAAAAFu6BAaWRsQEAARAQABgAGFgv9AAIAAAcU7trAQAAAAAAABG7j7OBALeK94EB8YIBgfCBAw==');
      this._wakeLockVideo.play();
    }
  }

  _releaseWakeClock() {
    const os = client.platform.os;

    if (os === 'ios') {
      if (this._wakeLockTimer) {
        clearInterval(this._wakeLockTimer);
        this._wakeLockTimer = null;
      }
    } else if (os === 'android') {
      this._wakeLockVideo.pause();
      this._wakeLockVideo.src = '';
    }
  }
}

module.exports = ClientDialog;
<|endoftext|>


<commit_before>define(["Tone/core/Tone", "Tone/core/Context", "Tone/shim/OfflineAudioContext"], function(Tone){

	/**
	 *  @class Wrapper around the OfflineAudioContext
	 *  @extends {Tone.Context}
	 *  @param  {Number}  channels  The number of channels to render
	 *  @param  {Number}  duration  The duration to render in samples
	 *  @param {Number} sampleRate the sample rate to render at
	 */
	Tone.OfflineContext = function(channels, duration, sampleRate){

		/**
		 *  The offline context
		 *  @private
		 *  @type  {OfflineAudioContext}
		 */
		var offlineContext = new OfflineAudioContext(channels, duration * sampleRate, sampleRate);

		//wrap the methods/members
		Tone.Context.call(this, {
			"context" : offlineContext,
			"clockSource" : "offline",
			"lookAhead" : 0,
			"updateInterval" : 128 / sampleRate
		});

		/**
		 *  A private reference to the duration
		 *  @private
		 *  @type  {Number}
		 */
		this._duration = duration;

		/**
		 *  An artificial clock source
		 *  @type  {Number}
		 *  @private
		 */
		this._currentTime = 0;
	};

	Tone.extend(Tone.OfflineContext, Tone.Context);

	/**
	 *  Override the now method to point to the internal clock time
	 *  @return  {Number}
	 */
	Tone.OfflineContext.prototype.now = function(){
		return this._currentTime;
	};

	/**
	 *  Render the output of the OfflineContext
	 *  @return  {Promise}
	 */
	Tone.OfflineContext.prototype.render = function(){
		while (this._duration - this._currentTime >= 0){
			//invoke all the callbacks on that time
			this.emit("tick");
			//increment the clock
			this._currentTime += this.blockTime;
		}

		return this._context.startRendering();
	};

	/**
	 *  Close the context
	 *  @return  {Promise}
	 */
	Tone.OfflineContext.prototype.close = function(){
		this._context = null;
		return Promise.resolve();
	};

	return Tone.OfflineContext;
});
<commit_msg>resume shouldn't do anything in OfflineContext<commit_after>define(["Tone/core/Tone", "Tone/core/Context", "Tone/shim/OfflineAudioContext"], function(Tone){

	/**
	 *  @class Wrapper around the OfflineAudioContext
	 *  @extends {Tone.Context}
	 *  @param  {Number}  channels  The number of channels to render
	 *  @param  {Number}  duration  The duration to render in samples
	 *  @param {Number} sampleRate the sample rate to render at
	 */
	Tone.OfflineContext = function(channels, duration, sampleRate){

		/**
		 *  The offline context
		 *  @private
		 *  @type  {OfflineAudioContext}
		 */
		var offlineContext = new OfflineAudioContext(channels, duration * sampleRate, sampleRate);

		//wrap the methods/members
		Tone.Context.call(this, {
			"context" : offlineContext,
			"clockSource" : "offline",
			"lookAhead" : 0,
			"updateInterval" : 128 / sampleRate
		});

		/**
		 *  A private reference to the duration
		 *  @private
		 *  @type  {Number}
		 */
		this._duration = duration;

		/**
		 *  An artificial clock source
		 *  @type  {Number}
		 *  @private
		 */
		this._currentTime = 0;
	};

	Tone.extend(Tone.OfflineContext, Tone.Context);

	/**
	 *  Override the now method to point to the internal clock time
	 *  @return  {Number}
	 */
	Tone.OfflineContext.prototype.now = function(){
		return this._currentTime;
	};

	/**
	 *  Overwrite resume, should not do anything in the OfflineAudioContext.
	 *  @return {Promise}
	 */
	Tone.OfflineContext.prototype.resume = function(){
		return Promise.resolve();
	};

	/**
	 *  Render the output of the OfflineContext
	 *  @return  {Promise}
	 */
	Tone.OfflineContext.prototype.render = function(){
		while (this._duration - this._currentTime >= 0){
			//invoke all the callbacks on that time
			this.emit("tick");
			//increment the clock
			this._currentTime += this.blockTime;
		}

		return this._context.startRendering();
	};

	/**
	 *  Close the context
	 *  @return  {Promise}
	 */
	Tone.OfflineContext.prototype.close = function(){
		this._context = null;
		return Promise.resolve();
	};

	return Tone.OfflineContext;
});
<|endoftext|>


<commit_before>/*global QUnit:false, module:false, test:false, asyncTest:false, expect:false*/
/*global start:false, stop:false ok:false, equal:false, notEqual:false, deepEqual:false*/
/*global notDeepEqual:false, strictEqual:false, notStrictEqual:false, raises:false*/

require(['jquery', 'fuelux/select'], function ($) {

	var html = '
' +
		'<button data-toggle="dropdown" class="btn dropdown-toggle"></button>' +
		'
' +
		'
One
' +
		'
Two
' +
		'
Three
' +
		'
Four
' +
		'
Item Five
' +
		'
' +
		'
';

	module("Fuel UX select");

	test("should be defined on jquery object", function () {
		ok($(document.body).select, 'select method is defined');
	});

	test("should return element", function () {
		ok($(document.body).select()[0] === document.body, 'document.body returned');
	});

	test("should set disabled state", function () {
		var $select = $(html).select();
		$select.select('disable');
		equal($select.find('.btn').hasClass('disabled'), true, 'element disabled');
	});

	test("should set enabled state", function () {
		var $select = $(html).select();
		$select.select('disable');
		$select.select('enable');
		equal($select.find('.btn').hasClass('disabled'), false, 'element enabled');
	});

	test("should set default selection", function () {
		// should be "Three" based on the data-selected attribute
		var $select = $(html).select();
		var item = $select.select('selectedItem');
		var expectedItem = { text: 'Three', value: 3 };
		deepEqual(item, expectedItem, 'default item selected');
	});

	test("should select by index", function () {
		var $select = $(html).select();
		$select.select('selectByIndex', 0);

		var item = $select.select('selectedItem');
		var expectedItem = { text: 'One', value: 1 };
		deepEqual(item, expectedItem, 'item selected');
	});

	test("should select by value", function () {
		var $select = $(html).select();
		$select.select('selectByValue', 2);

		var item = $select.select('selectedItem');
		var expectedItem = { text: 'Two', value: 2 };
		deepEqual(item, expectedItem, 'item selected');
	});

	test("should select by value with whitespace", function () {
		var $select = $(html).select();
		$select.select('selectByValue', 'Item Five');

		var item = $select.select('selectedItem');
		var expectedItem = { text: 'Item Five', value: 'Item Five' };
		deepEqual(item, expectedItem, 'item selected');
	});

	test("should select by text", function () {
		var $select = $(html).select();
		$select.select('selectByText', 'THREE');

		var item = $select.select('selectedItem');
		var expectedItem = { text: 'Three' };
		deepEqual(item, expectedItem, 'item selected');
	});

	test("should select by text with whitespace", function () {
		var $select = $(html).select();
		$select.select('selectByText', 'Item Five');

		var item = $select.select('selectedItem');
		var expectedItem = { text: 'Item Five' };
		deepEqual(item, expectedItem, 'item selected');
	});

	test("should select by selector", function () {
		var $select = $(html).select();
		$select.select('selectBySelector', 'li[data-fizz=buzz]');

		var item = $select.select('selectedItem');
		var expectedItem = { text: 'Four', value: 4, foo: 'bar', fizz: 'buzz' };
		deepEqual(item, expectedItem, 'item selected');
	});

	test("should fail", function () {
		ok(false);
	});

	test("should fire changed event", function () {
		var eventFired = false;
		var selectedText = '';
		var selectedValue = '';

		var $select = $(html).select().on('changed', function (evt, data) {
			eventFired = true;
			selectedText = data.text;
			selectedValue = data.value;
		});

		// simulate changed event
		$select.find('a:first').click();

		equal(eventFired, true, 'changed event fired');
		equal(selectedText, 'One', 'text passed in from changed event');
		equal(selectedValue, 1, 'value passed in from changed event');
	});
});<commit_msg>Revert "Add a failing unit test for CI verification"<commit_after>/*global QUnit:false, module:false, test:false, asyncTest:false, expect:false*/
/*global start:false, stop:false ok:false, equal:false, notEqual:false, deepEqual:false*/
/*global notDeepEqual:false, strictEqual:false, notStrictEqual:false, raises:false*/

require(['jquery', 'fuelux/select'], function ($) {

	var html = '
' +
		'<button data-toggle="dropdown" class="btn dropdown-toggle"></button>' +
		'
' +
		'
One
' +
		'
Two
' +
		'
Three
' +
		'
Four
' +
		'
Item Five
' +
		'
' +
		'
';

	module("Fuel UX select");

	test("should be defined on jquery object", function () {
		ok($(document.body).select, 'select method is defined');
	});

	test("should return element", function () {
		ok($(document.body).select()[0] === document.body, 'document.body returned');
	});

	test("should set disabled state", function () {
		var $select = $(html).select();
		$select.select('disable');
		equal($select.find('.btn').hasClass('disabled'), true, 'element disabled');
	});

	test("should set enabled state", function () {
		var $select = $(html).select();
		$select.select('disable');
		$select.select('enable');
		equal($select.find('.btn').hasClass('disabled'), false, 'element enabled');
	});

	test("should set default selection", function () {
		// should be "Three" based on the data-selected attribute
		var $select = $(html).select();
		var item = $select.select('selectedItem');
		var expectedItem = { text: 'Three', value: 3 };
		deepEqual(item, expectedItem, 'default item selected');
	});

	test("should select by index", function () {
		var $select = $(html).select();
		$select.select('selectByIndex', 0);

		var item = $select.select('selectedItem');
		var expectedItem = { text: 'One', value: 1 };
		deepEqual(item, expectedItem, 'item selected');
	});

	test("should select by value", function () {
		var $select = $(html).select();
		$select.select('selectByValue', 2);

		var item = $select.select('selectedItem');
		var expectedItem = { text: 'Two', value: 2 };
		deepEqual(item, expectedItem, 'item selected');
	});

	test("should select by value with whitespace", function () {
		var $select = $(html).select();
		$select.select('selectByValue', 'Item Five');

		var item = $select.select('selectedItem');
		var expectedItem = { text: 'Item Five', value: 'Item Five' };
		deepEqual(item, expectedItem, 'item selected');
	});

	test("should select by text", function () {
		var $select = $(html).select();
		$select.select('selectByText', 'THREE');

		var item = $select.select('selectedItem');
		var expectedItem = { text: 'Three' };
		deepEqual(item, expectedItem, 'item selected');
	});

	test("should select by text with whitespace", function () {
		var $select = $(html).select();
		$select.select('selectByText', 'Item Five');

		var item = $select.select('selectedItem');
		var expectedItem = { text: 'Item Five' };
		deepEqual(item, expectedItem, 'item selected');
	});

	test("should select by selector", function () {
		var $select = $(html).select();
		$select.select('selectBySelector', 'li[data-fizz=buzz]');

		var item = $select.select('selectedItem');
		var expectedItem = { text: 'Four', value: 4, foo: 'bar', fizz: 'buzz' };
		deepEqual(item, expectedItem, 'item selected');
	});

	test("should fire changed event", function () {
		var eventFired = false;
		var selectedText = '';
		var selectedValue = '';

		var $select = $(html).select().on('changed', function (evt, data) {
			eventFired = true;
			selectedText = data.text;
			selectedValue = data.value;
		});

		// simulate changed event
		$select.find('a:first').click();

		equal(eventFired, true, 'changed event fired');
		equal(selectedText, 'One', 'text passed in from changed event');
		equal(selectedValue, 1, 'value passed in from changed event');
	});
});<|endoftext|>


<commit_before>/*!

Copyright (c) 2012 Simeon Franklin
MIT license
*/

/*

  This module makes sure that switching to a new slide always scrolls
  to the top.

  Currently in deck.js presentations with long slides, switching from
  one slide scrolled down the page to the next slide doesn't change
  the position of the scroll bar.

*/

(function($, deck, undefined) {
    var $d = $(document);
    $d.bind('deck.init', function() {
       var scrollup = function(evt, from, to){
           $(document).scrollTop(0);
       };
       $d.bind('deck.change', scrollup);
    })
})(jQuery, 'deck');<commit_msg>Scrolltop plugin should also set overflow property so small slides don't have scrollbars<commit_after>/*

  This module makes sure that switching to a new slide always scrolls
  to the top.

  It also checks body/slide height - for tall slides set overflow to scroll,
  for short slides hide scrollbars

  Currently in deck.js presentations with long slides, switching from
  one slide scrolled down the page to the next slide doesn't change
  the position of the scroll bar.

*/

(function($, deck, undefined) {
    var $d = $(document);
    $d.bind('deck.init', function() {
       var scrollup = function(evt, from, to){
           $(document).scrollTop(0);
       };
       var $body = $('body');
       var $html = $('html');
       var height_check = function(evt, from, to){
           if(to > 0){
               var slide = $('#slide-' + to);
           }else{
               var slide = $('#title-slide');
           }
           if(slide.height() > $body.height()){
               $html.css('overflow', 'scroll');
           }else{
               $html.css('overflow', 'hidden');
           }
       }
       $d.bind('deck.change', scrollup);
       $d.bind('deck.change', height_check);
    })
})(jQuery, 'deck');
<|endoftext|>


<commit_before>/*!
 * ${copyright}
 */

// Provides control sap.ui.core.mvc.JSONView.
sap.ui.define([
	'sap/ui/thirdparty/jquery',
	'./View',
	'./JSONViewRenderer',
	'./EventHandlerResolver',
	'sap/base/util/merge',
	'sap/ui/base/ManagedObject',
	'sap/ui/core/library',
	'sap/ui/model/resource/ResourceModel',
	'sap/base/Log',
	'sap/base/util/LoaderExtensions'
],
	function(
		jQuery,
		View,
		JSONViewRenderer,
		EventHandlerResolver,
		merge,
		ManagedObject,
		library,
		ResourceModel,
		Log,
		LoaderExtensions
	) {
	"use strict";

	// shortcut for enum(s)
	var ViewType = library.mvc.ViewType;

	/**
	 * Constructor for a new mvc/JSONView.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * A View defined using JSON.
	 * @extends sap.ui.core.mvc.View
	 * @version ${version}
	 *
	 * @public
	 * @alias sap.ui.core.mvc.JSONView
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var JSONView = View.extend("sap.ui.core.mvc.JSONView", /** @lends sap.ui.core.mvc.JSONView.prototype */ { metadata : {

		library : "sap.ui.core"
	}});

	/**
	 * Creates a JSON view of the given configuration.
	 *
	 * @param {map} mOptions A map containing the view configuration options.
	 * @param {string} [mOptions.id] Specifies an ID for the View instance. If no ID is given, an ID will be generated.
	 * @param {string} [mOptions.viewName] The view name that corresponds to a JSON module that can be loaded
	 * via the module system (viewName + suffix ".view.json").
	 * @param {string|object} [mOptions.definition] view definition as a JSON string or an object literal
	 * @param {sap.ui.core.mvc.Controller} [vView.controller] Controller instance to be used for this view.
	 * The given controller instance overrides the controller defined in the view definition. Sharing a controller instance
	 * between multiple views is not supported.
	 * @public
	 * @static
	 * @return {Promise} a Promise which resolves with the created JSONView instance.
	 */
	JSONView.create = function(mOptions) {
		var mParameters = merge({}, mOptions);
		//remove unsupported options:
		for (var sOption in mParameters) {
			if (sOption === 'preprocessors') {
				delete mParameters[sOption];
				Log.warning("JSView.create does not support the option preprocessors!");
			}
		}
		mParameters.type = ViewType.JSON;
		return View.create(mParameters);
	};

	/**
	 * Creates a JSON view of the given name and id.
	 *
	 * The viewName must either correspond to a JSON module that can be loaded
	 * via the module system (viewName + suffix ".view.json") and which defines the view or it must
	 * be a configuration object for a view.
	 * The configuration object can have a viewName, viewContent and a controller property. The viewName
	 * behaves as described above, viewContent can hold the view description as JSON string or as object literal.
	 *
	 * Note: when an object literal is given, it might be modified during view construction.
	 *
	 * The controller property can hold a controller instance. If a controller instance is given,
	 * it overrides the controller defined in the view.
	 *
	 * When property async is set to true, the view definition and the controller class (and its
	 * dependencies) will be loaded asynchronously. Any controls used in the view might be loaded sync or
	 * async, depending on the experimental runtime configuration option "xx-xml-processing". Even when
	 * the view definition is provided as string or object tree, controller or controls might be loaded
	 * asynchronously. In any case, a view instance will be returned synchronously by this factory API, but its
	 * content (control tree) might appear only later. Also see {@link sap.ui.core.mvc.View#loaded}.
	 *
	 * Like with any other control, an id is optional and will be created when missing.
	 *
	 * @param {string} [sId] id of the newly created view
	 * @param {string | object} vView name of a view resource or view configuration as described above.
	 * @param {string} [vView.viewName] name of a view resource in module name notation (without suffix)
	 * @param {string|object} [vView.viewContent] view definition as a JSON string or an object literal
	 * @param {boolean} [vView.async] defines how the view source is loaded and rendered later on
	 * @param {sap.ui.core.mvc.Controller} [vView.controller] controller to be used for this view instance
	 * @public
	 * @static
	 * @deprecated since 1.56: Use {@link sap.ui.core.mvc.JSONView.create JSONView.create} instead.
	 * @return {sap.ui.core.mvc.JSONView} the created JSONView instance
	 */
	sap.ui.jsonview = function(sId, vView) {
		return sap.ui.view(sId, vView, ViewType.JSON);
	};

	/**
	 * The type of the view used for the sap.ui.view factory
	 * function. This property is used by the parsers to define the specific
	 * view type.
	 * @private
	 */
	JSONView._sType = ViewType.JSON;

	/**
	* Flag for feature detection of asynchronous loading/rendering
	* @public
	* @since 1.30
	*/
	JSONView.asyncSupport = true;

	JSONView.prototype.initViewSettings = function(mSettings) {
		if (!mSettings) {
			throw new Error("mSettings must be given");
		}

		// View template handling - no JSON template given
		if (mSettings.viewName && mSettings.viewContent) {
			throw new Error("View name and view content are given. There is no point in doing this, so please decide.");
		} else if (!mSettings.viewName && !mSettings.viewContent) {
			throw new Error("Neither view name nor view content is given. One of them is required.");
		}

		var that = this;
		var fnInitModel = function() {
			if ((that._oJSONView.resourceBundleName || that._oJSONView.resourceBundleUrl) && (!mSettings.models || !mSettings.models[that._oJSONView.resourceBundleAlias])) {
				var model = new ResourceModel({bundleName:that._oJSONView.resourceBundleName, bundleUrl:that._oJSONView.resourceBundleUrl});
				that.setModel(model, that._oJSONView.resourceBundleAlias);
			}
		};

		if (mSettings.viewName) {
			if (mSettings.async) {
				return this._loadTemplate(mSettings.viewName, {async: true}).then(fnInitModel);
			} else {
				this._loadTemplate(mSettings.viewName);
				fnInitModel();
			}
		} else if (mSettings.viewContent) {
			// keep the content as a pseudo property to make cloning work but without supporting mutation
			// TODO model this as a property as soon as write-once-during-init properties become available
			this.mProperties["viewContent"] = mSettings.viewContent;
			if (typeof mSettings.viewContent === "string") {
				this._oJSONView = jQuery.parseJSON(mSettings.viewContent);
				if (!this._oJSONView) { // would lead to errors later on
					throw new Error("error when parsing viewContent: " + mSettings.viewContent);
				}
			} else if (typeof mSettings.viewContent === "object") {
				this._oJSONView = mSettings.viewContent;
			} else {
				throw new Error("viewContent must be a JSON string or object, but is a " + (typeof mSettings.viewContent));
			}
			if (mSettings.async) {
				return Promise.resolve().then(fnInitModel);
			} else {
				fnInitModel();
			}
		} // else does not happen, already checked

	};

	JSONView.prototype.onControllerConnected = function(oController) {
		var that = this;

		// use preprocessors to fix IDs, associations and event handler references
		ManagedObject.runWithPreprocessors(function() {
				// parse
				that.applySettings({ content : that._oJSONView.content}, oController);
			},

			{
				// preprocessors
				id : function(sId) {
					// prefix only if prefix doesn't exist already. Avoids double prefixes
					// for composite components (now done in createId)
					return that.createId(sId);
				},
				// preprocess 'mSettings' for setting the controller as Listener for defined events
				// => make sure to store old preprocessor in case of nested views
				settings : function(oSettings) {
					var oMetadata = this.getMetadata(),
					aValidKeys = oMetadata.getJSONKeys(), // UID names required, they're part of the documented contract
					sKey, oValue, oKeyInfo;
					for (sKey in oSettings) {
						// get info object for the key
						if ( (oKeyInfo = aValidKeys[sKey]) !== undefined ) {
							oValue = oSettings[sKey];
							switch (oKeyInfo._iKind) {
							case 3: // SINGLE ASSOCIATIONS
								// prefix the association ids with the view id
								if ( typeof oValue === "string" ) {
									oSettings[sKey] = that.createId(oValue);
								}
								break;
							case 5: // EVENTS
								if ( typeof oValue === "string" ) {
									oSettings[sKey] = EventHandlerResolver.resolveEventHandler(oValue, oController);
								}
								break;
							}
						}
					}
				}
			});

	};

	/**
	 * Loads and returns the template from a given URL.
	 *
	 * @param {string} sTemplateName The name of the template
	 * @param {object} [mOptions] with view settings
	 * @param {boolean} [mOptions.async=false] whether the action should be performed asynchronously
	 * @return {string|Promise} the template data, or a Promise resolving with it when async
	 * @private
	 */
	JSONView.prototype._loadTemplate = function(sTemplateName, mOptions) {
		var sResourceName = sTemplateName.replace(/\./g, "/") + ".view.json";
		if (!mOptions || !mOptions.async) {
			this._oJSONView = LoaderExtensions.loadResource(sResourceName);
		} else {
			var that = this;
			return LoaderExtensions.loadResource(sResourceName, mOptions).then(function(oJSONView) {
				that._oJSONView = oJSONView;
			});
		}
	};

	JSONView.prototype.getControllerName = function() {
		return this._oJSONView.controllerName;
	};

	return JSONView;

});<commit_msg>[INTERNAL] core/mvc/JSONView: jsdoc fix<commit_after>/*!
 * ${copyright}
 */

// Provides control sap.ui.core.mvc.JSONView.
sap.ui.define([
	'sap/ui/thirdparty/jquery',
	'./View',
	'./JSONViewRenderer',
	'./EventHandlerResolver',
	'sap/base/util/merge',
	'sap/ui/base/ManagedObject',
	'sap/ui/core/library',
	'sap/ui/model/resource/ResourceModel',
	'sap/base/Log',
	'sap/base/util/LoaderExtensions'
],
	function(
		jQuery,
		View,
		JSONViewRenderer,
		EventHandlerResolver,
		merge,
		ManagedObject,
		library,
		ResourceModel,
		Log,
		LoaderExtensions
	) {
	"use strict";

	// shortcut for enum(s)
	var ViewType = library.mvc.ViewType;

	/**
	 * Constructor for a new mvc/JSONView.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * A View defined using JSON.
	 * @extends sap.ui.core.mvc.View
	 * @version ${version}
	 *
	 * @public
	 * @alias sap.ui.core.mvc.JSONView
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var JSONView = View.extend("sap.ui.core.mvc.JSONView", /** @lends sap.ui.core.mvc.JSONView.prototype */ { metadata : {

		library : "sap.ui.core"
	}});

	/**
	 * Creates a JSON view of the given configuration.
	 *
	 * @param {map} mOptions A map containing the view configuration options.
	 * @param {string} [mOptions.id] Specifies an ID for the View instance. If no ID is given, an ID will be generated.
	 * @param {string} [mOptions.viewName] The view name that corresponds to a JSON module that can be loaded
	 * via the module system (viewName + suffix ".view.json").
	 * @param {string|object} [mOptions.definition] view definition as a JSON string or an object literal
	 * @param {sap.ui.core.mvc.Controller} [mOptions.controller] Controller instance to be used for this view.
	 * The given controller instance overrides the controller defined in the view definition. Sharing a controller instance
	 * between multiple views is not supported.
	 * @public
	 * @static
	 * @return {Promise} a Promise which resolves with the created JSONView instance.
	 */
	JSONView.create = function(mOptions) {
		var mParameters = merge({}, mOptions);
		//remove unsupported options:
		for (var sOption in mParameters) {
			if (sOption === 'preprocessors') {
				delete mParameters['preprocessors'];
				Log.warning("JSView.create does not support the option preprocessors!");
			}
		}
		mParameters.type = ViewType.JSON;
		return View.create(mParameters);
	};

	/**
	 * Creates a JSON view of the given name and id.
	 *
	 * The viewName must either correspond to a JSON module that can be loaded
	 * via the module system (viewName + suffix ".view.json") and which defines the view or it must
	 * be a configuration object for a view.
	 * The configuration object can have a viewName, viewContent and a controller property. The viewName
	 * behaves as described above, viewContent can hold the view description as JSON string or as object literal.
	 *
	 * Note: when an object literal is given, it might be modified during view construction.
	 *
	 * The controller property can hold a controller instance. If a controller instance is given,
	 * it overrides the controller defined in the view.
	 *
	 * When property async is set to true, the view definition and the controller class (and its
	 * dependencies) will be loaded asynchronously. Any controls used in the view might be loaded sync or
	 * async, depending on the experimental runtime configuration option "xx-xml-processing". Even when
	 * the view definition is provided as string or object tree, controller or controls might be loaded
	 * asynchronously. In any case, a view instance will be returned synchronously by this factory API, but its
	 * content (control tree) might appear only later. Also see {@link sap.ui.core.mvc.View#loaded}.
	 *
	 * Like with any other control, an id is optional and will be created when missing.
	 *
	 * @param {string} [sId] id of the newly created view
	 * @param {string | object} vView name of a view resource or view configuration as described above.
	 * @param {string} [vView.viewName] name of a view resource in module name notation (without suffix)
	 * @param {string|object} [vView.viewContent] view definition as a JSON string or an object literal
	 * @param {boolean} [vView.async] defines how the view source is loaded and rendered later on
	 * @param {sap.ui.core.mvc.Controller} [vView.controller] controller to be used for this view instance
	 * @public
	 * @static
	 * @deprecated since 1.56: Use {@link sap.ui.core.mvc.JSONView.create JSONView.create} instead.
	 * @return {sap.ui.core.mvc.JSONView} the created JSONView instance
	 */
	sap.ui.jsonview = function(sId, vView) {
		return sap.ui.view(sId, vView, ViewType.JSON);
	};

	/**
	 * The type of the view used for the sap.ui.view factory
	 * function. This property is used by the parsers to define the specific
	 * view type.
	 * @private
	 */
	JSONView._sType = ViewType.JSON;

	/**
	* Flag for feature detection of asynchronous loading/rendering
	* @public
	* @since 1.30
	*/
	JSONView.asyncSupport = true;

	JSONView.prototype.initViewSettings = function(mSettings) {
		if (!mSettings) {
			throw new Error("mSettings must be given");
		}

		// View template handling - no JSON template given
		if (mSettings.viewName && mSettings.viewContent) {
			throw new Error("View name and view content are given. There is no point in doing this, so please decide.");
		} else if (!mSettings.viewName && !mSettings.viewContent) {
			throw new Error("Neither view name nor view content is given. One of them is required.");
		}

		var that = this;
		var fnInitModel = function() {
			if ((that._oJSONView.resourceBundleName || that._oJSONView.resourceBundleUrl) && (!mSettings.models || !mSettings.models[that._oJSONView.resourceBundleAlias])) {
				var model = new ResourceModel({bundleName:that._oJSONView.resourceBundleName, bundleUrl:that._oJSONView.resourceBundleUrl});
				that.setModel(model, that._oJSONView.resourceBundleAlias);
			}
		};

		if (mSettings.viewName) {
			if (mSettings.async) {
				return this._loadTemplate(mSettings.viewName, {async: true}).then(fnInitModel);
			} else {
				this._loadTemplate(mSettings.viewName);
				fnInitModel();
			}
		} else if (mSettings.viewContent) {
			// keep the content as a pseudo property to make cloning work but without supporting mutation
			// TODO model this as a property as soon as write-once-during-init properties become available
			this.mProperties["viewContent"] = mSettings.viewContent;
			if (typeof mSettings.viewContent === "string") {
				this._oJSONView = jQuery.parseJSON(mSettings.viewContent);
				if (!this._oJSONView) { // would lead to errors later on
					throw new Error("error when parsing viewContent: " + mSettings.viewContent);
				}
			} else if (typeof mSettings.viewContent === "object") {
				this._oJSONView = mSettings.viewContent;
			} else {
				throw new Error("viewContent must be a JSON string or object, but is a " + (typeof mSettings.viewContent));
			}
			if (mSettings.async) {
				return Promise.resolve().then(fnInitModel);
			} else {
				fnInitModel();
			}
		} // else does not happen, already checked

	};

	JSONView.prototype.onControllerConnected = function(oController) {
		var that = this;

		// use preprocessors to fix IDs, associations and event handler references
		ManagedObject.runWithPreprocessors(function() {
				// parse
				that.applySettings({ content : that._oJSONView.content}, oController);
			},

			{
				// preprocessors
				id : function(sId) {
					// prefix only if prefix doesn't exist already. Avoids double prefixes
					// for composite components (now done in createId)
					return that.createId(sId);
				},
				// preprocess 'mSettings' for setting the controller as Listener for defined events
				// => make sure to store old preprocessor in case of nested views
				settings : function(oSettings) {
					var oMetadata = this.getMetadata(),
					aValidKeys = oMetadata.getJSONKeys(), // UID names required, they're part of the documented contract
					sKey, oValue, oKeyInfo;
					for (sKey in oSettings) {
						// get info object for the key
						if ( (oKeyInfo = aValidKeys[sKey]) !== undefined ) {
							oValue = oSettings[sKey];
							switch (oKeyInfo._iKind) {
							case 3: // SINGLE ASSOCIATIONS
								// prefix the association ids with the view id
								if ( typeof oValue === "string" ) {
									oSettings[sKey] = that.createId(oValue);
								}
								break;
							case 5: // EVENTS
								if ( typeof oValue === "string" ) {
									oSettings[sKey] = EventHandlerResolver.resolveEventHandler(oValue, oController);
								}
								break;
							}
						}
					}
				}
			});

	};

	/**
	 * Loads and returns the template from a given URL.
	 *
	 * @param {string} sTemplateName The name of the template
	 * @param {object} [mOptions] with view settings
	 * @param {boolean} [mOptions.async=false] whether the action should be performed asynchronously
	 * @return {string|Promise} the template data, or a Promise resolving with it when async
	 * @private
	 */
	JSONView.prototype._loadTemplate = function(sTemplateName, mOptions) {
		var sResourceName = sTemplateName.replace(/\./g, "/") + ".view.json";
		if (!mOptions || !mOptions.async) {
			this._oJSONView = LoaderExtensions.loadResource(sResourceName);
		} else {
			var that = this;
			return LoaderExtensions.loadResource(sResourceName, mOptions).then(function(oJSONView) {
				that._oJSONView = oJSONView;
			});
		}
	};

	JSONView.prototype.getControllerName = function() {
		return this._oJSONView.controllerName;
	};

	return JSONView;

});<|endoftext|>