<commit_before>function syncDefaultOptions() {
  chrome.storage.sync.getBytesInUse(null, (bytes) => {
    if (bytes === 0) {
      chrome.storage.sync.set({
        lowLimit: 13,
        upLimit: 255,
        autoLoad: false,
        autoPlay: false,
      });
    }
  });
}

function setUpContextMenus() {
  chrome.contextMenus.create({ id: 'bracketless', title: 'local.clear()' });
}
function updateContextMenus(text) {
  chrome.contextMenus.update('bracketless', { title: text });
}

function getState(tabId) {
  return new Promise((resolve) => {
    chrome.storage.local.get(tabId.toString(), (state) => {
      console.warn('getState');
      console.log(state[tabId]);
      resolve(state[tabId]);
    });
  });
}

function setLoadState(tabId) {
  console.warn('setLoadState');
  console.log(tabId);
  return new Promise((resolve) => {
    chrome.storage.local.set({ [tabId]: {} }, () => resolve());
  });
}

function setActiveState(tabId, tabState, value) {
  console.warn('setActiveState');
  const activeTabState = tabState;
  activeTabState.active = value;
  console.log(activeTabState);
  return new Promise((resolve) => {
    chrome.storage.local.set({ [tabId]: activeTabState }, () => resolve());
  });
}

function load(tabId) {
  return new Promise((resolve) => {
    chrome.tabs.executeScript(tabId, { file: 'src/bracketless.js' }, () => {
      chrome.browserAction.setIcon({ tabId, path: 'icons/play.png' });
      chrome.browserAction.setTitle({ tabId, title: 'Collapse brackets' });
      // updateContextMenus('Collapse brackets');
      chrome.tabs.insertCSS(tabId, { file: 'css/action.css' });
      chrome.tabs.executeScript(tabId, { file: 'src/action.js' }, () => {
        setLoadState(tabId)
          .then(() => resolve('load resolved')); // { 322: {} }
      });
    });
  });
}

function doAction(tabId, tabState, action) {
  return new Promise((resolve) => {
    const state = action === 'play' ?
      { message: 'Pause collapsing', collapse: true, icon: 'pause' } :
      { message: 'Collapse brackets', collapse: false, icon: 'play' };
    chrome.browserAction.setIcon({ tabId, path: `icons/${state.icon}.png` });
    chrome.browserAction.setTitle({ tabId, title: state.message });
    // updateContextMenus(state.message);
    chrome.tabs.sendMessage(tabId, { collapse: state.collapse }, (response) => {
      console.warn('doAction sendMessage responseFn');
      console.log(response);
      setActiveState(tabId, tabState, state.collapse)
        .then(() => { resolve(`action resolved: ${action}`); }); // { 322: {active: bool}
    });
  });
}

function listenerAction(tabId) {
  getState(tabId)
    .then((tabState) => {
      console.warn('getState.then()');
      console.log(tabState);

      if (!tabState) {
        console.warn('not loaded, load');
        console.log(tabState, '->', !tabState);
        return load(tabId);

      } else if (!tabState.active) {
        console.warn('loaded not active, play');
        console.log(tabState.active, '->', !tabState.active);
        return doAction(tabId, tabState, 'play');

      } else if (tabState.active) {
        console.warn('loaded active, pause');
        console.log(tabState.active, '->', 'doesn\`t use bool reverse');
        return doAction(tabId, tabState, 'pause');
      }
      return Promise.reject(new Error('listenerAction if else didn\'t work'));
    })
    .then((action) => {
      console.log(action);
      console.log('------------------------');
    });
}

function optionalPermsCheck() {
  return new Promise((resolve, reject) => chrome.permissions.contains({
    permissions: ['tabs'],
    origins: ['http://*/', 'https://*/'],
  }, (permission) => {
    if (permission) resolve(permission);
    else reject(new Error(`Bracketless. Tabs at any origins was denied. Permission: ${permission}`));
  }));
}

function autoAction() {
  chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
    // if (this is not the same page AND already loaded) OR (chrome browser utility page) - like "chrome://"
    if ((tabId !== tab.id && loadedTabs[tabId]) || /(chrome)(?:[/:-])/.test(tab.url)) return;
    if (changeInfo.status === 'complete' && tab.active) {
      chrome.storage.sync.get(null, (options) => {
        if (options.autoLoad && options.autoPlay === false) load(tabId);
        if (options.autoLoad && options.autoPlay) {
          load(tabId)
            .then(() => doAction(tabId, 'play'));
        }
      });
    }
  });
}

function localClear() {
  chrome.storage.local.clear(() => {
    chrome.storage.local.get(null, (cleared) => {
      console.warn('local.clear()');
      console.log(cleared);
    });
  });
}

function localGetAll() {
  chrome.storage.local.get(null, (all) => {
    console.warn('local.get(null)');
    console.log(all);
  });
}

// !PRODUCTION BREAKING! Dev QoL (Quality of Life)
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
  if (changeInfo.status === 'complete' && tab.active) {
    // localClear();
    localGetAll();
  }
});

chrome.runtime.onInstalled.addListener(() => {
  syncDefaultOptions();
  setUpContextMenus();
  chrome.browserAction.onClicked.addListener(tab => listenerAction(tab.id));
  chrome.contextMenus.onClicked.addListener((_, tab) => localClear());
  // optionalPermsCheck()
  //   .then(autoAction, e => console.warn(e)); // no permission, just ignore?
});
<commit_msg>Simplify state storing: replace object with bool<commit_after>function syncDefaultOptions() {
  chrome.storage.sync.getBytesInUse(null, (bytes) => {
    if (bytes === 0) {
      chrome.storage.sync.set({
        lowLimit: 13,
        upLimit: 255,
        autoLoad: false,
        autoPlay: false,
      });
    }
  });
}

function setUpContextMenus() {
  chrome.contextMenus.create({ id: 'bracketless', title: 'local.clear()' });
}
function updateContextMenus(text) {
  chrome.contextMenus.update('bracketless', { title: text });
}

function getState(tabId) {
  return new Promise((resolve) => {
    chrome.storage.local.get(tabId.toString(), (state) => {
      console.warn('getState');
      console.log(state[tabId]);
      resolve(state[tabId]);
    });
  });
}

function setLoadState(tabId) {
  console.warn('setLoadState');
  console.log(tabId);
  return new Promise((resolve) => {
    chrome.storage.local.set({ [tabId]: false }, () => resolve());
  });
}

function setActiveState(tabId, tabState, value) {
  console.warn('setActiveState');
  console.log(tabState, value);
  return new Promise((resolve) => {
    chrome.storage.local.set({ [tabId]: value }, () => resolve());
  });
}

function load(tabId) {
  return new Promise((resolve) => {
    chrome.tabs.executeScript(tabId, { file: 'src/bracketless.js' }, () => {
      chrome.browserAction.setIcon({ tabId, path: 'icons/play.png' });
      chrome.browserAction.setTitle({ tabId, title: 'Collapse brackets' });
      // updateContextMenus('Collapse brackets');
      chrome.tabs.insertCSS(tabId, { file: 'css/action.css' });
      chrome.tabs.executeScript(tabId, { file: 'src/action.js' }, () => {
        setLoadState(tabId)
          .then(() => resolve('load resolved')); // { 322: {} }
      });
    });
  });
}

function doAction(tabId, tabState, action) {
  return new Promise((resolve) => {
    const state = action === 'play' ?
      { message: 'Pause collapsing', collapse: true, icon: 'pause' } :
      { message: 'Collapse brackets', collapse: false, icon: 'play' };
    chrome.browserAction.setIcon({ tabId, path: `icons/${state.icon}.png` });
    chrome.browserAction.setTitle({ tabId, title: state.message });
    // updateContextMenus(state.message);
    chrome.tabs.sendMessage(tabId, { collapse: state.collapse }, (response) => {
      console.warn('doAction sendMessage responseFn');
      console.log(response);
      setActiveState(tabId, tabState, state.collapse)
        .then(() => { resolve(`action resolved: ${action}`); }); // { 322: {active: bool}
    });
  });
}

function listenerAction(tabId) {
  getState(tabId)
    .then((tabState) => {
      console.warn('getState.then()');
      console.log(tabState);

      if (tabState === undefined) {
        console.warn('not loaded, load');
        console.log(tabState, '->', !tabState);
        return load(tabId);

      } else if (tabState === false) {
        console.warn('loaded not active, play');
        console.log(tabState, '->', !tabState.active);
        return doAction(tabId, tabState, 'play');

      } else if (tabState === true) {
        console.warn('loaded active, pause');
        console.log(tabState, '->', 'doesn\`t use bool reverse');
        return doAction(tabId, tabState, 'pause');
      }
      return Promise.reject(new Error('listenerAction if else didn\'t work'));
    })
    .then((action) => {
      console.log(action);
      console.log('------------------------');
    });
}

function optionalPermsCheck() {
  return new Promise((resolve, reject) => chrome.permissions.contains({
    permissions: ['tabs'],
    origins: ['http://*/', 'https://*/'],
  }, (permission) => {
    if (permission) resolve(permission);
    else reject(new Error(`Bracketless. Tabs at any origins was denied. Permission: ${permission}`));
  }));
}

function autoAction() {
  chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
    // if (this is not the same page AND already loaded) OR (chrome browser utility page) - like "chrome://"
    if ((tabId !== tab.id && loadedTabs[tabId]) || /(chrome)(?:[/:-])/.test(tab.url)) return;
    if (changeInfo.status === 'complete' && tab.active) {
      chrome.storage.sync.get(null, (options) => {
        if (options.autoLoad && options.autoPlay === false) load(tabId);
        if (options.autoLoad && options.autoPlay) {
          load(tabId)
            .then(() => doAction(tabId, 'play'));
        }
      });
    }
  });
}

function localClear() {
  chrome.storage.local.clear(() => {
    chrome.storage.local.get(null, (cleared) => {
      console.warn('local.clear()');
      console.log(cleared);
    });
  });
}

function localGetAll() {
  chrome.storage.local.get(null, (all) => {
    console.warn('local.get(null)');
    console.log(all);
  });
}

// !PRODUCTION BREAKING! Dev QoL (Quality of Life)
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
  if (changeInfo.status === 'complete' && tab.active) {
    // localClear();
    localGetAll();
  }
});

chrome.runtime.onInstalled.addListener(() => {
  syncDefaultOptions();
  setUpContextMenus();
  chrome.browserAction.onClicked.addListener(tab => listenerAction(tab.id));
  chrome.contextMenus.onClicked.addListener((_, tab) => localClear());
  // optionalPermsCheck()
  //   .then(autoAction, e => console.warn(e)); // no permission, just ignore?
});
<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp'),
    config = {
        app: 'app',
        dist: 'dist',
        port: 9000,
        scripts: function () {
            return this.app + '/scripts/*.js';
        },
        styles: function () {
            return this.app + '/styles';
        },
        html: function () {
            return this.app + '/*.html';
        }
    };

config.scripts.apply(config);
config.styles.apply(config);
config.html.apply(config);

gulp.task('clean', function(cb) {
    require('rimraf')(config.dist, cb);
});

gulp.task('lint', function() {
    var path = config.scripts(),
        jshint = require('gulp-jshint');

    return gulp.src(path)
        .pipe(jshint())
        .pipe(jshint.reporter('default'));
});
<% if (includeSass) { %>
gulp.task('styles', function () {
    var dir = config.styles(),
        sass = require('gulp-sass'),
        cssbeautify = require('gulp-cssbeautify');

    return gulp.src(dir + '/*.scss')
        .pipe(sass({
            outputStyle: 'expanded'
        }))
        .pipe(cssbeautify())
        .pipe(gulp.dest(dir));
});<% } %>

gulp.task('wiredep', function () {
    var wiredep = require('wiredep').stream;
<% if (includeSass) { %>
    gulp.src('app/styles/*.scss')
        .pipe(wiredep({
            directory: 'app/bower_components'
        }))
        .pipe(gulp.dest('app/styles'));
<% } %>
    gulp.src('app/*.html')
        .pipe(wiredep({
            directory: 'app/bower_components'
        }))
        .pipe(gulp.dest('app'));
});

gulp.task('connect', function() {
    var connect = require('connect');
    var app = connect()
        .use(require('connect-livereload')({ port: 35729 }))
        .use(connect.static(config.app))
        .use(connect.directory(config.app));

    require('http').createServer(app)
        .listen(config.port)
        .on('listening', function() {
            console.log('Started connect web server on http://localhost:' + config.port + '.');

            require('opn')('http://localhost:' + config.port);
        });
});

gulp.task('server', [<% if (includeSass) { %>'styles', <% } %>'connect'], function() {
    var jsPath = config.scripts(),
        cssPath = config.styles(),
        htmlPath = config.html(),
        livereload = require('gulp-livereload'),
        server = livereload();
    <% if (includeSass) { %>
    gulp.watch(cssPath + '/**/*.scss', ['styles']);<% } %>

    gulp.watch([cssPath + '/**/*.<%= includeSass ? 'scss' : 'css' %>', jsPath, htmlPath]).on('change', function (file) {
        server.changed(file.path);
    });

    gulp.watch('bower.json', ['wiredep']);
});

gulp.task('images', function(){
    return gulp.src(config.app + '/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}')
        .pipe(gulp.dest(config.dist + '/images'));
});

gulp.task('fonts', function(){
    var cssPath = config.styles();

    return gulp.src(cssPath + '/fonts/*')
        .pipe(gulp.dest(config.dist + '/styles/fonts'));
});

gulp.task('misc', function(){
    return gulp.src([
            config.app + '/*.{ico,png,txt}'
        ])
        .pipe(gulp.dest(config.dist));
});

gulp.task('html', ['lint'<% if (includeSass) { %>, 'styles'<% } %>], function(){
    var htmlPath = config.html(),
        minifycss = require('gulp-minify-css'),
        useref = require('gulp-useref'),
        filter = require('gulp-filter'),
        jsFilter = filter('**/*.js'),
        cssFilter = filter('**/*.css'),
        uglify = require('gulp-uglify');

    return gulp.src(htmlPath)
        .pipe(useref.assets())
        .pipe(jsFilter)
        .pipe(uglify())
        .pipe(jsFilter.restore())
        .pipe(cssFilter)
        .pipe(minifycss())
        .pipe(cssFilter.restore())
        .pipe(useref.restore())
        .pipe(useref())
        .pipe(gulp.dest(config.dist));
});

gulp.task('build', ['clean'], function(){
    gulp.start('images', 'fonts', 'misc', 'html');
});

gulp.task('default', ['build']);<commit_msg>Move 'opn' call to 'server' task instead of 'connect' so that 'opn' will be called after the 'styles' task finishes.<commit_after>'use strict';

var gulp = require('gulp'),
    config = {
        app: 'app',
        dist: 'dist',
        port: 9000,
        scripts: function () {
            return this.app + '/scripts/*.js';
        },
        styles: function () {
            return this.app + '/styles';
        },
        html: function () {
            return this.app + '/*.html';
        }
    };

config.scripts.apply(config);
config.styles.apply(config);
config.html.apply(config);

gulp.task('clean', function(cb) {
    require('rimraf')(config.dist, cb);
});

gulp.task('lint', function() {
    var path = config.scripts(),
        jshint = require('gulp-jshint');

    return gulp.src(path)
        .pipe(jshint())
        .pipe(jshint.reporter('default'));
});
<% if (includeSass) { %>
gulp.task('styles', function () {
    var dir = config.styles(),
        sass = require('gulp-sass'),
        cssbeautify = require('gulp-cssbeautify');

    return gulp.src(dir + '/*.scss')
        .pipe(sass({
            outputStyle: 'expanded'
        }))
        .pipe(cssbeautify())
        .pipe(gulp.dest(dir));
});<% } %>

gulp.task('wiredep', function () {
    var wiredep = require('wiredep').stream;
<% if (includeSass) { %>
    gulp.src('app/styles/*.scss')
        .pipe(wiredep({
            directory: 'app/bower_components'
        }))
        .pipe(gulp.dest('app/styles'));
<% } %>
    gulp.src('app/*.html')
        .pipe(wiredep({
            directory: 'app/bower_components'
        }))
        .pipe(gulp.dest('app'));
});

gulp.task('connect', function() {
    var connect = require('connect');
    var app = connect()
        .use(require('connect-livereload')({ port: 35729 }))
        .use(connect.static(config.app))
        .use(connect.directory(config.app));

    require('http').createServer(app)
        .listen(config.port)
        .on('listening', function() {
            console.log('Started connect web server on http://localhost:' + config.port + '.');
        });
});

gulp.task('server', [<% if (includeSass) { %>'styles', <% } %>'connect'], function() {
    var jsPath = config.scripts(),
        cssPath = config.styles(),
        htmlPath = config.html(),
        livereload = require('gulp-livereload'),
        server = livereload();

    require('opn')('http://localhost:' + config.port);
    <% if (includeSass) { %>
    gulp.watch(cssPath + '/**/*.scss', ['styles']);<% } %>

    gulp.watch([cssPath + '/**/*.<%= includeSass ? 'scss' : 'css' %>', jsPath, htmlPath]).on('change', function (file) {
        server.changed(file.path);
    });

    gulp.watch('bower.json', ['wiredep']);
});

gulp.task('images', function(){
    return gulp.src(config.app + '/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}')
        .pipe(gulp.dest(config.dist + '/images'));
});

gulp.task('fonts', function(){
    var cssPath = config.styles();

    return gulp.src(cssPath + '/fonts/*')
        .pipe(gulp.dest(config.dist + '/styles/fonts'));
});

gulp.task('misc', function(){
    return gulp.src([
            config.app + '/*.{ico,png,txt}'
        ])
        .pipe(gulp.dest(config.dist));
});

gulp.task('html', ['lint'<% if (includeSass) { %>, 'styles'<% } %>], function(){
    var htmlPath = config.html(),
        minifycss = require('gulp-minify-css'),
        useref = require('gulp-useref'),
        filter = require('gulp-filter'),
        jsFilter = filter('**/*.js'),
        cssFilter = filter('**/*.css'),
        uglify = require('gulp-uglify');

    return gulp.src(htmlPath)
        .pipe(useref.assets())
        .pipe(jsFilter)
        .pipe(uglify())
        .pipe(jsFilter.restore())
        .pipe(cssFilter)
        .pipe(minifycss())
        .pipe(cssFilter.restore())
        .pipe(useref.restore())
        .pipe(useref())
        .pipe(gulp.dest(config.dist));
});

gulp.task('build', ['clean'], function(){
    gulp.start('images', 'fonts', 'misc', 'html');
});

gulp.task('default', ['build']);<|endoftext|>


<commit_before>// ---- Angular Hammer ----

// Copyright (c) 2014 Ryan S Mullins <ryan@ryanmullins.org>
// Licensed under the MIT Software License

(function () {
  'use strict';

  // Checking to make sure Hammer and Angular are defined

  if (typeof angular === 'undefined') {
    var angular;

    if (typeof require !== 'undefined' && require) {
      try {
        angular = require('angular');
      } finally {
        return console.log('ERROR: require("angular") could not find the Angular.js module');
      }
    } else if (typeof window.angular !== 'undefined') {
      angular = window.angular;
    } else {
      return console.log('ERROR: Angular Hammer could not find or require() a reference to angular');
    }
  }

  if (typeof Hammer === 'undefined') {
    var Hammer;

    if (typeof require !== 'undefined' && require) {
      try {
        Hammer = require('hammer');
      } catch (e) {
        try {
          Hammer = require('hammerjs');
        } finally {
          return console.log('ERROR: require("hammerjs") could not find the Hammer.js module');
        }
      } finally {
        return console.log('ERROR: require("hammer") could not find the Hammer.js module');
      }
    } else if (typeof window.Hammer !== 'undefined') {
      Hammer = window.Hammer;
    } else {
      return console.log('ERROR: Angular Hammer could not find or require() a reference to Hammer');
    }
  }

  /**
   * Mapping of the gesture event names with the Angular attribute directive
   * names. Follows the form: <directiveName>:<eventName>.
   *
   * @type {Array}
   */
  var gestureTypes = [
    'hmCustom:custom',
    'hmSwipe:swipe',
    'hmSwipeleft:swipeleft',
    'hmSwiperight:swiperight',
    'hmSwipeup:swipeup',
    'hmSwipedown:swipedown',
    'hmPan:pan',
    'hmPanstart:panstart',
    'hmPanmove:panmove',
    'hmPanend:panend',
    'hmPancancel:pancancel',
    'hmPanleft:panleft',
    'hmPanright:panright',
    'hmPanup:panup',
    'hmPandown:pandown',
    'hmPress:press',
    'hmRotate:rotate',
    'hmRotatestart:rotatestart',
    'hmRotatemove:rotatemove',
    'hmRotateend:rotateend',
    'hmRotatecancel:rotatecancel',
    'hmPinch:pinch',
    'hmPinchstart:pinchstart',
    'hmPinchmove:pinchmove',
    'hmPinchend:pinchend',
    'hmPinchcancel:pinchcancel',
    'hmPinchin:pinchin',
    'hmPinchout:pinchout',
    'hmTap:tap',
    'hmDoubletap:doubletap'
  ];

  // ---- Module Definition ----

  /**
   * @module hmTouchEvents
   * @description Angular.js module for adding Hammer.js event listeners to HTML
   * elements using attribute directives
   * @requires angular
   * @requires hammer
   */
  angular.module('hmTouchEvents', []);

  /**
   * Iterates through each gesture type mapping and creates a directive for
   * each of the
   *
   * @param  {String} type Mapping in the form of <directiveName>:<eventName>
   * @return None
   */
  angular.forEach(gestureTypes, function (type) {
    var directive = type.split(':'),
        directiveName = directive[0],
        eventName = directive[1];

    angular.module('hmTouchEvents')
      .directive(directiveName, ['$parse', '$window', function ($parse, $window) {
        return {
          'restrict' : 'A',
          'link' : function (scope, element, attrs) {
            var handlerName = attrs[directiveName],
                handlerExpr = $parse(handlerName),
                handler = function (event) {
                  event.element = element;

                  var phase = scope.$root.$$phase,
                      fn = function () {
                        handlerExpr(scope, {$event: event});
                      };

                  if (scope[handlerName]) {
                    scope[handlerName](event);
                  } else {
                    if (phase === '$apply' || phase === '$digest') {
                      fn();
                    } else {
                      scope.$apply(fn);
                    }
                  }
                },
                managerOpts = angular.fromJson(attrs.hmManagerOptions),
                recognizerOpts = angular.fromJson(attrs.hmRecognizerOptions),
                hammer = element.data('hammer');

            // Check for Hammer and required functionality
            // If no Hammer, maybe bind tap and doubletap to click and dblclick

            if (!Hammer || !$window.addEventListener) {
              if (directiveName === 'hmTap') {
                element.bind('click', handler);
              }

              if (directiveName === 'hmDoubleTap') {
                element.bind('dblclick', handler);
              }

              return;
            }

            // Hammer exists, check for a manager and set up the recognizers.

            if (!hammer) {
              hammer = new Hammer.Manager(element[0], managerOpts);
              element.data('hammer', hammer);
            }

            if (eventName === 'custom') {
              // Handling custom events

              // Custom events require you to define hmRecognizerOptions. If you
              // do not define the this attribute no custom handlers will be created

              if (angular.isArray(recognizerOpts)) {
                // The recognizer options may be stored in an array. In this
                // case, Angular Hammer iterates through the array of options
                // trying to find an occurrence of the options.type in the event
                // name. If it find the type in the event name, it applies those
                // options to the recognizer for events with that name. If it
                // does not find the type in the event name it moves on.

                angular.forEach(recognizerOpts, function (options) {
                  setupRecognizerWithOptions(hammer, options);

                  hammer.on(options.event, handler);
                  scope.$on('$destroy', function () {
                    hammer.destroy();
                  });
                });
              } else if (angular.isObject(recognizerOpts)) {
                // Recognizer options may be stored as an object. In this case,
                // Angular Hammer applies the options directly to the manager
                // instance for this element.

                setupRecognizerWithOptions(hammer, recognizerOpts);

                hammer.on(options.event, handler);
                scope.$on('$destroy', function () {
                  hammer.destroy();
                });
              }
            } else {
              // Handling the standard events

              if (angular.isArray(recognizerOpts)) {
                // The recognizer options may be stored in an array. In this
                // case, Angular Hammer iterates through the array of options
                // trying to find an occurrence of the options.type in the event
                // name. If it find the type in the event name, it applies those
                // options to the recognizer for events with that name. If it
                // does not find the type in the event name it moves on.

                angular.forEach(recognizerOpts, function (options) {
                  if (eventName.indexOf(options.type) > -1) {
                    setupRecognizerWithOptions(hammer, options);
                  }
                });
              } else if (angular.isObject(recognizerOpts) &&
                  eventName.indexOf(recognizerOpts.type) > -1) {
                // Recognizer options may be stored as an object. In this case,
                // Angular Hammer checks to make sure that the options type
                // property is found in the event name. If the options are
                // designated for this general type of event, Angular Hammer
                // applies the options directly to the manager instance for
                // this element.

                setupRecognizerWithOptions(hammer, recognizerOpts);
              } else {
                // If no options are supplied, or the supplied options do not
                // match any of the above conditions, Angular Hammer sets up
                // the default options that a manager instantiated using
                // Hammer() would have.

                recognizerOpts = {'type':eventName};

                if (recognizerOpts.type.indexOf('doubletap') > -1) {
                  recognizerOpts.event = recognizerOpts.type;
                  recognizerOpts.taps = 2;

                  if (hammer.get('tap')) {
                    recognizerOpts.recognizeWith = 'tap';
                  }
                }

                if (recognizerOpts.type.indexOf('pan') > -1 &&
                    hammer.get('swipe')) {
                  recognizerOpts.recognizeWith = 'swipe';
                }

                if (recognizerOpts.type.indexOf('pinch') > -1 &&
                    hammer.get('rotate')) {
                  recognizerOpts.recognizeWith = 'rotate';
                }

                setupRecognizerWithOptions(hammer, recognizerOpts);
              }

              hammer.on(eventName, handler);
              scope.$on('$destroy', function () {
                hammer.destroy();
              });
            }
          }
        };
      }]);
  });

  // ---- Private Functions -----

  /**
   * Adds a gesture recognizer to a given manager. The type of recognizer to
   * add is determined by the value of the options.type property.
   *
   * @param {Object}  manager Hammer.js manager object assigned to an element
   * @param {Object}  options Options that define the recognizer to add
   * @return {Object} Reference to the new gesture recognizer, if successful,
   *                  null otherwise.
   */
  function addRecognizer (manager, options) {
    var recognizer;

    if (options.type) {
      if (options.type.indexOf('pan') > -1) {
        recognizer = new Hammer.Pan(options);
      }

      if (options.type.indexOf('pinch') > -1) {
        recognizer = new Hammer.Pinch(options);
      }

      if (options.type.indexOf('press') > -1) {
        recognizer = new Hammer.Press(options);
      }

      if (options.type.indexOf('rotate') > -1) {
        recognizer = new Hammer.Rotate(options);
      }

      if (options.type.indexOf('swipe') > -1) {
        recognizer = new Hammer.Swipe(options);
      }

      if (options.type.indexOf('tap') > -1) {
        recognizer = new Hammer.Tap(options);
      }
    }

    if (manager && recognizer) {
      manager.add(recognizer);
      return recognizer;
    }
  }

  /**
   * Applies the passed options object to the appropriate gesture recognizer.
   * Recognizers are created if they do not already exist. See the README for a
   * description of the options object that can be passed to this function.
   *
   * @param  {Object} manager Hammer.js manager object assigned to an element
   * @param  {Object} options Options applied to a recognizer managed by manager
   * @return None
   */
  function setupRecognizerWithOptions (manager, options) {
    var recognizer = manager.get(options.type);

    if (!recognizer) {
      recognizer = addRecognizer(manager, options);
    }

    if (options) {
      if (options.directions) {
        options.direction = parseDirections(options.directions);
      }

      recognizer.set(options);
    }

    if (options.recognizeWith) {
      recognizer.recognizeWith(options.recognizeWith);
    }

    if (options.dropRecognizeWith) {
      recognizer.dropRecognizeWith(options.dropRecognizeWith);
    }

    if (options.requireFailure) {
      recognizer.requireFailure(options.requireFailure);
    }

    if (options.dropRequireFailure) {
      recognizer.dropRequireFailure(options.dropRequireFailure);
    }
  }

  /**
   * Parses the value of the directions property of any Angular Hammer options
   * object and converts them into the standard Hammer.js directions values.
   *
   * @param  {String} dirs Direction names separated by '|' characters
   * @return {Number}      Hammer.js direction value
   */
  function parseDirections (dirs) {
    var directions = 0;

    angular.forEach(dirs.split('|'), function (direction) {
      if (Hammer.hasOwnProperty(direction)) {
        directions = directions | Hammer[direction];
      }
    });

    return directions;
  }
})();
<commit_msg>clean up the loading code<commit_after>// ---- Angular Hammer ----

// Copyright (c) 2014 Ryan S Mullins <ryan@ryanmullins.org>
// Licensed under the MIT Software License

(function () {
  'use strict';

  // Checking to make sure Hammer and Angular are defined
  var angular, Hammer;

  if (typeof angular === 'undefined') {
    if (typeof require !== 'undefined' && require) {
      angular = require('angular');
    } else if (typeof window.angular !== 'undefined') {
      angular = window.angular;
    } else {
      return console.log('ERROR: Angular Hammer could not find or require() a reference to angular');
    }
  }

  if (typeof Hammer === 'undefined') {
    if (typeof require !== 'undefined' && require) {
      try {
        Hammer = require('hammerjs');
      } catch (e) {
        try {
          Hammer = require('hammer');
        } catch (e) {
          return console.log('ERROR: Angular Hammer could not require() a reference to Hammer');
        }
      }
    } else if (typeof window.Hammer !== 'undefined') {
      Hammer = window.Hammer;
    } else {
      return console.log('ERROR: Angular Hammer could not find or require() a reference to Hammer');
    }
  }

  /**
   * Mapping of the gesture event names with the Angular attribute directive
   * names. Follows the form: <directiveName>:<eventName>.
   *
   * @type {Array}
   */
  var gestureTypes = [
    'hmCustom:custom',
    'hmSwipe:swipe',
    'hmSwipeleft:swipeleft',
    'hmSwiperight:swiperight',
    'hmSwipeup:swipeup',
    'hmSwipedown:swipedown',
    'hmPan:pan',
    'hmPanstart:panstart',
    'hmPanmove:panmove',
    'hmPanend:panend',
    'hmPancancel:pancancel',
    'hmPanleft:panleft',
    'hmPanright:panright',
    'hmPanup:panup',
    'hmPandown:pandown',
    'hmPress:press',
    'hmRotate:rotate',
    'hmRotatestart:rotatestart',
    'hmRotatemove:rotatemove',
    'hmRotateend:rotateend',
    'hmRotatecancel:rotatecancel',
    'hmPinch:pinch',
    'hmPinchstart:pinchstart',
    'hmPinchmove:pinchmove',
    'hmPinchend:pinchend',
    'hmPinchcancel:pinchcancel',
    'hmPinchin:pinchin',
    'hmPinchout:pinchout',
    'hmTap:tap',
    'hmDoubletap:doubletap'
  ];

  // ---- Module Definition ----

  /**
   * @module hmTouchEvents
   * @description Angular.js module for adding Hammer.js event listeners to HTML
   * elements using attribute directives
   * @requires angular
   * @requires hammer
   */
  angular.module('hmTouchEvents', []);

  /**
   * Iterates through each gesture type mapping and creates a directive for
   * each of the
   *
   * @param  {String} type Mapping in the form of <directiveName>:<eventName>
   * @return None
   */
  angular.forEach(gestureTypes, function (type) {
    var directive = type.split(':'),
        directiveName = directive[0],
        eventName = directive[1];

    angular.module('hmTouchEvents')
      .directive(directiveName, ['$parse', '$window', function ($parse, $window) {
        return {
          'restrict' : 'A',
          'link' : function (scope, element, attrs) {
            var handlerName = attrs[directiveName],
                handlerExpr = $parse(handlerName),
                handler = function (event) {
                  event.element = element;

                  var phase = scope.$root.$$phase,
                      fn = function () {
                        handlerExpr(scope, {$event: event});
                      };

                  if (scope[handlerName]) {
                    scope[handlerName](event);
                  } else {
                    if (phase === '$apply' || phase === '$digest') {
                      fn();
                    } else {
                      scope.$apply(fn);
                    }
                  }
                },
                managerOpts = angular.fromJson(attrs.hmManagerOptions),
                recognizerOpts = angular.fromJson(attrs.hmRecognizerOptions),
                hammer = element.data('hammer');

            // Check for Hammer and required functionality
            // If no Hammer, maybe bind tap and doubletap to click and dblclick

            if (!Hammer || !$window.addEventListener) {
              if (directiveName === 'hmTap') {
                element.bind('click', handler);
              }

              if (directiveName === 'hmDoubleTap') {
                element.bind('dblclick', handler);
              }

              return;
            }

            // Hammer exists, check for a manager and set up the recognizers.

            if (!hammer) {
              hammer = new Hammer.Manager(element[0], managerOpts);
              element.data('hammer', hammer);
            }

            if (eventName === 'custom') {
              // Handling custom events

              // Custom events require you to define hmRecognizerOptions. If you
              // do not define the this attribute no custom handlers will be created

              if (angular.isArray(recognizerOpts)) {
                // The recognizer options may be stored in an array. In this
                // case, Angular Hammer iterates through the array of options
                // trying to find an occurrence of the options.type in the event
                // name. If it find the type in the event name, it applies those
                // options to the recognizer for events with that name. If it
                // does not find the type in the event name it moves on.

                angular.forEach(recognizerOpts, function (options) {
                  setupRecognizerWithOptions(hammer, options);

                  hammer.on(options.event, handler);
                  scope.$on('$destroy', function () {
                    hammer.destroy();
                  });
                });
              } else if (angular.isObject(recognizerOpts)) {
                // Recognizer options may be stored as an object. In this case,
                // Angular Hammer applies the options directly to the manager
                // instance for this element.

                setupRecognizerWithOptions(hammer, recognizerOpts);

                hammer.on(options.event, handler);
                scope.$on('$destroy', function () {
                  hammer.destroy();
                });
              }
            } else {
              // Handling the standard events

              if (angular.isArray(recognizerOpts)) {
                // The recognizer options may be stored in an array. In this
                // case, Angular Hammer iterates through the array of options
                // trying to find an occurrence of the options.type in the event
                // name. If it find the type in the event name, it applies those
                // options to the recognizer for events with that name. If it
                // does not find the type in the event name it moves on.

                angular.forEach(recognizerOpts, function (options) {
                  if (eventName.indexOf(options.type) > -1) {
                    setupRecognizerWithOptions(hammer, options);
                  }
                });
              } else if (angular.isObject(recognizerOpts) &&
                  eventName.indexOf(recognizerOpts.type) > -1) {
                // Recognizer options may be stored as an object. In this case,
                // Angular Hammer checks to make sure that the options type
                // property is found in the event name. If the options are
                // designated for this general type of event, Angular Hammer
                // applies the options directly to the manager instance for
                // this element.

                setupRecognizerWithOptions(hammer, recognizerOpts);
              } else {
                // If no options are supplied, or the supplied options do not
                // match any of the above conditions, Angular Hammer sets up
                // the default options that a manager instantiated using
                // Hammer() would have.

                recognizerOpts = {'type':eventName};

                if (recognizerOpts.type.indexOf('doubletap') > -1) {
                  recognizerOpts.event = recognizerOpts.type;
                  recognizerOpts.taps = 2;

                  if (hammer.get('tap')) {
                    recognizerOpts.recognizeWith = 'tap';
                  }
                }

                if (recognizerOpts.type.indexOf('pan') > -1 &&
                    hammer.get('swipe')) {
                  recognizerOpts.recognizeWith = 'swipe';
                }

                if (recognizerOpts.type.indexOf('pinch') > -1 &&
                    hammer.get('rotate')) {
                  recognizerOpts.recognizeWith = 'rotate';
                }

                setupRecognizerWithOptions(hammer, recognizerOpts);
              }

              hammer.on(eventName, handler);
              scope.$on('$destroy', function () {
                hammer.destroy();
              });
            }
          }
        };
      }]);
  });

  // ---- Private Functions -----

  /**
   * Adds a gesture recognizer to a given manager. The type of recognizer to
   * add is determined by the value of the options.type property.
   *
   * @param {Object}  manager Hammer.js manager object assigned to an element
   * @param {Object}  options Options that define the recognizer to add
   * @return {Object} Reference to the new gesture recognizer, if successful,
   *                  null otherwise.
   */
  function addRecognizer (manager, options) {
    var recognizer;

    if (options.type) {
      if (options.type.indexOf('pan') > -1) {
        recognizer = new Hammer.Pan(options);
      }

      if (options.type.indexOf('pinch') > -1) {
        recognizer = new Hammer.Pinch(options);
      }

      if (options.type.indexOf('press') > -1) {
        recognizer = new Hammer.Press(options);
      }

      if (options.type.indexOf('rotate') > -1) {
        recognizer = new Hammer.Rotate(options);
      }

      if (options.type.indexOf('swipe') > -1) {
        recognizer = new Hammer.Swipe(options);
      }

      if (options.type.indexOf('tap') > -1) {
        recognizer = new Hammer.Tap(options);
      }
    }

    if (manager && recognizer) {
      manager.add(recognizer);
      return recognizer;
    }
  }

  /**
   * Applies the passed options object to the appropriate gesture recognizer.
   * Recognizers are created if they do not already exist. See the README for a
   * description of the options object that can be passed to this function.
   *
   * @param  {Object} manager Hammer.js manager object assigned to an element
   * @param  {Object} options Options applied to a recognizer managed by manager
   * @return None
   */
  function setupRecognizerWithOptions (manager, options) {
    var recognizer = manager.get(options.type);

    if (!recognizer) {
      recognizer = addRecognizer(manager, options);
    }

    if (options) {
      if (options.directions) {
        options.direction = parseDirections(options.directions);
      }

      recognizer.set(options);
    }

    if (options.recognizeWith) {
      recognizer.recognizeWith(options.recognizeWith);
    }

    if (options.dropRecognizeWith) {
      recognizer.dropRecognizeWith(options.dropRecognizeWith);
    }

    if (options.requireFailure) {
      recognizer.requireFailure(options.requireFailure);
    }

    if (options.dropRequireFailure) {
      recognizer.dropRequireFailure(options.dropRequireFailure);
    }
  }

  /**
   * Parses the value of the directions property of any Angular Hammer options
   * object and converts them into the standard Hammer.js directions values.
   *
   * @param  {String} dirs Direction names separated by '|' characters
   * @return {Number}      Hammer.js direction value
   */
  function parseDirections (dirs) {
    var directions = 0;

    angular.forEach(dirs.split('|'), function (direction) {
      if (Hammer.hasOwnProperty(direction)) {
        directions = directions | Hammer[direction];
      }
    });

    return directions;
  }
})();
<|endoftext|>


<commit_before>/*
* Copyright 2010-2011 Research In Motion Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/** Called automatically by JsDoc Toolkit. */
function publish(symbolSet) {
    publish.conf = { // trailing slash expected for dirs
        ext : ".html",
        outDir : JSDOC.opt.d || SYS.pwd + "../out/jsdoc/",
        templatesDir : JSDOC.opt.t || SYS.pwd + "../templates/jsdoc/",
        staticDir : "static/",
        symbolsDir : "",
        srcDir : "src/",
        cssDir : "css/",
        imagesDir : "images/",
        jsDir : "javascript/",
        templateName : "BBTest",
        templateVersion : "0.1"
    };

    // is source output is suppressed, just display the links to the source file
    if (JSDOC.opt.s && defined(Link) && Link.prototype._makeSrcLink) {
        Link.prototype._makeSrcLink = function(srcFilePath) {
            return "<" + srcFilePath + ">";
        }
    }

    // create the folders and subfolders to hold the output
    IO.mkPath((publish.conf.outDir + publish.conf.imagesDir));
    /* These paths are no longer used
    IO.mkPath((publish.conf.outDir + publish.conf.cssDir));
    IO.mkPath((publish.conf.outDir + publish.conf.jsDir));
    IO.mkPath((publish.conf.outDir + publish.conf.srcDir));
    */

    // used to allow Link to check the details of things being linked to
    Link.symbolSet = symbolSet;

    // create the required templates
    try {
		var classTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"class.tmpl");
        var ditamapTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"ditamap.tmpl");
        var JSONTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"JSON.tmpl");
        var PHPTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"PHP.tmpl");
        // var viewableClassTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"viewableClass.tmpl");
	}
	catch(e) {
        print("Couldn't create the required templates: " + e);
        quit();
    }

    // some utility filters
	function hasNoParent($) {return ($.memberOf == "");};
	function isaFile($) {return ($.is("FILE"));};
	function isaClass($) {return ($.is("CONSTRUCTOR") || $.isNamespace) && !($.alias == "_global_");};

    // get an array version of the symbolset, useful for filtering
    var symbols = symbolSet.toArray();

    // get a list of all the classes in the symbolset
    var classes = symbols.filter(isaClass).sort(makeSortby("name"));

	// create a filemap in which outfiles must be to be named uniquely, ignoring case
    if (JSDOC.opt.u) {
        var filemapCounts = {};
        Link.filemap = {};
        for ( var i = 0, l = classes.length; i < l; i++) {
            var lcAlias = classes[i].alias.toLowerCase();

			if (!filemapCounts[lcAlias]) filemapCounts[lcAlias] = 1;
			else filemapCounts[lcAlias]++;

			Link.filemap[classes[i].alias] =
				(filemapCounts[lcAlias] > 1)?
				lcAlias+"_"+filemapCounts[lcAlias] : lcAlias;
        }
    }

    // create each of the class pages
    for ( var i = 0, l = classes.length; i < l; i++) {
        var symbol = classes[i];

        symbol.events = symbol.getEvents(); // 1 order matters
        symbol.methods = symbol.getMethods(); // 2

        Link.currentSymbol = symbol;
        Link.base="";

        var output = classTemplate.process(symbol);
		IO.saveFile(publish.conf.outDir, ((JSDOC.opt.u)? Link.filemap[symbol.alias] : symbol.alias) + publish.conf.ext, output);
    }

    // Generate the toc page
    Link.base = "";

    var classes = classes.filter(function ($) {return ($.toc)} ).sort(makeTocSort());

    var processedDitamap = ditamapTemplate.process(classes);
    IO.saveFile(publish.conf.outDir, "toc.ditamap", processedDitamap);

    var processedJSON = JSONTemplate.process(classes);
    IO.saveFile(publish.conf.outDir, "menu-apis.php.json", processedJSON);

    var processedPHP = PHPTemplate.process(classes);
    IO.saveFile(publish.conf.outDir, "menu-apis.php", processedPHP);

    // COPY FILES
    // CSS files
	// copyFiles(publish.conf.templatesDir+"/"+publish.conf.cssDir,publish.conf.outDir+"/"+publish.conf.cssDir );
    // Static files
	copyFiles(publish.conf.templatesDir+"/"+publish.conf.staticDir,publish.conf.outDir );
    // Image Files
	// copyFiles(publish.conf.templatesDir+"/"+publish.conf.imagesDir,publish.conf.outDir+"/"+publish.conf.imagesDir );
    // JS Files
	// copyFiles(publish.conf.templatesDir+"/"+publish.conf.jsDir,publish.conf.outDir+"/"+publish.conf.jsDir );

}

function copyFiles(srcDir, destDir) {
    if (IO.exists(srcDir)) {
        var files = IO.ls(srcDir);
        for ( var i = 0; i < files.length; i++) {
            IO.copyFile(files[i], destDir);
        }
    }
}

/** Just the first sentence (up to a full stop). Should not break on dotted variable names. */
function summarize(desc) {
    if (typeof desc != "undefined")
        return desc.match(/([\w\W]+?\.)[^a-z0-9_$]/i) ? RegExp.$1 : desc;
}

/** Make a symbol sorter by some attribute. */
function makeSortby(attribute) {
	return function(a, b) {
		try{
		if (a[attribute] != undefined && b[attribute] != undefined) {
			if (a[attribute].toLowerCase && b[attribute].toLowerCase) {
				a = a[attribute].toLowerCase();
				b = b[attribute].toLowerCase();
			}
			if (a  b) return 1;
                return 0;
            }
        } catch (e) {
            print("Couldn't sort by attribute " + attribute + ": " + e);
        }
    }
}

/** Make a symbol sorter by some attribute. */
function makeNameSort() {
    return function(a, b) {
        try {
            a = getSymbolName(a);
            b = getSymbolName(b);
            if (a  b)
                return 1;
            return 0;
        } catch (e) {
            print("Couldn't sort by attribute " + attribute + ": " + e);
        }
    }
}

function makeSpecialSortby(attribute1, attribute2) {
    return function(a, b) {
        try {
		if (a[attribute1] != undefined && a[attribute1][attribute2] != undefined  && b[attribute1] != undefined && b[attribute1][attribute2] != undefined ) {
                a = a[attribute1][attribute2].toLowerCase();
                b = b[attribute1][attribute2].toLowerCase();
			if (a  b) return 1;
                return 0;
            }
        } catch (e) {
            print("Couldn't sort by attribute " + attribute + ": " + e);
        }
    }
}

function makeTocSort() {
    return function(a, b) {
        try {
            var baseAttribute = "toc";
            var subAttribute1 = "type";
            var subAttribute2 = "desc";
			if (a[baseAttribute] != undefined &&
			    a[baseAttribute][subAttribute1] != undefined  &&
			    a[baseAttribute][subAttribute2] != undefined  &&
			    b[baseAttribute] != undefined &&
			    a[baseAttribute][subAttribute1] != undefined  &&
			    b[baseAttribute][subAttribute2] != undefined ) {
				a = a[baseAttribute][subAttribute1].toLowerCase() + a[baseAttribute][subAttribute2].toLowerCase();
				b = b[baseAttribute][subAttribute1].toLowerCase() + b[baseAttribute][subAttribute2].toLowerCase();
				//print("Comparing " + a + " and " +b + " and result is " + (a>b?1:(a<b?-1:0)) );
				if (a  b) return 1;
                return 0;
            }
        } catch (e) {
            print("Couldn't sort by attribute " + attribute + ": " + e);
        }
    }
}

/** Pull in the contents of an external file at the given path. */
function include(path) {
    var path = publish.conf.templatesDir + path;
    return IO.readFile(path);
}

/** Turn a raw source file into a code-hilited page in the docs. */
function makeSrcFile(path, srcDir, name) {
	if (JSDOC.opt.s) return;

    if (!name) {
        name = path.replace(/\.\.?[\\\/]/g, "").replace(/[\\\/]/g, "_");
        name = name.replace(/\:/g, "_");
    }

	var src = {path: path, name:name, charset: IO.encoding, hilited: ""};

    if (defined(JSDOC.PluginManager)) {
        JSDOC.PluginManager.run("onPublishSrc", src);
    }

    if (src.hilited) {
        IO.saveFile(srcDir, name + publish.conf.ext, src.hilited);
    }
}

/** Build output for displaying function parameters. */
function makeSignature(params) {
	if (!params) return "()";
	var signature = "("
	+
	params.filter(
		function($) {
			return $.name.indexOf(".") == -1; // don't show config params in signature
		}
	).map(
		function($) {
        if ($.isOptional) {
            return "[" + $.name + ": " + $.type + "]";
        } else {
            return $.name + " : " + $.type;
        }
		}
	).join(", ")
	+
	")";
    return signature;
}

/** Build output for displaying Callback function parameters.
 *  These differ because
 *  	callbacks only have subParams (will not be filtered),
 *  	the names of the params are sliced
 *		the type is a link to the actual type
 **/
function makeCallbackSignature(params) {
	if (!params) return "()";
    var signature = "("
	+
	params.map(
                    function($) {
			var name = ($.name.indexOf(".") != -1) ? ($.name.slice($.name.indexOf('.')+1, $.name.length)) : $.name;
			var type = (($.type)?(new Link().toSymbol($.type)) : "");
                        if ($.isOptional) {
                            return "[" + name + ": " + type + "]";
                        } else {
                            return name + " : " + type;
                        }
		}
	).join(", ")
	+
	")";
    return signature;
}

/** Find symbol {@link ...} strings in text and turn into html links */
function resolveLinks(str, from) {
    str = str.replace(/\{@link ([^} ]+) ?\}/gi,
        function(match, symbolName) {
            var symbol = JSDOC.Parser.symbols.getSymbol(symbolName);
            var textSymbolName = symbol ? getSymbolName(symbol) : symbolName;
            return new Link().toSymbol(symbolName).withText(textSymbolName);
    });

	str = str.replace(/\{@image ([^} ]+) ?\}/gi,
		function(match, symbolName) {

        // Find filename independant of slashes used
        var fileName = symbolName.substring(symbolName.lastIndexOf("\\") + 1);
        var fileName = symbolName.substring(symbolName.lastIndexOf("/") + 1);
        // Try catch to ignore missing files
        // Use for loop to try all source locations
        try {
            for ( var i = 0; i < JSDOC.opt._.length; i++) {
					IO.copyFile(JSDOC.opt._[i]+"/"+symbolName, publish.conf.outDir+"/"+publish.conf.imagesDir);
            }
			}catch(e){}
			return "<image src=\""+publish.conf.imagesDir + fileName+"\">";
        }
	);

    return str;
}

function getSymbolName(symbol, forSummary) {
    if(symbol.is('CONSTRUCTOR')){
        return symbol.alias.replace(/\^\d+$/, '').toString().replace(/\|/g, ' | ');
    }else if (symbol.constructedBy){
        return symbol.constructedBy.toString().replace("[\^][\d]", '');
    }else if (symbol.squareAccessor) {
        return "[]";
    } else if (symbol.uri) {
        return "webworks://" + symbol.alias.replace(/\./g, "/").replace("[\^][\d]", '');
    } else if (symbol.isStatic && !forSummary) {
        return symbol.memberOf + "." + symbol.name.replace(/\^\d+$/, '').replace("[\^][\d]", '');
    } else {
        return symbol.name.replace(/\^\d+$/, '').replace("[\^][\d]", '');
    }
}

function isMethod($)      {return (!$.isNamespace && !$.uri && !$.isConstant && !$.constructedBy);};
function isURIMethod($)   {return (!$.isNamespace && $.uri  && !$.isConstant && !$.constructedBy);};
function isConstructor($) {return ((!$.isNamespace && !$.uri && !$.isConstant && $.constructedBy) || ($.is('CONSTRUCTOR')));};
function isProperty($)    {return (!$.isNamespace && !$.uri && !$.isConstant && !$.constructedBy);};
function isConstant($)    {return (!$.isNamespace && !$.uri && $.isConstant  && !$.constructedBy);};
function isEvent($)       {return (!$.isNamespace && !$.uri && !$.isConstant && !$.constructedBy);};

function isBlank(str) { return (!str || /^\s*$/.test(str)); };

/** Include a sub-template in the current template, specifying a data object */
function subtemplate(template, data) {
	try {
		return new JSDOC.JsPlate(publish.conf.templatesDir+template).process(data);
	}
	catch(e) { print(e.message); quit(); }
}
<commit_msg>Updating templates to stop producing toc.ditamap<commit_after>/*
* Copyright 2010-2011 Research In Motion Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/** Called automatically by JsDoc Toolkit. */
function publish(symbolSet) {
    publish.conf = { // trailing slash expected for dirs
        ext : ".html",
        outDir : JSDOC.opt.d || SYS.pwd + "../out/jsdoc/",
        templatesDir : JSDOC.opt.t || SYS.pwd + "../templates/jsdoc/",
        staticDir : "static/",
        symbolsDir : "",
        srcDir : "src/",
        cssDir : "css/",
        imagesDir : "images/",
        jsDir : "javascript/",
        templateName : "BBTest",
        templateVersion : "0.1"
    };

    // is source output is suppressed, just display the links to the source file
    if (JSDOC.opt.s && defined(Link) && Link.prototype._makeSrcLink) {
        Link.prototype._makeSrcLink = function(srcFilePath) {
            return "<" + srcFilePath + ">";
        }
    }

    // create the folders and subfolders to hold the output
    IO.mkPath((publish.conf.outDir + publish.conf.imagesDir));
    /* These paths are no longer used
    IO.mkPath((publish.conf.outDir + publish.conf.cssDir));
    IO.mkPath((publish.conf.outDir + publish.conf.jsDir));
    IO.mkPath((publish.conf.outDir + publish.conf.srcDir));
    */

    // used to allow Link to check the details of things being linked to
    Link.symbolSet = symbolSet;

    // create the required templates
    try {
		var classTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"class.tmpl");
        // var ditamapTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"ditamap.tmpl");
        var JSONTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"JSON.tmpl");
        var PHPTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"PHP.tmpl");
        // var viewableClassTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"viewableClass.tmpl");
	}
	catch(e) {
        print("Couldn't create the required templates: " + e);
        quit();
    }

    // some utility filters
	function hasNoParent($) {return ($.memberOf == "");};
	function isaFile($) {return ($.is("FILE"));};
	function isaClass($) {return ($.is("CONSTRUCTOR") || $.isNamespace) && !($.alias == "_global_");};

    // get an array version of the symbolset, useful for filtering
    var symbols = symbolSet.toArray();

    // get a list of all the classes in the symbolset
    var classes = symbols.filter(isaClass).sort(makeSortby("name"));

	// create a filemap in which outfiles must be to be named uniquely, ignoring case
    if (JSDOC.opt.u) {
        var filemapCounts = {};
        Link.filemap = {};
        for ( var i = 0, l = classes.length; i < l; i++) {
            var lcAlias = classes[i].alias.toLowerCase();

			if (!filemapCounts[lcAlias]) filemapCounts[lcAlias] = 1;
			else filemapCounts[lcAlias]++;

			Link.filemap[classes[i].alias] =
				(filemapCounts[lcAlias] > 1)?
				lcAlias+"_"+filemapCounts[lcAlias] : lcAlias;
        }
    }

    // create each of the class pages
    for ( var i = 0, l = classes.length; i < l; i++) {
        var symbol = classes[i];

        symbol.events = symbol.getEvents(); // 1 order matters
        symbol.methods = symbol.getMethods(); // 2

        Link.currentSymbol = symbol;
        Link.base="";

        var output = classTemplate.process(symbol);
		IO.saveFile(publish.conf.outDir, ((JSDOC.opt.u)? Link.filemap[symbol.alias] : symbol.alias) + publish.conf.ext, output);
    }

    // Generate the toc page
    Link.base = "";

    var classes = classes.filter(function ($) {return ($.toc)} ).sort(makeTocSort());

    // var processedDitamap = ditamapTemplate.process(classes);
    // IO.saveFile(publish.conf.outDir, "toc.ditamap", processedDitamap);

    var processedJSON = JSONTemplate.process(classes);
    IO.saveFile(publish.conf.outDir, "menu-apis.php.json", processedJSON);

    var processedPHP = PHPTemplate.process(classes);
    IO.saveFile(publish.conf.outDir, "menu-apis.php", processedPHP);

    // COPY FILES
    // CSS files
	// copyFiles(publish.conf.templatesDir+"/"+publish.conf.cssDir,publish.conf.outDir+"/"+publish.conf.cssDir );
    // Static files
	copyFiles(publish.conf.templatesDir+"/"+publish.conf.staticDir,publish.conf.outDir );
    // Image Files
	// copyFiles(publish.conf.templatesDir+"/"+publish.conf.imagesDir,publish.conf.outDir+"/"+publish.conf.imagesDir );
    // JS Files
	// copyFiles(publish.conf.templatesDir+"/"+publish.conf.jsDir,publish.conf.outDir+"/"+publish.conf.jsDir );

}

function copyFiles(srcDir, destDir) {
    if (IO.exists(srcDir)) {
        var files = IO.ls(srcDir);
        for ( var i = 0; i < files.length; i++) {
            IO.copyFile(files[i], destDir);
        }
    }
}

/** Just the first sentence (up to a full stop). Should not break on dotted variable names. */
function summarize(desc) {
    if (typeof desc != "undefined")
        return desc.match(/([\w\W]+?\.)[^a-z0-9_$]/i) ? RegExp.$1 : desc;
}

/** Make a symbol sorter by some attribute. */
function makeSortby(attribute) {
	return function(a, b) {
		try{
		if (a[attribute] != undefined && b[attribute] != undefined) {
			if (a[attribute].toLowerCase && b[attribute].toLowerCase) {
				a = a[attribute].toLowerCase();
				b = b[attribute].toLowerCase();
			}
			if (a  b) return 1;
                return 0;
            }
        } catch (e) {
            print("Couldn't sort by attribute " + attribute + ": " + e);
        }
    }
}

/** Make a symbol sorter by some attribute. */
function makeNameSort() {
    return function(a, b) {
        try {
            a = getSymbolName(a);
            b = getSymbolName(b);
            if (a  b)
                return 1;
            return 0;
        } catch (e) {
            print("Couldn't sort by attribute " + attribute + ": " + e);
        }
    }
}

function makeSpecialSortby(attribute1, attribute2) {
    return function(a, b) {
        try {
		if (a[attribute1] != undefined && a[attribute1][attribute2] != undefined  && b[attribute1] != undefined && b[attribute1][attribute2] != undefined ) {
                a = a[attribute1][attribute2].toLowerCase();
                b = b[attribute1][attribute2].toLowerCase();
			if (a  b) return 1;
                return 0;
            }
        } catch (e) {
            print("Couldn't sort by attribute " + attribute + ": " + e);
        }
    }
}

function makeTocSort() {
    return function(a, b) {
        try {
            var baseAttribute = "toc";
            var subAttribute1 = "type";
            var subAttribute2 = "desc";
			if (a[baseAttribute] != undefined &&
			    a[baseAttribute][subAttribute1] != undefined  &&
			    a[baseAttribute][subAttribute2] != undefined  &&
			    b[baseAttribute] != undefined &&
			    a[baseAttribute][subAttribute1] != undefined  &&
			    b[baseAttribute][subAttribute2] != undefined ) {
				a = a[baseAttribute][subAttribute1].toLowerCase() + a[baseAttribute][subAttribute2].toLowerCase();
				b = b[baseAttribute][subAttribute1].toLowerCase() + b[baseAttribute][subAttribute2].toLowerCase();
				//print("Comparing " + a + " and " +b + " and result is " + (a>b?1:(a<b?-1:0)) );
				if (a  b) return 1;
                return 0;
            }
        } catch (e) {
            print("Couldn't sort by attribute " + attribute + ": " + e);
        }
    }
}

/** Pull in the contents of an external file at the given path. */
function include(path) {
    var path = publish.conf.templatesDir + path;
    return IO.readFile(path);
}

/** Turn a raw source file into a code-hilited page in the docs. */
function makeSrcFile(path, srcDir, name) {
	if (JSDOC.opt.s) return;

    if (!name) {
        name = path.replace(/\.\.?[\\\/]/g, "").replace(/[\\\/]/g, "_");
        name = name.replace(/\:/g, "_");
    }

	var src = {path: path, name:name, charset: IO.encoding, hilited: ""};

    if (defined(JSDOC.PluginManager)) {
        JSDOC.PluginManager.run("onPublishSrc", src);
    }

    if (src.hilited) {
        IO.saveFile(srcDir, name + publish.conf.ext, src.hilited);
    }
}

/** Build output for displaying function parameters. */
function makeSignature(params) {
	if (!params) return "()";
	var signature = "("
	+
	params.filter(
		function($) {
			return $.name.indexOf(".") == -1; // don't show config params in signature
		}
	).map(
		function($) {
        if ($.isOptional) {
            return "[" + $.name + ": " + $.type + "]";
        } else {
            return $.name + " : " + $.type;
        }
		}
	).join(", ")
	+
	")";
    return signature;
}

/** Build output for displaying Callback function parameters.
 *  These differ because
 *  	callbacks only have subParams (will not be filtered),
 *  	the names of the params are sliced
 *		the type is a link to the actual type
 **/
function makeCallbackSignature(params) {
	if (!params) return "()";
    var signature = "("
	+
	params.map(
                    function($) {
			var name = ($.name.indexOf(".") != -1) ? ($.name.slice($.name.indexOf('.')+1, $.name.length)) : $.name;
			var type = (($.type)?(new Link().toSymbol($.type)) : "");
                        if ($.isOptional) {
                            return "[" + name + ": " + type + "]";
                        } else {
                            return name + " : " + type;
                        }
		}
	).join(", ")
	+
	")";
    return signature;
}

/** Find symbol {@link ...} strings in text and turn into html links */
function resolveLinks(str, from) {
    str = str.replace(/\{@link ([^} ]+) ?\}/gi,
        function(match, symbolName) {
            var symbol = JSDOC.Parser.symbols.getSymbol(symbolName);
            var textSymbolName = symbol ? getSymbolName(symbol) : symbolName;
            return new Link().toSymbol(symbolName).withText(textSymbolName);
    });

	str = str.replace(/\{@image ([^} ]+) ?\}/gi,
		function(match, symbolName) {

        // Find filename independant of slashes used
        var fileName = symbolName.substring(symbolName.lastIndexOf("\\") + 1);
        var fileName = symbolName.substring(symbolName.lastIndexOf("/") + 1);
        // Try catch to ignore missing files
        // Use for loop to try all source locations
        try {
            for ( var i = 0; i < JSDOC.opt._.length; i++) {
					IO.copyFile(JSDOC.opt._[i]+"/"+symbolName, publish.conf.outDir+"/"+publish.conf.imagesDir);
            }
			}catch(e){}
			return "<image src=\""+publish.conf.imagesDir + fileName+"\">";
        }
	);

    return str;
}

function getSymbolName(symbol, forSummary) {
    if(symbol.is('CONSTRUCTOR')){
        return symbol.alias.replace(/\^\d+$/, '').toString().replace(/\|/g, ' | ');
    }else if (symbol.constructedBy){
        return symbol.constructedBy.toString().replace("[\^][\d]", '');
    }else if (symbol.squareAccessor) {
        return "[]";
    } else if (symbol.uri) {
        return "webworks://" + symbol.alias.replace(/\./g, "/").replace("[\^][\d]", '');
    } else if (symbol.isStatic && !forSummary) {
        return symbol.memberOf + "." + symbol.name.replace(/\^\d+$/, '').replace("[\^][\d]", '');
    } else {
        return symbol.name.replace(/\^\d+$/, '').replace("[\^][\d]", '');
    }
}

function isMethod($)      {return (!$.isNamespace && !$.uri && !$.isConstant && !$.constructedBy);};
function isURIMethod($)   {return (!$.isNamespace && $.uri  && !$.isConstant && !$.constructedBy);};
function isConstructor($) {return ((!$.isNamespace && !$.uri && !$.isConstant && $.constructedBy) || ($.is('CONSTRUCTOR')));};
function isProperty($)    {return (!$.isNamespace && !$.uri && !$.isConstant && !$.constructedBy);};
function isConstant($)    {return (!$.isNamespace && !$.uri && $.isConstant  && !$.constructedBy);};
function isEvent($)       {return (!$.isNamespace && !$.uri && !$.isConstant && !$.constructedBy);};

function isBlank(str) { return (!str || /^\s*$/.test(str)); };

/** Include a sub-template in the current template, specifying a data object */
function subtemplate(template, data) {
	try {
		return new JSDOC.JsPlate(publish.conf.templatesDir+template).process(data);
	}
	catch(e) { print(e.message); quit(); }
}
<|endoftext|>


<commit_before>/* @flow */

import { toState } from '../redux';
import { toURLString } from '../util';

/**
 * Figures out what's the current conference URL which is supposed to indicate what conference is currently active.
 * When not currently in any conference and not trying to join any then 'undefined' is returned.
 *
 * @param {Object|Function} stateful - Either the whole Redux state object or the Redux store's {@code getState} method.
 * @returns {string|undefined}
 * @private
 */
export function getCurrentConferenceUrl(stateful: Function | Object) {
    const state = toState(stateful);
    let currentUrl;

    if (isInviteURLReady(state)) {
        currentUrl = toURLString(getInviteURL(state));
    }

    // Check if the URL doesn't end with a slash
    if (currentUrl && currentUrl.substr(-1) === '/') {
        currentUrl = undefined;
    }

    return currentUrl ? currentUrl : undefined;
}

/**
 * Retrieves a simplified version of the conference/location URL stripped of URL params (i.e. Query/search and hash)
 * which should be used for sending invites.
 * NOTE that the method will throw an error if called too early. That is before the conference is joined or before
 * the process of joining one has started. This limitation does not apply to the case when called with the URL object
 * instance. Use {@link isInviteURLReady} to check if it's safe to call the method already.
 *
 * @param {Function|Object} stateOrGetState - The redux state or redux's {@code getState} function or the URL object
 * to be stripped.
 * @returns {string}
 */
export function getInviteURL(stateOrGetState: Function | Object): string {
    const state = toState(stateOrGetState);
    let locationURL
        = state instanceof URL
            ? state
            : state['features/base/connection'].locationURL;

    // If there's no locationURL on the base/connection feature try the base/config where it's set earlier.
    if (!locationURL) {
        locationURL = state['features/base/config'].locationURL;
    }

    if (!locationURL) {
        throw new Error('Can not get invite URL - the app is not ready');
    }

    const { inviteDomain } = state['features/dynamic-branding'];
    const urlWithoutParams = getURLWithoutParams(locationURL);

    if (inviteDomain) {
        const meetingId
            = state['features/base/config'].brandingRoomAlias || urlWithoutParams.pathname.replace('/', '');

        return `${inviteDomain}/${meetingId}`;
    }

    return urlWithoutParams.href;
}

/**
 * Checks whether or not is safe to call the {@link getInviteURL} method already.
 *
 * @param {Function|Object} stateOrGetState - The redux state or redux's {@code getState} function.
 * @returns {boolean}
 */
export function isInviteURLReady(stateOrGetState: Function | Object): boolean {
    const state = toState(stateOrGetState);

    return Boolean(state['features/base/connection'].locationURL || state['features/base/config'].locationURL);
}

/**
 * Gets a {@link URL} without hash and query/search params from a specific
 * {@code URL}.
 *
 * @param {URL} url - The {@code URL} which may have hash and query/search
 * params.
 * @returns {URL}
 */
export function getURLWithoutParams(url: URL): URL {
    const { hash, search } = url;

    if ((hash && hash.length > 1) || (search && search.length > 1)) {
        url = new URL(url.href); // eslint-disable-line no-param-reassign
        url.hash = '';
        url.search = '';

        // XXX The implementation of URL at least on React Native appends ? and
        // # at the end of the href which is not desired.
        let { href } = url;

        if (href) {
            href.endsWith('#') && (href = href.substring(0, href.length - 1));
            href.endsWith('?') && (href = href.substring(0, href.length - 1));

            // eslint-disable-next-line no-param-reassign
            url.href === href || (url = new URL(href));
        }
    }

    return url;
}

/**
 * Gets a URL string without hash and query/search params from a specific
 * {@code URL}.
 *
 * @param {URL} url - The {@code URL} which may have hash and query/search
 * params.
 * @returns {string}
 */
export function getURLWithoutParamsNormalized(url: URL): string {
    const urlWithoutParams = getURLWithoutParams(url).href;

    if (urlWithoutParams) {
        return urlWithoutParams.toLowerCase();
    }

    return '';
}

/**
 * Converts a specific id to jid if it's not jid yet.
 *
 * @param {string} id - User id or jid.
 * @param {Object} configHosts - The {@code hosts} part of the {@code config}
 * object.
 * @returns {string} A string in the form of a JID (i.e.
 * {@code user@server.com}).
 */
export function toJid(id: string, { authdomain, domain }: Object): string {
    return id.indexOf('@') >= 0 ? id : `${id}@${authdomain || domain}`;
}
<commit_msg>fix(jaas) replace only the first slash in a pathname<commit_after>/* @flow */

import { toState } from '../redux';
import { toURLString } from '../util';

/**
 * Figures out what's the current conference URL which is supposed to indicate what conference is currently active.
 * When not currently in any conference and not trying to join any then 'undefined' is returned.
 *
 * @param {Object|Function} stateful - Either the whole Redux state object or the Redux store's {@code getState} method.
 * @returns {string|undefined}
 * @private
 */
export function getCurrentConferenceUrl(stateful: Function | Object) {
    const state = toState(stateful);
    let currentUrl;

    if (isInviteURLReady(state)) {
        currentUrl = toURLString(getInviteURL(state));
    }

    // Check if the URL doesn't end with a slash
    if (currentUrl && currentUrl.substr(-1) === '/') {
        currentUrl = undefined;
    }

    return currentUrl ? currentUrl : undefined;
}

/**
 * Retrieves a simplified version of the conference/location URL stripped of URL params (i.e. Query/search and hash)
 * which should be used for sending invites.
 * NOTE that the method will throw an error if called too early. That is before the conference is joined or before
 * the process of joining one has started. This limitation does not apply to the case when called with the URL object
 * instance. Use {@link isInviteURLReady} to check if it's safe to call the method already.
 *
 * @param {Function|Object} stateOrGetState - The redux state or redux's {@code getState} function or the URL object
 * to be stripped.
 * @returns {string}
 */
export function getInviteURL(stateOrGetState: Function | Object): string {
    const state = toState(stateOrGetState);
    let locationURL
        = state instanceof URL
            ? state
            : state['features/base/connection'].locationURL;

    // If there's no locationURL on the base/connection feature try the base/config where it's set earlier.
    if (!locationURL) {
        locationURL = state['features/base/config'].locationURL;
    }

    if (!locationURL) {
        throw new Error('Can not get invite URL - the app is not ready');
    }

    const { inviteDomain } = state['features/dynamic-branding'];
    const urlWithoutParams = getURLWithoutParams(locationURL);

    if (inviteDomain) {
        const meetingId
            = state['features/base/config'].brandingRoomAlias || urlWithoutParams.pathname.replace(/\//, '');

        return `${inviteDomain}/${meetingId}`;
    }

    return urlWithoutParams.href;
}

/**
 * Checks whether or not is safe to call the {@link getInviteURL} method already.
 *
 * @param {Function|Object} stateOrGetState - The redux state or redux's {@code getState} function.
 * @returns {boolean}
 */
export function isInviteURLReady(stateOrGetState: Function | Object): boolean {
    const state = toState(stateOrGetState);

    return Boolean(state['features/base/connection'].locationURL || state['features/base/config'].locationURL);
}

/**
 * Gets a {@link URL} without hash and query/search params from a specific
 * {@code URL}.
 *
 * @param {URL} url - The {@code URL} which may have hash and query/search
 * params.
 * @returns {URL}
 */
export function getURLWithoutParams(url: URL): URL {
    const { hash, search } = url;

    if ((hash && hash.length > 1) || (search && search.length > 1)) {
        url = new URL(url.href); // eslint-disable-line no-param-reassign
        url.hash = '';
        url.search = '';

        // XXX The implementation of URL at least on React Native appends ? and
        // # at the end of the href which is not desired.
        let { href } = url;

        if (href) {
            href.endsWith('#') && (href = href.substring(0, href.length - 1));
            href.endsWith('?') && (href = href.substring(0, href.length - 1));

            // eslint-disable-next-line no-param-reassign
            url.href === href || (url = new URL(href));
        }
    }

    return url;
}

/**
 * Gets a URL string without hash and query/search params from a specific
 * {@code URL}.
 *
 * @param {URL} url - The {@code URL} which may have hash and query/search
 * params.
 * @returns {string}
 */
export function getURLWithoutParamsNormalized(url: URL): string {
    const urlWithoutParams = getURLWithoutParams(url).href;

    if (urlWithoutParams) {
        return urlWithoutParams.toLowerCase();
    }

    return '';
}

/**
 * Converts a specific id to jid if it's not jid yet.
 *
 * @param {string} id - User id or jid.
 * @param {Object} configHosts - The {@code hosts} part of the {@code config}
 * object.
 * @returns {string} A string in the form of a JID (i.e.
 * {@code user@server.com}).
 */
export function toJid(id: string, { authdomain, domain }: Object): string {
    return id.indexOf('@') >= 0 ? id : `${id}@${authdomain || domain}`;
}
<|endoftext|>


<commit_before>var gulp = require("gulp");
var git = require("gulp-git");
var path = require("path");
var fs = require("fs");

function _runTest(runTestFunc, browserArr, done) {
    console.log("run test...");

    runTestFunc(browserArr).then(function (failList) {
        console.log("done");
        done()
    }, function (e) {
        console.log("fail");
        console.error(e);
        done();
    })
}

function _runTestInLocal(reportFilePath, runTestFunc, generateReportFunc, browserArr, done) {
    console.log("run test...");

    runTestFunc(browserArr).then(function (failList) {
        console.log("generate report...");

        generateReportFunc(reportFilePath, failList).then(function () {
            console.log("done");
            done()
        }, function (e) {
            console.error(e);
            done();
        })
    }, function (e) {
        console.log("fail");
        console.error(e);
        done();
    })
}

function _runBuild(cb) {
    var exec = require("child_process").exec;

    console.log("build...");

    exec("npm run buildAll", { maxBuffer: 8192 * 4000 }, function (err, stdout, stderr) {
        if (err) {
            throw err;
        }

        cb()
    });
}

function _deepCopyJson(json) {
    return JSON.parse(JSON.stringify(json));
}

function _writeGenerateBasedCommitIdToConfig(commitId, config, type, configFilePath) {
    console.log("_write generate based commitId...");
    var copiedConfig = _deepCopyJson(config);
    copiedConfig[type].last_generate_based_commit_id = commitId;
    fs.writeFileSync(configFilePath, JSON.stringify(copiedConfig));
}

function _restoreToCurrentCommid(currentCommitId, done) {
    git.reset(currentCommitId, { args: '--hard' }, function (err) {
        if (!!err) {
            console.error(err);
            done();
            return;
        }

        console.log("build...");

        _runBuild(function () {
            done()
        });
    });
}

module.exports = {
    testInCI: function (generateDataInfo, type, generateCorrectDataFunc, runTestFunc, done) {
        var configFilePath = path.join(process.cwd(), "test/e2e/config/e2eConfig.json");

        git.revParse({ args: "HEAD" }, function (err, commitId) {
            var currentCommitId = commitId;

            var config = JSON.parse(fs.readFileSync(configFilePath));
            var basedCommitId = config[type].base_commit_id;

            if (!!err) {
                console.error(err);
                done();
                return;
            }

            // if (basedCommitId === config[type].last_generate_based_commit_id) {
            //     _runBuild(function () {
            //         _runTest(runTestFunc, [], done);
            //     });
            //     return
            // }

            console.log("reset hard to basedCommitId:", basedCommitId, "...");

            git.reset(basedCommitId, { args: '--hard' }, function (err) {
                if (!!err) {
                    console.error(err);
                    done();
                    return;
                }

                _runBuild(function () {
                    console.log(generateDataInfo);

                    generateCorrectDataFunc().then(function (browser) {
                        console.log("reset hard to currentCommitId:", currentCommitId, "...");

                        git.reset(currentCommitId, { args: '--hard' }, function (err) {
                            if (!!err) {
                                console.error(err);

                                return;
                            }

                            // _writeGenerateBasedCommitIdToConfig(basedCommitId, config, type, configFilePath);

                            _runBuild(function () {
                                _runTest(runTestFunc, [browser], done);
                            });
                        });
                    }, function (e) {
                        console.error(e);

                        console.log("restore to origin commitId...");

                        _restoreToCurrentCommid(currentCommitId, done);
                    })
                });
            });
        });

    },
    testInLocal: function (generateDataInfo, reportFilePath, type, generateCorrectDataFunc, generateReportFunc, runTestFunc, reportFilePath, done) {
        var configFilePath = path.join(process.cwd(), "test/e2e/config/e2eConfig.json");

        git.revParse({ args: "HEAD" }, function (err, commitId) {
            var currentCommitId = commitId;

            var config = JSON.parse(fs.readFileSync(configFilePath));
            var basedCommitId = config[type].base_commit_id;

            if (!!err) {
                console.error(err);
                done();
                return;
            }

            if (basedCommitId === config[type].last_generate_based_commit_id) {
                console.log("already generate data based on the same commit id, not generate again...");

                _runBuild(function () {
                    _runTestInLocal(reportFilePath, runTestFunc, generateReportFunc, [], done);
                });
                return
            }

            console.log("reset hard to basedCommitId:", basedCommitId, "...");

            git.reset(basedCommitId, { args: '--hard' }, function (err) {
                if (!!err) {
                    console.error(err);
                    done();
                    return;
                }

                _runBuild(function () {
                    console.log(generateDataInfo);

                    generateCorrectDataFunc().then(function (browser) {
                        console.log("reset hard to currentCommitId:", currentCommitId, "...");

                        git.reset(currentCommitId, { args: '--hard' }, function (err) {
                            if (!!err) {
                                console.error(err);

                                return;
                            }

                            _writeGenerateBasedCommitIdToConfig(basedCommitId, config, type, configFilePath);

                            _runBuild(function () {
                                _runTestInLocal(reportFilePath, runTestFunc, generateReportFunc, [browser], done);
                            });
                        });
                    }, function (e) {
                        console.error(e);

                        console.log("restore to origin commitId...");

                        _restoreToCurrentCommid(currentCommitId, done);
                    })
                });
            });
        });

    }
}
<commit_msg>test(e2e-test): fix test.js->"testInLocal"<commit_after>var gulp = require("gulp");
var git = require("gulp-git");
var path = require("path");
var fs = require("fs");

function _runTest(runTestFunc, browserArr, done) {
    console.log("run test...");

    runTestFunc(browserArr).then(function (failList) {
        console.log("done");
        done()
    }, function (e) {
        console.log("fail");
        console.error(e);
        done();
    })
}

function _runTestInLocal(reportFilePath, runTestFunc, generateReportFunc, browserArr, done) {
    console.log("run test...");

    runTestFunc(browserArr).then(function (failList) {
        console.log("generate report...");

        generateReportFunc(reportFilePath, failList).then(function () {
            console.log("done");
            done()
        }, function (e) {
            console.error(e);
            done();
        })
    }, function (e) {
        console.log("fail");
        console.error(e);
        done();
    })
}

function _runBuild(cb) {
    var exec = require("child_process").exec;

    console.log("build...");

    exec("npm run buildAll", { maxBuffer: 8192 * 4000 }, function (err, stdout, stderr) {
        if (err) {
            throw err;
        }

        cb()
    });
}

function _deepCopyJson(json) {
    return JSON.parse(JSON.stringify(json));
}

function _writeGenerateBasedCommitIdToConfig(commitId, config, type, configFilePath) {
    console.log("_write generate based commitId...");
    var copiedConfig = _deepCopyJson(config);
    copiedConfig[type].last_generate_based_commit_id = commitId;
    fs.writeFileSync(configFilePath, JSON.stringify(copiedConfig));
}

function _restoreToCurrentCommid(currentCommitId, done) {
    git.reset(currentCommitId, { args: '--hard' }, function (err) {
        if (!!err) {
            console.error(err);
            done();
            return;
        }

        console.log("build...");

        _runBuild(function () {
            done()
        });
    });
}

module.exports = {
    testInCI: function (generateDataInfo, type, generateCorrectDataFunc, runTestFunc, done) {
        var configFilePath = path.join(process.cwd(), "test/e2e/config/e2eConfig.json");

        git.revParse({ args: "HEAD" }, function (err, commitId) {
            var currentCommitId = commitId;

            var config = JSON.parse(fs.readFileSync(configFilePath));
            var basedCommitId = config[type].base_commit_id;

            if (!!err) {
                console.error(err);
                done();
                return;
            }

            // if (basedCommitId === config[type].last_generate_based_commit_id) {
            //     _runBuild(function () {
            //         _runTest(runTestFunc, [], done);
            //     });
            //     return
            // }

            console.log("reset hard to basedCommitId:", basedCommitId, "...");

            git.reset(basedCommitId, { args: '--hard' }, function (err) {
                if (!!err) {
                    console.error(err);
                    done();
                    return;
                }

                _runBuild(function () {
                    console.log(generateDataInfo);

                    generateCorrectDataFunc().then(function (browser) {
                        console.log("reset hard to currentCommitId:", currentCommitId, "...");

                        git.reset(currentCommitId, { args: '--hard' }, function (err) {
                            if (!!err) {
                                console.error(err);

                                return;
                            }

                            // _writeGenerateBasedCommitIdToConfig(basedCommitId, config, type, configFilePath);

                            _runBuild(function () {
                                _runTest(runTestFunc, [browser], done);
                            });
                        });
                    }, function (e) {
                        console.error(e);

                        console.log("restore to origin commitId...");

                        _restoreToCurrentCommid(currentCommitId, done);
                    })
                });
            });
        });
    },
    testInLocal: function (generateDataInfo, reportFilePath, type, generateCorrectDataFunc, generateReportFunc, runTestFunc, done) {
        var configFilePath = path.join(process.cwd(), "test/e2e/config/e2eConfig.json");

        git.revParse({ args: "HEAD" }, function (err, commitId) {
            var currentCommitId = commitId;

            var config = JSON.parse(fs.readFileSync(configFilePath));
            var basedCommitId = config[type].base_commit_id;

            if (!!err) {
                console.error(err);
                done();
                return;
            }

            if (basedCommitId === config[type].last_generate_based_commit_id) {
                console.log("already generate data based on the same commit id, not generate again...");

                _runBuild(function () {
                    _runTestInLocal(reportFilePath, runTestFunc, generateReportFunc, [], done);
                });
                return
            }

            console.log("reset hard to basedCommitId:", basedCommitId, "...");

            git.reset(basedCommitId, { args: '--hard' }, function (err) {
                if (!!err) {
                    console.error(err);
                    done();
                    return;
                }

                _runBuild(function () {
                    console.log(generateDataInfo);

                    generateCorrectDataFunc().then(function (browser) {
                        console.log("reset hard to currentCommitId:", currentCommitId, "...");

                        git.reset(currentCommitId, { args: '--hard' }, function (err) {
                            if (!!err) {
                                console.error(err);

                                return;
                            }

                            _writeGenerateBasedCommitIdToConfig(basedCommitId, config, type, configFilePath);

                            _runBuild(function () {
                                _runTestInLocal(reportFilePath, runTestFunc, generateReportFunc, [browser], done);
                            });
                        });
                    }, function (e) {
                        console.error(e);

                        console.log("restore to origin commitId...");

                        _restoreToCurrentCommid(currentCommitId, done);
                    })
                });
            });
        });

    }
}
<|endoftext|>