<commit_before>/*jslint indent: 2, nomen: true, maxlen: 100, white: true, plusplus: true, eqeq: true */
/*global require, exports */

////////////////////////////////////////////////////////////////////////////////
/// @brief Mini Stub and Mock Framework
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Lucas Dohmen
/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany

var stub,
  allow,
  expect,
  FunctionStub,
  FunctionMock,
  _ = require("underscore");

// Sorry for Yak Shaving. But I can't take it anymore.

// x = stub();

stub = function () {
  return function() {};
};

// allow(x)
//   .toReceive("functionName")
//   .andReturn({ x: 1 })

FunctionStub = function(obj) {
  this.obj = obj;
};

_.extend(FunctionStub.prototype, {
  toReceive: function (functionName) {
    this.functionName = functionName;
    this.buildFunctionStub();
    return this;
  },

  andReturn: function (returnValue) {
    this.returnValue = returnValue;
    this.buildFunctionStub();
    return this;
  },

  buildFunctionStub: function () {
    var returnValue = this.returnValue;

    this.obj[this.functionName] = function () {
      return returnValue;
    };
  }
});

allow = function(obj) {
  return (new FunctionStub(obj));
};

// expect(x)
//   .toReceive("functionName")
//   .withArguments(5)
//   .andReturn({ x: 1 })
//
// ...
//
// x.assertIsSatisfied();

FunctionMock = function(obj) {
  this.obj = obj;
  this.obj.satisfied = false;

  this.obj.assertIsSatisfied = function () {
    assertTrue(this.satisfied, "Mock expectation was not satisfied");
  };
};

_.extend(FunctionMock.prototype, {
  toReceive: function (functionName) {
    this.functionName = functionName;
    this.buildFunctionMock();
    return this;
  },

  andReturn: function (returnValue) {
    this.returnValue = returnValue;
    this.buildFunctionMock();
    return this;
  },

  withArguments: function () {
    this.expectedArguments = arguments;
    this.buildFunctionMock();
    return this;
  },

  buildFunctionMock: function () {
    var returnValue = this.returnValue,
      expectedArguments = this.expectedArguments,
      obj = this.obj;

    this.obj[this.functionName] = function () {
      if ((expectedArguments === undefined) || (_.isEqual(arguments, expectedArguments))) {
        obj.satisfied = true;
      }

      return returnValue;
    };
  }
});

expect = function(obj) {
  return (new FunctionMock(obj));
};

exports.stub = stub;
exports.allow = allow;
exports.expect = expect;
<commit_msg>jslintified<commit_after>/*jslint indent: 2, nomen: true, maxlen: 100, white: true, plusplus: true, eqeq: true */
/*global require, exports, assertTrue */

////////////////////////////////////////////////////////////////////////////////
/// @brief Mini Stub and Mock Framework
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Lucas Dohmen
/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany

var stub,
  allow,
  expect,
  FunctionStub,
  FunctionMock,
  _ = require("underscore");

// Sorry for Yak Shaving. But I can't take it anymore.

// x = stub();

stub = function () {
  'use strict';
  return function() {};
};

// allow(x)
//   .toReceive("functionName")
//   .andReturn({ x: 1 })

FunctionStub = function(obj) {
  'use strict';
  this.obj = obj;
};

_.extend(FunctionStub.prototype, {
  toReceive: function (functionName) {
    'use strict';
    this.functionName = functionName;
    this.buildFunctionStub();
    return this;
  },

  andReturn: function (returnValue) {
    'use strict';
    this.returnValue = returnValue;
    this.buildFunctionStub();
    return this;
  },

  buildFunctionStub: function () {
    'use strict';
    var returnValue = this.returnValue;

    this.obj[this.functionName] = function () {
      return returnValue;
    };
  }
});

allow = function(obj) {
  'use strict';
  return (new FunctionStub(obj));
};

// expect(x)
//   .toReceive("functionName")
//   .withArguments(5)
//   .andReturn({ x: 1 })
//
// ...
//
// x.assertIsSatisfied();

FunctionMock = function(obj) {
  'use strict';
  this.obj = obj;
  this.obj.satisfied = false;

  this.obj.assertIsSatisfied = function () {
    assertTrue(this.satisfied, "Mock expectation was not satisfied");
  };
};

_.extend(FunctionMock.prototype, {
  toReceive: function (functionName) {
    'use strict';
    this.functionName = functionName;
    this.buildFunctionMock();
    return this;
  },

  andReturn: function (returnValue) {
    'use strict';
    this.returnValue = returnValue;
    this.buildFunctionMock();
    return this;
  },

  withArguments: function () {
    'use strict';
    this.expectedArguments = arguments;
    this.buildFunctionMock();
    return this;
  },

  buildFunctionMock: function () {
    'use strict';
    var returnValue = this.returnValue,
      expectedArguments = this.expectedArguments,
      obj = this.obj;

    this.obj[this.functionName] = function () {
      if ((expectedArguments === undefined) || (_.isEqual(arguments, expectedArguments))) {
        obj.satisfied = true;
      }

      return returnValue;
    };
  }
});

expect = function(obj) {
  'use strict';
  return (new FunctionMock(obj));
};

exports.stub = stub;
exports.allow = allow;
exports.expect = expect;
<|endoftext|>


<commit_before>/*jshint globalstrict:false, strict:false */
/*global describe, expect, it, beforeEach, createSpyObj */

var FoxxRepository = require("org/arangodb/foxx/repository").Repository,
  Model = require("org/arangodb/foxx/model").Model;

describe('Model Events', function () {
  'use strict';

  var collection, instance, repository;

  beforeEach(function () {
    collection = createSpyObj('collection', [
      'update',
      'save',
      'remove'
    ]);
    instance = new Model({ random: '', beforeCalled: false, afterCalled: false });
    repository = new FoxxRepository(collection, {model: Model});
  });

  it('should be possible to subscribe and emit events', function () {
    expect(instance.on).toBeDefined();
    expect(instance.emit).toBeDefined();
  });

  it('should emit beforeCreate and afterCreate events when creating the model', function () {
    addHooks(instance, 'Create');
    expect(repository.save(instance)).toEqual(instance);
    expect(instance.get('beforeCalled')).toBe(true);
    expect(instance.get('afterCalled')).toBe(true);
  });

  it('should emit beforeSave and afterSave events when creating the model', function () {
    addHooks(instance, 'Save');
    expect(repository.save(instance)).toEqual(instance);
    expect(instance.get('beforeCalled')).toBe(true);
    expect(instance.get('afterCalled')).toBe(true);
  });

  it('should emit beforeUpdate and afterUpdate events when updating the model', function () {
    var newData = { newAttribute: 'test' };
    addHooks(instance, 'Update', newData);
    expect(repository.update(instance, newData)).toEqual(instance);
    expect(instance.get('beforeCalled')).toBe(true);
    expect(instance.get('afterCalled')).toBe(true);
  });

  it('should emit beforeSave and afterSave events when updating the model', function () {
    var newData = { newAttribute: 'test' };
    addHooks(instance, 'Save', newData);
    expect(repository.update(instance, newData)).toEqual(instance);
    expect(instance.get('beforeCalled')).toBe(true);
    expect(instance.get('afterCalled')).toBe(true);
  });

  it('should emit beforeRemove and afterRemove events when removing the model', function () {
    addHooks(instance, 'Remove');
    repository.remove(instance);
    expect(instance.get('beforeCalled')).toBe(true);
    expect(instance.get('afterCalled')).toBe(true);
  });

});

function addHooks(model, ev, dataToReceive) {
  'use strict';

  var random = String(Math.floor(Math.random() * 1000));

  model.on('before' + ev, function (data) {
    expect(this).toEqual(model);
    expect(data).toEqual(dataToReceive);
    this.set('random', random);
    this.set('beforeCalled', true);
  });
  model.on('after' + ev, function (data) {
    expect(this).toEqual(model);
    expect(data).toEqual(dataToReceive);
    this.set('afterCalled', true);
    expect(this.get('beforeCalled')).toBe(true);
    expect(this.get('random')).toEqual(random);
  });
}<commit_msg>Fixed model-events test.<commit_after>/*jshint globalstrict:false, strict:false */
/*global describe, expect, it, beforeEach, createSpyObj */

var FoxxRepository = require("org/arangodb/foxx/repository").Repository,
  Model = require("org/arangodb/foxx/model").Model;

describe('Model Events', function () {
  'use strict';

  var collection, instance, repository;

  beforeEach(function () {
    collection = createSpyObj('collection', [
      'update',
      'save',
      'type',
      'remove'
    ]);
    collection.type.and.returnValue(2);
    instance = new Model({ random: '', beforeCalled: false, afterCalled: false });
    repository = new FoxxRepository(collection, {model: Model});
  });

  it('should be possible to subscribe and emit events', function () {
    expect(instance.on).toBeDefined();
    expect(instance.emit).toBeDefined();
  });

  it('should emit beforeCreate and afterCreate events when creating the model', function () {
    addHooks(instance, 'Create');
    expect(repository.save(instance)).toEqual(instance);
    expect(instance.get('beforeCalled')).toBe(true);
    expect(instance.get('afterCalled')).toBe(true);
  });

  it('should emit beforeSave and afterSave events when creating the model', function () {
    addHooks(instance, 'Save');
    expect(repository.save(instance)).toEqual(instance);
    expect(instance.get('beforeCalled')).toBe(true);
    expect(instance.get('afterCalled')).toBe(true);
  });

  it('should emit beforeUpdate and afterUpdate events when updating the model', function () {
    var newData = { newAttribute: 'test' };
    addHooks(instance, 'Update', newData);
    expect(repository.update(instance, newData)).toEqual(instance);
    expect(instance.get('beforeCalled')).toBe(true);
    expect(instance.get('afterCalled')).toBe(true);
  });

  it('should emit beforeSave and afterSave events when updating the model', function () {
    var newData = { newAttribute: 'test' };
    addHooks(instance, 'Save', newData);
    expect(repository.update(instance, newData)).toEqual(instance);
    expect(instance.get('beforeCalled')).toBe(true);
    expect(instance.get('afterCalled')).toBe(true);
  });

  it('should emit beforeRemove and afterRemove events when removing the model', function () {
    addHooks(instance, 'Remove');
    repository.remove(instance);
    expect(instance.get('beforeCalled')).toBe(true);
    expect(instance.get('afterCalled')).toBe(true);
  });

});

function addHooks(model, ev, dataToReceive) {
  'use strict';

  var random = String(Math.floor(Math.random() * 1000));

  model.on('before' + ev, function (data) {
    expect(this).toEqual(model);
    expect(data).toEqual(dataToReceive);
    this.set('random', random);
    this.set('beforeCalled', true);
  });
  model.on('after' + ev, function (data) {
    expect(this).toEqual(model);
    expect(data).toEqual(dataToReceive);
    this.set('afterCalled', true);
    expect(this.get('beforeCalled')).toBe(true);
    expect(this.get('random')).toEqual(random);
  });
}<|endoftext|>


<commit_before>

    module("bootstrap-buttons")

      test("should be defined BootStrap Namespace", function () {
        ok(BootStrap.Button, 'button method is defined')
      });

      test("should return set state to loading", function () {
        var btn = new Element('button',{'class':'btn','data-loading-text':"fat"}).update('mdo')
        equals(btn.innerHTML, 'mdo', 'btn text equals mdo')
        var bbtn = new BootStrap.Button(btn,'loading')
        equals(btn.innerHTML, 'fat', 'btn text equals fat')
        stop()
        setTimeout(function () {
          ok(btn.writeAttribute('disabled'), 'btn is disabled')
          ok(btn.hasClassName('disabled'), 'btn has disabled class')
          start()
        }, 0)
      })

      test("should return reset state", function () {
        var btn = new Element('button',{'class':'btn','data-loading-text':'fat'}).update('mdo');
        equals(btn.innerHTML, 'mdo', 'btn text equals mdo')
        var bbtn = new BootStrap.Button(btn,'loading')
        equals(btn.innerHTML, 'fat', 'btn text equals fat')
        stop()
        setTimeout(function () {
          ok(btn.writeAttribute('disabled'), 'btn is disabled')
          ok(btn.hasClassName('disabled'), 'btn has disabled class')
          start()
          stop()
        }, 0)
        bbtn.setState('reset')
        equals(btn.innerHTML, 'mdo', 'btn text equals mdo')
        setTimeout(function () {
          ok(!btn.readAttribute('disabled'), 'btn is not disabled')
          ok(!btn.hasClassName('disabled'), 'btn does not have disabled class')
          start()
        }, 0)
      })

      test("should toggle active", function () {
        var btn = new Element('button',{'class':"btn"}).update('mdo')
        ok(!btn.hasClassName('active'), 'btn does not have active class')
        var bbtn = new BootStrap.Button(btn,'toggle')
        ok(btn.hasClassName('active'), 'btn has class active')
      })

      test("should toggle active when btn children are clicked", function () {
        var btn = new Element('button',{'class':"btn",'data-toggle':"button"}).update('mdo')
          , inner = new Element('i')
        btn.insert(inner)
        $('qunit-fixture').insert(btn)
        $$("[data-toggle^=button]").invoke("observe","click",function(e){
          var $btn = e.findElement()
          if(!$btn.hasClassName('btn')) $btn = $btn.up('.btn')
          new BootStrap.Button($btn,'toggle')
        });
        ok(!btn.hasClassName('active'), 'btn does not have active class')
        inner.simulate('click')
        ok(btn.hasClassName('active'), 'btn has class active')
      })

      test("should toggle active when btn children are clicked within btn-group", function () {
        var btngroup = new Element('div',{'class':"btn-group",'data-toggle':"buttons-checkbox"})
          , btn = new Element('button',{'class':"btn"}).update('fat')
          , inner = new Element('i')
        btngroup.insert(btn.insert(inner))
        $('qunit-fixture').insert(btngroup)
        $$("[data-toggle^=button]").invoke("observe","click",function(e){
          var $btn = e.findElement()
          if(!$btn.hasClassName('btn')) $btn = $btn.up('.btn')
          new BootStrap.Button($btn,'toggle')
        });
        ok(!btn.hasClassName('active'), 'btn does not have active class')
        inner.simulate('click')
        ok(btn.hasClassName('active'), 'btn has class active')
      })

      test("should check for closest matching toggle", function () {
        var group = new Element('div',{'data-toggle':'buttons-radio'})
          , btn1  = new Element("button",{'class':'btn active'})
          , btn2  = new Element("button",{'class':'btn'})
          , wrap  = new Element("div")

        wrap.insert(btn1).insert(btn2)

        $('qunit-fixture').insert(group.insert(wrap))
        $$("[data-toggle^=button]").invoke("observe","click",function(e){
          var $btn = e.findElement()
          if(!$btn.hasClassName('btn')) $btn = $btn.up('.btn')
          new BootStrap.Button($btn,'toggle')
        });

        ok(btn1.hasClassName('active'), 'btn1 has active class')
        ok(!btn2.hasClassName('active'), 'btn2 does not have active class')
        btn2.simulate('click')
        ok(!btn1.hasClassName('active'), 'btn1 does not have active class')
        ok(btn2.hasClassName('active'), 'btn2 has active class')
      })

<commit_msg>fix spacing<commit_after>module("bootstrap-buttons")

test("should be defined BootStrap Namespace", function () {
	ok(BootStrap.Button, 'button method is defined')
});

test("should return set state to loading", function () {
	var btn = new Element('button',{'class':'btn','data-loading-text':"fat"}).update('mdo')
	equals(btn.innerHTML, 'mdo', 'btn text equals mdo')
	var bbtn = new BootStrap.Button(btn,'loading')
	equals(btn.innerHTML, 'fat', 'btn text equals fat')
	stop()
	setTimeout(function () {
		ok(btn.writeAttribute('disabled'), 'btn is disabled')
		ok(btn.hasClassName('disabled'), 'btn has disabled class')
		start()
	}, 0)
})

test("should return reset state", function () {
	var btn = new Element('button',{'class':'btn','data-loading-text':'fat'}).update('mdo');
	equals(btn.innerHTML, 'mdo', 'btn text equals mdo')
	var bbtn = new BootStrap.Button(btn,'loading')
	equals(btn.innerHTML, 'fat', 'btn text equals fat')
	stop()
	setTimeout(function () {
		ok(btn.writeAttribute('disabled'), 'btn is disabled')
		ok(btn.hasClassName('disabled'), 'btn has disabled class')
		start()
		stop()
	}, 0)
	bbtn.setState('reset')
	equals(btn.innerHTML, 'mdo', 'btn text equals mdo')
	setTimeout(function () {
		ok(!btn.readAttribute('disabled'), 'btn is not disabled')
		ok(!btn.hasClassName('disabled'), 'btn does not have disabled class')
		start()
	}, 0)
})

test("should toggle active", function () {
	var btn = new Element('button',{'class':"btn"}).update('mdo')
	ok(!btn.hasClassName('active'), 'btn does not have active class')
	var bbtn = new BootStrap.Button(btn,'toggle')
	ok(btn.hasClassName('active'), 'btn has class active')
})

test("should toggle active when btn children are clicked", function () {
	var btn = new Element('button',{'class':"btn",'data-toggle':"button"}).update('mdo')
	, inner = new Element('i')
	btn.insert(inner)
	$('qunit-fixture').insert(btn)
	$$("[data-toggle^=button]").invoke("observe","click",function(e){
		var $btn = e.findElement()
		if(!$btn.hasClassName('btn')) $btn = $btn.up('.btn')
		new BootStrap.Button($btn,'toggle')
	});
	ok(!btn.hasClassName('active'), 'btn does not have active class')
	inner.simulate('click')
	ok(btn.hasClassName('active'), 'btn has class active')
})

test("should toggle active when btn children are clicked within btn-group", function () {
	var btngroup = new Element('div',{'class':"btn-group",'data-toggle':"buttons-checkbox"})
	, btn = new Element('button',{'class':"btn"}).update('fat')
	, inner = new Element('i')
	btngroup.insert(btn.insert(inner))
	$('qunit-fixture').insert(btngroup)
	$$("[data-toggle^=button]").invoke("observe","click",function(e){
		var $btn = e.findElement()
		if(!$btn.hasClassName('btn')) $btn = $btn.up('.btn')
		new BootStrap.Button($btn,'toggle')
	});
	ok(!btn.hasClassName('active'), 'btn does not have active class')
	inner.simulate('click')
	ok(btn.hasClassName('active'), 'btn has class active')
})

test("should check for closest matching toggle", function () {
	var group = new Element('div',{'data-toggle':'buttons-radio'})
	, btn1  = new Element("button",{'class':'btn active'})
	, btn2  = new Element("button",{'class':'btn'})
	, wrap  = new Element("div")

	wrap.insert(btn1).insert(btn2)

	$('qunit-fixture').insert(group.insert(wrap))
	$$("[data-toggle^=button]").invoke("observe","click",function(e){
		var $btn = e.findElement()
		if(!$btn.hasClassName('btn')) $btn = $btn.up('.btn')
			new BootStrap.Button($btn,'toggle')
	});

	ok(btn1.hasClassName('active'), 'btn1 has active class')
	ok(!btn2.hasClassName('active'), 'btn2 does not have active class')
	btn2.simulate('click')
	ok(!btn1.hasClassName('active'), 'btn1 does not have active class')
	ok(btn2.hasClassName('active'), 'btn2 has active class')
})

<|endoftext|>


<commit_before>var glob = require('glob');
var path = require('path');
var _ = require('lodash');

module.exports = function(app, config) {

  var seedNodules = [], routes = {};

  var rootConfig = {
    // set this to true if you have not defined a customDebugger but want to temporality see debugging output
    debugToConsole: false,

    // directories to look for nodules in, minus exclude pattern
    dirs: [
      { path: process.cwd(), exclude: null }
    ],

    noduleDefaults: {
      // the array of middleware functions which will be called in order for each nodule
      middlewares: [],

      // NOTE: the three route config params below must be specified in the nodule init method, they cannot be mutated at request-time
      // REQUIRED, must be unique within express app, can be String or RegExp or an array of either to handle multiple routes
      route: null,

      // get/post/put/delete
      routeVerb: 'get',

      // use to load routes before or after main group (use negative #s for to load route first - like z-index)
      routeIndex: 0,
    },
  };

  var defaultConfig = _.merge(_.cloneDeep(rootConfig), config);

  var debug = config.customDebug || function(msg) { if (defaultConfig.debugToConsole) console.log(msg); };

  // find all nodules and init all routes first so they can be sorted based on routeIndex
  defaultConfig.dirs.forEach(function(dir) { loadNodules(dir.path, dir.exclude); });

  registerRoutes();

  // finds nodules in supplied dir, minus exclude patterns, and invokes initNodule method on them
  function loadNodules(dir, exclude) {
    var root = dir || process.cwd(); // TOOD - should this be process.cwd() + '/app' ?
    glob.sync('./**/*.js', { cwd: root })
      .filter(doesntMatch.apply(this, exclude))
      .forEach(function(file) { initNodule(path.join(root, file)); });
  }

  // creates seedNodules for each found nodule (seedNodules are cloned at the beginning of each request and added to the req object)
  function initNodule(filepath) {
    var config = require(filepath)(app);
    var seedNodule = _.merge(_.cloneDeep(defaultConfig.noduleDefaults), config); // merge config properties onto default config
    seedNodule.path = path.dirname(filepath);
    seedNodule.name = path.basename(filepath, '.js');

    // nodules can have multiple routes
    var routeArray = (typeof seedNodule.route === 'string') || (seedNodule.route instanceof RegExp) ? [seedNodule.route] : seedNodule.route;
    _.each(routeArray, function(routePath) {
      seedNodules[routePath] = seedNodule; // routes must me unique

      if (!routes[seedNodule.routeIndex])
        routes[seedNodule.routeIndex] = [];
      routes[seedNodule.routeIndex].push({path:routePath, verb:seedNodule.routeVerb, middlewares:seedNodule.middlewares});
    });
  }

  // register express routes (call app.get()/app.post() etc.) in order based on nodule.routeIndex (default = 0, can be negative)
  function registerRoutes() {
    var sortedRouteKeys = _.sortBy(_.keys(routes), function(num){ return 1*num; });
    _.each(sortedRouteKeys, function(key) {
      _.each(routes[key], function(route) {

        debug('registering route: ' + route.verb + ' ' + route.path);
        if (defaultConfig.debugToConsole) console.log('registering route: ' + route.verb + ' ' + route.path);

        app[route.verb].apply(app, [route.path, initRequest].concat(route.middlewares));
      });
    });
  }

  // first step in middleware chain - clone applicable seedNodule and attach cloned instance to each incoming request
  function initRequest(req, res, next) {
    req.module = _.cloneDeep(seedNodules[req.route.path]);
    next();
  }
};

function doesntMatch() {
  var matchers = Array.prototype.slice.call(arguments, 0);
  return function(str) {
    var matches = !matchers.some(function(matcher) {
      return str.indexOf(matcher) !== -1;
    });
    return matches;
  };
}<commit_msg>Add function to return custom middlewares array based on nodule properties<commit_after>var glob = require('glob');
var path = require('path');
var _ = require('lodash');

module.exports = function(app, config) {

  var seedNodules = [], routes = {};

  var rootConfig = {
    // set this to true if you have not defined a customDebugger but want to temporality see debugging output
    debugToConsole: false,

    // directories to look for nodules in, minus exclude pattern - looks in nodules directory by default
    dirs: [
      { path: path.join(process.cwd(), 'nodules'), exclude: null }
    ],

    noduleDefaults: {
      // array of (or function which returns array of) middleware functions which will be called in order for each nodule on each express request
      middlewares: [],
      // - use a function if you want to specify different groups of middleware based on certain nodule properties when app inits
      // - but be careful because most nodule properties can be mutated at request time - whereas middleware chains are set up at app init time
      // function example (use 'this' to reference current nodule):
      // middlewares: function() {
      //  if (this.routeVerb === 'post') return formMiddleWareArray;  // predefined middleware array just for post requests
      //  else return middleWareArray;                                // standard middleware array used for everything else
      // },

      // NOTE: the three route config params below must be specified in the nodule init method, they cannot be mutated at request-time
      // REQUIRED, must be unique within express app, can be String or RegExp or an array of either to handle multiple routes
      route: null,

      // get/post/put/delete
      routeVerb: 'get',

      // use to load routes before or after main group (use negative #s for to load route first - like z-index)
      routeIndex: 0,
    },
  };

  var defaultConfig = _.merge(_.cloneDeep(rootConfig), config);

  var debug = config.customDebug || function(msg) { if (defaultConfig.debugToConsole) console.log(msg); };

  // find all nodules and init all routes first so they can be sorted based on routeIndex
  defaultConfig.dirs.forEach(function(dir) { loadNodules(dir.path, dir.exclude); });

  registerRoutes();

  // finds nodules in supplied dir, minus exclude patterns, and invokes initNodule method on them
  function loadNodules(dir, exclude) {
    var root = dir || process.cwd(); // TOOD - should this be process.cwd() + '/app' ?
    glob.sync('./**/*.js', { cwd: root })
      .filter(doesntMatch.apply(this, exclude))
      .forEach(function(file) { initNodule(path.join(root, file)); });
  }

  // creates seedNodules for each found nodule (seedNodules are cloned at the beginning of each request and added to the req object)
  function initNodule(filepath) {
    var config = require(filepath)(app);
    var seedNodule = _.merge(_.cloneDeep(defaultConfig.noduleDefaults), config); // merge config properties onto default config
    seedNodule.path = path.dirname(filepath);
    seedNodule.name = path.basename(filepath, '.js');

    // nodules can have multiple routes
    var routeArray = (typeof seedNodule.route === 'string') || (seedNodule.route instanceof RegExp) ? [seedNodule.route] : seedNodule.route;
    _.each(routeArray, function(routePath) {
      seedNodules[routePath] = seedNodule; // routes must me unique

      var middlewares = typeof seedNodule.middlewares === 'function' ? seedNodule.middlewares() : seedNodule.middlewares;
      if (!routes[seedNodule.routeIndex]) routes[seedNodule.routeIndex] = [];
      routes[seedNodule.routeIndex].push({path:routePath, verb:seedNodule.routeVerb, middlewares:middlewares});
    });
  }

  // register express routes (call app.get()/app.post() etc.) in order based on nodule.routeIndex (default = 0, can be negative)
  function registerRoutes() {
    var sortedRouteKeys = _.sortBy(_.keys(routes), function(num){ return 1*num; });
    _.each(sortedRouteKeys, function(key) {
      _.each(routes[key], function(route) {

        debug('registering route: ' + route.verb + ' ' + route.path);
        if (defaultConfig.debugToConsole) console.log('registering route: ' + route.verb + ' ' + route.path);

        app[route.verb].apply(app, [route.path, initRequest].concat(route.middlewares));
      });
    });
  }

  // first step in middleware chain - clone applicable seedNodule and attach cloned instance to each incoming request
  function initRequest(req, res, next) {
    req.nodule = _.cloneDeep(seedNodules[req.route.path]);
    next();
  }
};

function doesntMatch() {
  var matchers = Array.prototype.slice.call(arguments, 0);
  return function(str) {
    var matches = !matchers.some(function(matcher) {
      return str.indexOf(matcher) !== -1;
    });
    return matches;
  };
}<|endoftext|>


<commit_before>// create a variable to store the products 'database' in
var products;

// use fetch to retrieve it, and report any errors that occur in the fetch operation
// once the products have been successfully loaded and formatted as a JSON object
// using response.json(), run the initialize() function
fetch('products.json').then(function(response) {
  if(response.ok) {
    response.json().then(function(json) {
      products = json;
      initialize();
    });
  } else {
    console.log('Network request for products.json failed with response ' + response.status + ': ' + response.statusText);
  }
});

// sets up the app logic, declares required variables, contains all the other functions
function initialize() {
  // grab the UI elements that we need to manipulate
  var category = document.querySelector('#category');
  var searchTerm = document.querySelector('#searchTerm');
  var searchBtn = document.querySelector('button');
  var main = document.querySelector('main');

  // keep a record of what the last category and search term entered were
  var lastCategory = category.value;
  var lastSearch = searchTerm.value;

  // these contain the results of filtering by category, and search term
  // finalGroup will contain the products that need to be displayed after
  // the searching has been done. Each will be an array containing objects.
  // Each object will represent a product
  var categoryGroup;
  var finalGroup;

  // To start with, set finalGroup to equal the entire products database
  // then run updateDisplay(), so ALL products are displayed initially.
  finalGroup = products;
  updateDisplay();

  // Set both to equal an empty array, in time for searches to be run
  categoryGroup = [];
  finalGroup = [];

  // when the search button is clicked, invoke selectCategory() to start
  // a search running to select the category of products we want to display
  searchBtn.onclick = selectCategory;

  function selectCategory(e) {
    // Use preventDefault() to stop the form submitting — that would ruin
    // the experience
    e.preventDefault();

    // Set these back to empty arrays, to clear out the previous search
    categoryGroup = [];
    finalGroup = [];

    // if the category and search term are the same as they were the last time a
    // search was run, the results will be the same, so there is no point running
    // it again — just return out of the function
    if(category.value === lastCategory && searchTerm.value === lastSearch) {
      return;
    } else {
      // update the record of last category and search term
      lastCategory = category.value;
      lastSearch = searchTerm.value;
      // In this case we want to select all products, then filter them by the search
      // term, so we just set categoryGroup to the entire JSON object, then run selectProducts()
      if(category.value === 'All') {
        categoryGroup = products;
        selectProducts();
      // If a specific category is chosen, we need to filter out the products not in that
      // category, then put the remaining products inside categoryGroup, before running
      // selectProducts()
      } else {
        // the values in the <option> elements are uppercase, whereas the categories
        // store in the JSON (under "type") are lowercase. We therefore need to convert
        // to lower case before we do a comparison
        var lowerCaseType = category.value.toLowerCase();
        for(var i = 0; i < products.length ; i++) {
          // If a product's type property is the same as the chosen category, we want to
          // dispay it, so we push it onto the categoryGroup array
          if(products[i].type === lowerCaseType) {
            categoryGroup.push(products[i]);
          }
        }

        // Run selectProducts() after the filtering has bene done
        selectProducts();
      }
    }
  }

  // selectProducts() Takes the group of products selected by selectCategory(), and further
  // filters them by the tnered search term (if one has bene entered)
  function selectProducts() {
    // If no search term has been entered, just make the finalGroup array equal to the categoryGroup
    // array — we don't want to filter the products further — then run updateDisplay().
    if(searchTerm.value === '') {
      finalGroup = categoryGroup;
      updateDisplay();
    } else {
      // Make sure the search term is converted to lower case before comparison. We've kept the
      // product names all lower case to keep things simple
      var lowerCaseSearchTerm = searchTerm.value.toLowerCase();
      // For each product in categoryGroup, see if the search term is contained inside the product name
      // (if the indexOf() result doesn't return -1, it means it is) — if it is, then push the product
      // onto the finalGroup array
      for(var i = 0; i < categoryGroup.length ; i++) {
        if(categoryGroup[i].name.indexOf(lowerCaseSearchTerm) !== -1) {
          finalGroup.push(categoryGroup[i]);
        }
      }

      // run updateDisplay() after this second round of filtering has been done
      updateDisplay();
    }

  }

  // start the process of updating the display with the new set of products
  function updateDisplay() {
    // remove the previous contents of the <main> element
    while (main.firstChild) {
      main.removeChild(main.firstChild);
    }

    // if no products match the search term, display a "No results to display" message
    if(finalGroup.length === 0) {
      var para = document.querySelector('p');
      para.textContent = 'No results to display!';
      main.appendChild(para);
    // for each product we want to display, pass its product object to fetchBlob()
    } else {
      for(var i = 0; i < finalGroup.length; i++) {
        fetchBlob(finalGroup[i]);
      }
    }
  }

  // fetchBlob uses fetch to retrieve the image for that product, and then sends the
  // resulting image display URL and product object on to showProduct() to finally
  // display it
  function fetchBlob(product) {
    // construct the URL path to the image file from the product.image property
    var url = 'images/' + product.image;
    // Use fetch to fetch the image, and convert the resulting response to a blob
    // Again, if any errors occur we report them in the console.
    fetch(url).then(function(response) {
      if(response.ok) {
        response.blob().then(function(blob) {
          // Convert the blob to an object URL — this is basically an temporary internal URL
          // that points to an object stored inside the browser
          objectURL = URL.createObjectURL(blob);
          // invoke showProduct
          showProduct(objectURL, product);
        });
      } else {
        console.log('Network request for "' + product.name + '" image failed with response ' + response.status + ': ' + response.statusText);
      }
    });
  }

  // Display a product inside the <main> element
  function showProduct(objectURL, product) {
    // create <section>, <h2>, <p>, and <img> elements
    var section = document.createElement('section');
    var heading = document.createElement('h2');
    var para = document.createElement('p');
    var image = document.createElement('img');

    // give the <section> a classname equal to the product "type" property so it will display the correct icon
    section.setAttribute('class', product.type);

    // Give the <h2> textContent equal to the product "name" property, but with the first character
    // replaced with the uppercase version of the first character
    heading.textContent = product.name.replace(product.name.charAt(0), product.name.charAt(0).toUpperCase());

    // Give the <p> textContent equal to the product "price" property, with a $ sign in front
    // toFixed(2) is used to fix the price at 2 decimal places, so for example 1.40 is displayed
    // as 1.40, not 1.4.
    para.textContent = '$' + product.price.toFixed(2);

    // Set the src of the <img> element to the ObjectURL, and the alt to the product "name" property
    image.src = objectURL;
    image.alt = product.name;

    // append the elements to the DOM as appropriate, to add the product to the UI
    main.appendChild(section);
    section.appendChild(heading);
    section.appendChild(para);
    section.appendChild(image);
  }
}
<commit_msg>Update can-script.js<commit_after>// create a variable to store the products 'database' in
var products;

// use fetch to retrieve it, and report any errors that occur in the fetch operation
// once the products have been successfully loaded and formatted as a JSON object
// using response.json(), run the initialize() function
fetch('products.json').then(function(response) {
  if(response.ok) {
    response.json().then(function(json) {
      products = json;
      initialize();
    });
  } else {
    console.log('Network request for products.json failed with response ' + response.status + ': ' + response.statusText);
  }
});

// sets up the app logic, declares required variables, contains all the other functions
function initialize() {
  // grab the UI elements that we need to manipulate
  var category = document.querySelector('#category');
  var searchTerm = document.querySelector('#searchTerm');
  var searchBtn = document.querySelector('button');
  var main = document.querySelector('main');

  // keep a record of what the last category and search term entered were
  var lastCategory = category.value;
  var lastSearch = searchTerm.value;

  // these contain the results of filtering by category, and search term
  // finalGroup will contain the products that need to be displayed after
  // the searching has been done. Each will be an array containing objects.
  // Each object will represent a product
  var categoryGroup;
  var finalGroup;

  // To start with, set finalGroup to equal the entire products database
  // then run updateDisplay(), so ALL products are displayed initially.
  finalGroup = products;
  updateDisplay();

  // Set both to equal an empty array, in time for searches to be run
  categoryGroup = [];
  finalGroup = [];

  // when the search button is clicked, invoke selectCategory() to start
  // a search running to select the category of products we want to display
  searchBtn.onclick = selectCategory;

  function selectCategory(e) {
    // Use preventDefault() to stop the form submitting — that would ruin
    // the experience
    e.preventDefault();

    // Set these back to empty arrays, to clear out the previous search
    categoryGroup = [];
    finalGroup = [];

    // if the category and search term are the same as they were the last time a
    // search was run, the results will be the same, so there is no point running
    // it again — just return out of the function
    if(category.value === lastCategory && searchTerm.value === lastSearch) {
      return;
    } else {
      // update the record of last category and search term
      lastCategory = category.value;
      lastSearch = searchTerm.value;
      // In this case we want to select all products, then filter them by the search
      // term, so we just set categoryGroup to the entire JSON object, then run selectProducts()
      if(category.value === 'All') {
        categoryGroup = products;
        selectProducts();
      // If a specific category is chosen, we need to filter out the products not in that
      // category, then put the remaining products inside categoryGroup, before running
      // selectProducts()
      } else {
        // the values in the <option> elements are uppercase, whereas the categories
        // store in the JSON (under "type") are lowercase. We therefore need to convert
        // to lower case before we do a comparison
        var lowerCaseType = category.value.toLowerCase();
        for(var i = 0; i < products.length ; i++) {
          // If a product's type property is the same as the chosen category, we want to
          // dispay it, so we push it onto the categoryGroup array
          if(products[i].type === lowerCaseType) {
            categoryGroup.push(products[i]);
          }
        }

        // Run selectProducts() after the filtering has bene done
        selectProducts();
      }
    }
  }

  // selectProducts() Takes the group of products selected by selectCategory(), and further
  // filters them by the tnered search term (if one has bene entered)
  function selectProducts() {
    // If no search term has been entered, just make the finalGroup array equal to the categoryGroup
    // array — we don't want to filter the products further — then run updateDisplay().
    if(searchTerm.value === '') {
      finalGroup = categoryGroup;
      updateDisplay();
    } else {
      // Make sure the search term is converted to lower case before comparison. We've kept the
      // product names all lower case to keep things simple
      var lowerCaseSearchTerm = searchTerm.value.toLowerCase();
      // For each product in categoryGroup, see if the search term is contained inside the product name
      // (if the indexOf() result doesn't return -1, it means it is) — if it is, then push the product
      // onto the finalGroup array
      for(var i = 0; i < categoryGroup.length ; i++) {
        if(categoryGroup[i].name.indexOf(lowerCaseSearchTerm) !== -1) {
          finalGroup.push(categoryGroup[i]);
        }
      }

      // run updateDisplay() after this second round of filtering has been done
      updateDisplay();
    }

  }

  // start the process of updating the display with the new set of products
  function updateDisplay() {
    // remove the previous contents of the <main> element
    while (main.firstChild) {
      main.removeChild(main.firstChild);
    }

    // if no products match the search term, display a "No results to display" message
    if(finalGroup.length === 0) {
      var para = document.createElement('p');
      para.textContent = 'No results to display!';
      main.appendChild(para);
    // for each product we want to display, pass its product object to fetchBlob()
    } else {
      for(var i = 0; i < finalGroup.length; i++) {
        fetchBlob(finalGroup[i]);
      }
    }
  }

  // fetchBlob uses fetch to retrieve the image for that product, and then sends the
  // resulting image display URL and product object on to showProduct() to finally
  // display it
  function fetchBlob(product) {
    // construct the URL path to the image file from the product.image property
    var url = 'images/' + product.image;
    // Use fetch to fetch the image, and convert the resulting response to a blob
    // Again, if any errors occur we report them in the console.
    fetch(url).then(function(response) {
      if(response.ok) {
        response.blob().then(function(blob) {
          // Convert the blob to an object URL — this is basically an temporary internal URL
          // that points to an object stored inside the browser
          objectURL = URL.createObjectURL(blob);
          // invoke showProduct
          showProduct(objectURL, product);
        });
      } else {
        console.log('Network request for "' + product.name + '" image failed with response ' + response.status + ': ' + response.statusText);
      }
    });
  }

  // Display a product inside the <main> element
  function showProduct(objectURL, product) {
    // create <section>, <h2>, <p>, and <img> elements
    var section = document.createElement('section');
    var heading = document.createElement('h2');
    var para = document.createElement('p');
    var image = document.createElement('img');

    // give the <section> a classname equal to the product "type" property so it will display the correct icon
    section.setAttribute('class', product.type);

    // Give the <h2> textContent equal to the product "name" property, but with the first character
    // replaced with the uppercase version of the first character
    heading.textContent = product.name.replace(product.name.charAt(0), product.name.charAt(0).toUpperCase());

    // Give the <p> textContent equal to the product "price" property, with a $ sign in front
    // toFixed(2) is used to fix the price at 2 decimal places, so for example 1.40 is displayed
    // as 1.40, not 1.4.
    para.textContent = '$' + product.price.toFixed(2);

    // Set the src of the <img> element to the ObjectURL, and the alt to the product "name" property
    image.src = objectURL;
    image.alt = product.name;

    // append the elements to the DOM as appropriate, to add the product to the UI
    main.appendChild(section);
    section.appendChild(heading);
    section.appendChild(para);
    section.appendChild(image);
  }
}
<|endoftext|>


<commit_before>/*
Copyright 2007-2009 WebDriver committers
Copyright 2007-2009 Google Inc.
Portions copyright 2007 ThoughtWorks, Inc

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.
*/

var driver = false;
var domMessenger = null;

// This will configure a FirefoxDriver and DomMessenger for each
// _browser window_ (not chrome window). Multiple tabs in the same window will
// share a FirefoxDriver and DomMessenger instance.
window.addEventListener("load", function(e) {
    handle = Components.classes["@googlecode.com/webdriver/fxdriver;1"].createInstance(Components.interfaces.nsISupports);
    var server = handle.wrappedJSObject;

  if (!domMessenger) {
    var appcontent = document.getElementById('appcontent');
    if (appcontent) {
      try {
        var commandProcessor = Components.
            classes['@googlecode.com/webdriver/command-processor;1'].
            getService(Components.interfaces.nsICommandProcessor);
        domMessenger = new DomMessenger(commandProcessor);
        appcontent.addEventListener('DOMContentLoaded',
            function(e) {
              domMessenger.onPageLoad(e);
            }, true);
        appcontent.addEventListener('pagehide',
            function(e) {
              domMessenger.onPageUnload(e);
            }, true);
      } catch (ex) {
        // Not catching this can really mess things up and lead to inexplicable
        // and hard to debug behavior.
        Components.utils.reportError(ex);
      }
    }
  }

    if (!driver) {
        driver = server.newDriver(window);
    }

    server.startListening();

}, true);

//window.addEventListener("focus", function(e) {
//    var active = e.originalTarget;
//    var doc = gBrowser.selectedBrowser.contentDocument;
//    if (active.ownerDocument == doc) {
//        driver.activeElement = active;
//    }
//}, true);
<commit_msg>DavidBurns removing argument that isnt needed<commit_after>/*
Copyright 2007-2009 WebDriver committers
Copyright 2007-2009 Google Inc.
Portions copyright 2007 ThoughtWorks, Inc

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.
*/

var driver = false;
var domMessenger = null;

// This will configure a FirefoxDriver and DomMessenger for each
// _browser window_ (not chrome window). Multiple tabs in the same window will
// share a FirefoxDriver and DomMessenger instance.
window.addEventListener("load", function(e) {
    try{
        handle = Components.classes["@googlecode.com/webdriver/fxdriver;1"].
        createInstance();
    } catch (e){
        dump("Error: " + e);
    }
    var server = handle.wrappedJSObject;

  if (!domMessenger) {
    var appcontent = document.getElementById('appcontent');
    if (appcontent) {
      try {
        var commandProcessor = Components.
            classes['@googlecode.com/webdriver/command-processor;1'].
            getService(Components.interfaces.nsICommandProcessor);
        domMessenger = new DomMessenger(commandProcessor);
        appcontent.addEventListener('DOMContentLoaded',
            function(e) {
              domMessenger.onPageLoad(e);
            }, true);
        appcontent.addEventListener('pagehide',
            function(e) {
              domMessenger.onPageUnload(e);
            }, true);
      } catch (ex) {
        // Not catching this can really mess things up and lead to inexplicable
        // and hard to debug behavior.
        Components.utils.reportError(ex);
      }
    }
  }

    if (!driver) {
        driver = server.newDriver(window);
    }

    server.startListening();

}, true);

//window.addEventListener("focus", function(e) {
//    var active = e.originalTarget;
//    var doc = gBrowser.selectedBrowser.contentDocument;
//    if (active.ownerDocument == doc) {
//        driver.activeElement = active;
//    }
//}, true);
<|endoftext|>


<commit_before>define([
    'jquery',
    'backbone',
    'views/editable/feedback-mixin',
], function ($, BB, Mixin) {
    var ctx = $("#qunit-fixture");
    Mixin.removeDelay = 200;
    Mixin.$el = ctx;
    Mixin.$ = $;

    return function () {
        asyncTest("Test loadingFeedback works", function () {
            expect(3);
            Mixin.saveFlag = true;
            feedback = Mixin.loadingFeedback(".editable", "works");

            ok(!$(".editable", ctx).hasClass("works"), "Target element does not have class yet");
            feedback.call(Mixin);
            ok($(".editable", ctx).hasClass("works"), "Target element now has the class");
            setTimeout(function () {
                ok(!$(".editable", ctx).hasClass("works"), "Target element again does not have the class");
                start();
            }, Mixin.removeDelay + 10);
        });

        asyncTest("Test loadingFeedback keeps class when instructed", function () {
            expect(3);
            Mixin.saveFlag = true;
            feedback = Mixin.loadingFeedback(".editable", "works", true);

            ok(!$(".editable", ctx).hasClass("works"), "Target element does not have class yet");
            feedback.call(Mixin);
            ok($(".editable", ctx).hasClass("works"), "Target element now has the class");
            setTimeout(function () {
                ok($(".editable", ctx).hasClass("works"), "Target element still has the class");
                start();
            }, Mixin.removeDelay + 10);
        });

        test("Test attachFeedback attached model listeners", function () {
            var Model = BB.Model.extend({}),
                m = new Model,
                ViewClass = BB.View.extend(Mixin).extend({
                    initialize: function () {
                        this.attachFeedback();
                    }
                }),
                view = new ViewClass({
                    model: m
                });

            ok(!$(".editable", ctx).hasClass("success"), "Target element does not have class yet");

            view.saveFlag = true;
            m.trigger("sync");
            ok($(".editable", ctx).hasClass("success"), "Target element now has the class");
            ok(!view.saveFlag, "saveFlag attribute was resetted.")
        });

        asyncTest("Test attachFeedback attached success listener loses class", function () {
            var Model = BB.Model.extend({}),
                m = new Model,
                ViewClass = BB.View.extend(Mixin).extend({
                    initialize: function () {
                        this.attachFeedback();
                    }
                }),
                view = new ViewClass({
                    model: m
                });
            expect(4);

            ok(!$(".editable", ctx).hasClass("success"), "Target element does not have class yet");

            view.saveFlag = true;
            m.trigger("sync");
            ok($(".editable", ctx).hasClass("success"), "Target element now has the class");
            ok(!view.saveFlag, "saveFlag attribute was resetted.")
            setTimeout(function () {
                ok(!$(".editable", ctx).hasClass("success"), "Target element lost the class");
                start();
            }, Mixin.removeDelay + 10);
        });

        asyncTest("Test attachFeedback attached error listener keeps class", function () {
            var Model = BB.Model.extend({}),
                m = new Model,
                ViewClass = BB.View.extend(Mixin).extend({
                    initialize: function () {
                        this.attachFeedback();
                    }
                }),
                view = new ViewClass({
                    model: m
                });
            expect(4);

            ok(!$(".editable", ctx).hasClass("error"), "Target element does not have class yet");

            view.saveFlag = true;
            m.trigger("error");
            ok($(".editable", ctx).hasClass("error"), "Target element now has the class");
            ok(!view.saveFlag, "saveFlag attribute was resetted.")
            setTimeout(function () {
                ok($(".editable", ctx).hasClass("error"), "Target element kept the class");
                start();
            }, Mixin.removeDelay + 10);
        });
    };
});
<commit_msg>Update feedback mixin test to use Jasmine<commit_after>define([
    'jquery',
    'backbone',
    'views/editable/feedback-mixin',
], function ($, BB, Mixin) {
    var ctx = $("#qunit-fixture");
    Mixin.removeDelay = 200;
    Mixin.$el = ctx;
    Mixin.$ = $;

    jasmine.getFixtures().fixturesPath = 'tests/html_fixtures';

    function callFeedback(feedback, ctx, done) {
    	feedback.call(Mixin);
    	since("Target element now has the class");
        expect($(".editable", ctx)).toHaveClass("works");
		done();
    }

    function triggerModel(view, m, ctx, trigger, elementClass, done) {
    	view.saveFlag = true;
        m.trigger(trigger);
        since("Target element now has the class");
    	expect($(".editable", ctx)).toHaveClass(elementClass);
        since("saveFlag attribute was resetted.");
        expect(view.saveFlag).toEqual(false);
        done();
    }

    describe("Test feedback mixin", function() {
    	beforeEach(function(done) {
    		loadFixtures('editables/feedback_mixin.html');
    		ctx = $("#qunit-fixture");
    		done();
    	});

	    it("Test loadingFeedback works", function (done) {
	        var assertionCounter = 0;

	        Mixin.saveFlag = true;
	        feedback = Mixin.loadingFeedback(".editable", "works");
	        since("Target element does not have class yet");
	        expect($(".editable", ctx)).not.toHaveClass("works");
		    assertionCounter++;

		    callFeedback(feedback, ctx, done);
    		assertionCounter++;

	        since("Target element again does not have the class");
	        expect($(".editable", ctx)).not.toHaveClass("works");
	        assertionCounter++;

			expect(assertionCounter).toEqual(3);
	    });

	    it("Test loadingFeedback keeps class when instructed", function (done) {
	        var assertionCounter = 0;
	        Mixin.saveFlag = true;
	        feedback = Mixin.loadingFeedback(".editable", "works", true);
	        since("Target element does not have class yet");
	        expect($(".editable", ctx)).not.toHaveClass("works");
	        assertionCounter++;

	        callFeedback(feedback, ctx, done);
	        assertionCounter++;

	       	since("Target element still has the class");
	        expect($(".editable", ctx)).toHaveClass("works");
	        assertionCounter++;

	        expect(assertionCounter).toEqual(3);
	    });

	    it("Test attachFeedback attached model listeners", function (done) {
	        var Model = BB.Model.extend({}),
	            m = new Model,
	            ViewClass = BB.View.extend(Mixin).extend({
	                initialize: function () {
	                    this.attachFeedback();
	                }
	            }),
	            view = new ViewClass({
	                model: m
	            });

	        since("Target element does not have class yet");
	        expect($(".editable", ctx)).not.toHaveClass("success");

	    	triggerModel(view, m, ctx, "sync", "success", done)
	    });

	    it("Test attachFeedback attached success listener loses class", function (done) {
	        var Model = BB.Model.extend({}),
	            m = new Model,
	            ViewClass = BB.View.extend(Mixin).extend({
	                initialize: function () {
	                    this.attachFeedback();
	                }
	            }),
	            view = new ViewClass({
	                model: m
	            });
	        var assertionCounter = 0;

	        since("Target element does not have class yet");
	        expect($(".editable", ctx)).not.toHaveClass("success");
	    	assertionCounter++;

	        triggerModel(view, m, ctx, "sync", "success", done);
	        assertionCounter+=2;

	        since("Target element lost the class");
	        expect($(".editable", ctx)).not.toHaveClass("success");
	        assertionCounter++;

	        expect(assertionCounter).toEqual(4);
	    });

	    it("Test attachFeedback attached error listener keeps class", function (done) {
	        var Model = BB.Model.extend({}),
	            m = new Model,
	            ViewClass = BB.View.extend(Mixin).extend({
	                initialize: function () {
	                    this.attachFeedback();
	                }
	            }),
	            view = new ViewClass({
	                model: m
	            });
	        var assertionCounter = 0;

	        since("Target element does not have class yet");
	        expect($(".editable", ctx)).not.toHaveClass("error");
	    	assertionCounter++;

	        triggerModel(view, m, ctx, "error", "error", done)
	        assertionCounter += 2;

	        since("Target element kept the class");
	        expect($(".editable", ctx)).toHaveClass("error");
	        assertionCounter++;

	        expect(assertionCounter).toEqual(4);
	    });
    });
});
<|endoftext|>


<commit_before>// View model for the page
function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.app  = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("WorksheetNameRapport");}, gvm);
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("HomeRapportTitle");}, gvm);
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectRapportName");}, gvm);
    gvm.homeManual = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("WorksheetRapportManual");}, gvm);

    gvm.formequip = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("FormEquip");}, gvm);
    gvm.formmethod = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("FormMethod");}, gvm);

    gvm.userId = null;
    gvm.availableModules = ko.observableArray([]);

    gvm.updateModules = function(courseid) {
        $.getJSON('/api/coursestructure/' + courseid, function(data) {
            if (!$.isEmptyObject(data)) {
                gvm.availableModules.removeAll();

                $.each(data, function(i, item) {
                    var tblObject = {modid: item.id, modname: item.name, competences: new Array()};
                    if (item.doelstellingen.id !== "undefined") {
                        console.log(item.doelstellingen);
                        gvm.updateCompetences(item.doelstellingen, tblObject.competences);
                    }
                    gvm.availableModules.push(tblObject);
                });
                makeChecklist();
            }
        });
    }

    gvm.updateCompetences = function(data, competences) {
        $.each(data, function(i, item) {
            var tblObject = {comid: item.id, comname: item.name, criterias: new Array()}
            if (item.criterias.id !== "undefined") {
                console.log(item.criterias);
                gvm.updateCriteria(item.criterias, tblObject.criterias);
            }
            competences.push(tblObject);
        });
        makeChecklist();
    }

    gvm.updateCriteria = function(data, criteria) {
        $.each(data, function(i, item){
            var tblObject = {critid: item.id, critname: item.name};
            criteria.push(tblObject);
        });
        makeChecklist();
    }
}

function addWorksheetProperties(serialData, wid, callback) {
    var collection = getCheckedFields();
    $.ajax({
        url: "/api/worksheetproperties/" + wid,
        type: "PUT",
        data: serialData,
        success: function(data) {
            console.log(data);
            callback(false);
        },
        error: function(data) {
            callback(true);
        }
    });
    $.ajax({
        url: "/api/worksheetmodules",
        type: "POST",
        data: {id: wid, modules: collection[0], competences: collection[1], criteria: collection[2]},
        success: function(data) {
            console.log('Success');
        },
        error: function(data) {
            console.log('Failure');
        }
    });
}

function makeChecklist() {
    $('.list-group.checked-list-box .list-group-item').each(function () {

        // Settings
        var $widget = $(this),
            $checkbox = $('<input type="checkbox" class="hidden" />'),
            color = ($widget.data('color') ? $widget.data('color') : "primary"),
            style = ($widget.data('style') == "button" ? "btn-" : "list-group-item-"),
            settings = {
                on: {
                    icon: 'glyphicon glyphicon-check'
                },
                off: {
                    icon: 'glyphicon glyphicon-unchecked'
                }
            };

        $widget.css('cursor', 'pointer')
        $widget.append($checkbox);

        // Event Handlers
        $widget.on('click', function () {
            $checkbox.prop('checked', !$checkbox.is(':checked'));
            $checkbox.triggerHandler('change');
            updateDisplay();
        });
        $checkbox.on('change', function () {
            updateDisplay();
        });

        // Actions
        function updateDisplay() {
            var isChecked = $checkbox.is(':checked');

            // Set the button's state
            $widget.data('state', (isChecked) ? "on" : "off");

            // Set the button's icon
            $widget.find('.state-icon')
                .removeClass()
                .addClass('state-icon ' + settings[$widget.data('state')].icon);

            // Update the button's color
            if (isChecked) {
                $widget.addClass(style + color + ' active');
            } else {
                $widget.removeClass(style + color + ' active');
            }
        }

        // Initialization
        function init() {

            if ($widget.data('checked') == true) {
                $checkbox.prop('checked', !$checkbox.is(':checked'));
            }

            updateDisplay();

            // Inject the icon if applicable
            if ($widget.find('.state-icon').length == 0) {
                $widget.prepend('');
            }
        }
        init();
    });
}

function getCheckedFields() {
    var checkedItems = [], counter = 0;
    $("#check-list-box li.active").each(function(idx, li) {
        checkedItems[counter] = $(li).text();
        counter++;
    });
    return filterModules(checkedItems);
}

function filterModules(data) {
    var collection = [];
    var modules = [];
    var comps = [];
    var criteria = [];
    $.each(viewModel.availableModules(), function(i, item) {
        if (data.indexOf(item.modname) > -1) {
            modules.push(item.modid);
        }
        $.each(item.competences, function(i, item) {
            if (data.indexOf(item.comname) > -1) {
                comps.push(item.comid);
            }
            $.each(item.criterias, function(i, item) {
                if (data.indexOf(item.critname) > -1) {
                    criteria.push(item.critid);
                }
            });
        });
    });
    collection.push(modules);
    collection.push(comps);
    collection.push(criteria);
    return collection;
}

function initPage() {
    $.getJSON('/api/currentuser', function(data) {
        var courseid = $('#storage').attr('data-value');
        viewModel.userId = data.id;
        viewModel.updateModules(courseid);
    });

    $('#submit').click(function() {
        var wid = $('#header').attr('data-value');
        addWorksheetProperties($('#worksheetform').serialize(), wid, function() {
            $('#worksheetform').prepend("
There was a problem submitting the form
");
        });
    });
}
<commit_msg>properties van worksheet invullen via formulier<commit_after>// View model for the page
function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.app  = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("WorksheetNameRapport");}, gvm);
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("HomeRapportTitle");}, gvm);
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectRapportName");}, gvm);
    gvm.homeManual = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("WorksheetRapportManual");}, gvm);

    gvm.formequip = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("FormEquip");}, gvm);
    gvm.formmethod = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("FormMethod");}, gvm);

    gvm.userId = null;
    gvm.availableModules = ko.observableArray([]);

    gvm.updateModules = function(courseid) {
        $.getJSON('/api/coursestructure/' + courseid, function(data) {
            if (!$.isEmptyObject(data)) {
                gvm.availableModules.removeAll();

                $.each(data, function(i, item) {
                    var tblObject = {modid: item.id, modname: item.name, competences: new Array()};
                    if (item.doelstellingen[0].id !== null) {
                        console.log(item.doelstellingen);
                        gvm.updateCompetences(item.doelstellingen, tblObject.competences);
                    }
                    gvm.availableModules.push(tblObject);
                });
                makeChecklist();
            }
        });
    }

    gvm.updateCompetences = function(data, competences) {
        $.each(data, function(i, item) {
            var tblObject = {comid: item.id, comname: item.name, criterias: new Array()}
            if (item.criterias[0].id !== null) {
                console.log(item.criterias);
                gvm.updateCriteria(item.criterias, tblObject.criterias);
            }
            competences.push(tblObject);
        });
        makeChecklist();
    }

    gvm.updateCriteria = function(data, criteria) {
        $.each(data, function(i, item){
            var tblObject = {critid: item.id, critname: item.name};
            criteria.push(tblObject);
        });
        makeChecklist();
    }
}

function addWorksheetProperties(serialData, wid, callback) {
    var collection = getCheckedFields();
    $.ajax({
        url: "/api/worksheetproperties/" + wid,
        type: "PUT",
        data: serialData,
        success: function(data) {
            console.log(data);
            callback(false);
        },
        error: function(data) {
            callback(true);
        }
    });
    $.ajax({
        url: "/api/worksheetmodules",
        type: "POST",
        data: {id: wid, modules: collection[0], competences: collection[1], criteria: collection[2]},
        success: function(data) {
            console.log('Success');
        },
        error: function(data) {
            console.log('Failure');
        }
    });
}

function makeChecklist() {
    $('.list-group.checked-list-box .list-group-item').each(function () {

        // Settings
        var $widget = $(this),
            $checkbox = $('<input type="checkbox" class="hidden" />'),
            color = ($widget.data('color') ? $widget.data('color') : "primary"),
            style = ($widget.data('style') == "button" ? "btn-" : "list-group-item-"),
            settings = {
                on: {
                    icon: 'glyphicon glyphicon-check'
                },
                off: {
                    icon: 'glyphicon glyphicon-unchecked'
                }
            };

        $widget.css('cursor', 'pointer')
        $widget.append($checkbox);

        // Event Handlers
        $widget.on('click', function () {
            $checkbox.prop('checked', !$checkbox.is(':checked'));
            $checkbox.triggerHandler('change');
            updateDisplay();
        });
        $checkbox.on('change', function () {
            updateDisplay();
        });

        // Actions
        function updateDisplay() {
            var isChecked = $checkbox.is(':checked');

            // Set the button's state
            $widget.data('state', (isChecked) ? "on" : "off");

            // Set the button's icon
            $widget.find('.state-icon')
                .removeClass()
                .addClass('state-icon ' + settings[$widget.data('state')].icon);

            // Update the button's color
            if (isChecked) {
                $widget.addClass(style + color + ' active');
            } else {
                $widget.removeClass(style + color + ' active');
            }
        }

        // Initialization
        function init() {

            if ($widget.data('checked') == true) {
                $checkbox.prop('checked', !$checkbox.is(':checked'));
            }

            updateDisplay();

            // Inject the icon if applicable
            if ($widget.find('.state-icon').length == 0) {
                $widget.prepend('');
            }
        }
        init();
    });
}

function getCheckedFields() {
    var checkedItems = [], counter = 0;
    $("#check-list-box li.active").each(function(idx, li) {
        checkedItems[counter] = $(li).text();
        counter++;
    });
    return filterModules(checkedItems);
}

function filterModules(data) {
    var collection = [];
    var modules = [];
    var comps = [];
    var criteria = [];
    $.each(viewModel.availableModules(), function(i, item) {
        if (data.indexOf(item.modname) > -1) {
            modules.push(item.modid);
        }
        $.each(item.competences, function(i, item) {
            if (data.indexOf(item.comname) > -1) {
                comps.push(item.comid);
            }
            $.each(item.criterias, function(i, item) {
                if (data.indexOf(item.critname) > -1) {
                    criteria.push(item.critid);
                }
            });
        });
    });
    collection.push(modules);
    collection.push(comps);
    collection.push(criteria);
    return collection;
}

function initPage() {
    $.getJSON('/api/currentuser', function(data) {
        var courseid = $('#storage').attr('data-value');
        viewModel.userId = data.id;
        viewModel.updateModules(courseid);
    });

    $('#submit').click(function() {
        var wid = $('#header').attr('data-value');
        addWorksheetProperties($('#worksheetform').serialize(), wid, function() {
            $('#worksheetform').prepend("
There was a problem submitting the form
");
        });
    });
}
<|endoftext|>


<commit_before>/*jshint strict: false, maxlen: 500 */
/*global require, assertEqual, assertTrue, AQL_EXPLAIN, AQL_EXECUTE */

////////////////////////////////////////////////////////////////////////////////
/// @brief tests for optimizer rule use index-range
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014-2014 triagens GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Max Neunhoeffer
/// @author Copyright 2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var internal = require("internal");
var jsunity = require("jsunity");
var helper = require("org/arangodb/aql-helper");
var removeAlwaysOnClusterRules = helper.removeAlwaysOnClusterRules;

////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////

function optimizerRuleUseIndexRangeTester () {
  var suiteName = "TestUseIndexRangeRule";
  var ruleName = "use-index-range";
  var collBaseName = "UTUseIndexRange";
  var collNames = ["NoInd", "SkipInd", "HashInd", "BothInd"];
  var collNoInd;
  var collSkipInd;
  var collHashInd;
  var collBothInd;

  // various choices to control the optimizer:
  var paramNone     = { optimizer: { rules: [ "-all" ] } };
  var paramEnabled  = { optimizer: { rules: [ "-all", "+" + ruleName ] } };
  var paramDisabled = { optimizer: { rules: [ "+all", "-" + ruleName ] } };
  var paramAll      = { optimizer: { rules: [ "+all" ] } };
  var paramEnabledAllPlans = { optimizer: { rules: [ "-all", "+" + ruleName ]},
                               allPlans: true };
  var paramAllAllPlans = { optimizer: { rules: [ "+all" ]}, allPlans: true };

  return {

////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////

    setUp : function () {
      var n = collNames.map(function(x) { return collBaseName + x; });
      var colls = [];
      for (var i = 0; i < n.length; i++) {
        var collName = n[i];
        internal.db._drop(collName);
        coll = internal.db._create(collName);
        for (var j = 0; j < 10; j++) {
          coll.insert({"a":j, "s":"s"+j});
        }
        colls.push(coll);
      }
      collNoInd = colls[0];
      collSkipInd = colls[1];
      collSkipInd.ensureSkiplist("a");
      collHashInd = colls[2];
      collHashInd.ensureHashIndex("a");
      collBothInd = colls[3];
      collBothInd.ensureHashIndex("a");
      collBothInd.ensureSkiplist("a");
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////

    tearDown : function () {
      var n = collNames.map(function(x) { return collBaseName + x; });
      for (var i = 0; i < n.length; i++) {
        internal.db._drop(n[i]);
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test that rule has no effect when explicitly disabled
////////////////////////////////////////////////////////////////////////////////

    testRuleDisabled : function () {
      var queries = [
        "FOR i IN UTUseIndexRangeNoInd FILTER i.a >= 2 RETURN i",
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a >= 2 RETURN i",
        "FOR i IN UTUseIndexRangeHashInd FILTER i.a == 2 RETURN i",
        "FOR i IN UTUseIndexRangeBothInd FILTER i.a == 2 RETURN i",
      ];

      queries.forEach(function(query) {
        var result = AQL_EXPLAIN(query, { }, paramNone);
        assertEqual([ ], removeAlwaysOnClusterRules(result.plan.rules), query);
      });
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test that rule has no effect
////////////////////////////////////////////////////////////////////////////////

    testRuleNoEffect : function () {
      var queries = [
        "FOR i IN UTUseIndexRangeNoInd FILTER i.a >= 2 RETURN i",
        "FOR i IN UTUseIndexRangeNoInd FILTER i.a == 2 RETURN i",
        "FOR i IN UTUseIndexRangeHashInd FILTER i.a >= 2 RETURN i"
      ];

      queries.forEach(function(query) {
        var result = AQL_EXPLAIN(query, { }, paramEnabled);
        assertEqual([ ], removeAlwaysOnClusterRules(result.plan.rules), query);
      });
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test that rule has an effect
////////////////////////////////////////////////////////////////////////////////

    testRuleHasEffect : function () {
      var queries = [
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a >= 2 RETURN i",
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a == 2 RETURN i",
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a < 2 RETURN i",
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a < 2 && i.a > 0 RETURN i",
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a < 2 && i.a > 3 RETURN i",
        "FOR i IN UTUseIndexRangeHashInd FILTER i.a == 2 RETURN i",
        "FOR i IN UTUseIndexRangeBothInd FILTER i.a == 2 RETURN i",
        "FOR i IN UTUseIndexRangeBothInd FILTER i.a <= 2 RETURN i",
        "FOR i IN UTUseIndexRangeBothInd FILTER i.a > 2 RETURN i"
      ];

      queries.forEach(function(query) {
        var result = AQL_EXPLAIN(query, { }, paramEnabled);
        assertEqual([ ruleName ], removeAlwaysOnClusterRules(result.plan.rules),
                    query);
      });
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test that rule has an effect
////////////////////////////////////////////////////////////////////////////////

    testRuleHasEffectWithAll : function () {
      var queries = [
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a >= 2 RETURN i",
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a == 2 RETURN i",
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a < 2 RETURN i",
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a < 2 && i.a > 0 RETURN i",
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a < 2 && i.a > 3 RETURN i",
        "FOR i IN UTUseIndexRangeHashInd FILTER i.a == 2 RETURN i",
        "FOR i IN UTUseIndexRangeBothInd FILTER i.a == 2 RETURN i",
        "FOR i IN UTUseIndexRangeBothInd FILTER i.a <= 2 RETURN i",
        "FOR i IN UTUseIndexRangeBothInd FILTER i.a > 2 RETURN i"
      ];

      queries.forEach(function(query) {
        var result = AQL_EXPLAIN(query, { }, paramAll);
        assertTrue(result.plan.rules.indexOf(ruleName) >= 0, query);
      });
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test that plan explosion does not happen
////////////////////////////////////////////////////////////////////////////////

    testRuleHasNoPlanExplosion : function () {
      var query =
        "LET A = (FOR a IN UTUseIndexRangeBothInd FILTER a.a == 2 RETURN a) "+
        "LET B = (FOR b IN UTUseIndexRangeBothInd FILTER b.a == 2 RETURN b) "+
        "LET C = (FOR c IN UTUseIndexRangeBothInd FILTER c.a == 2 RETURN c) "+
        "LET D = (FOR d IN UTUseIndexRangeBothInd FILTER d.a == 2 RETURN d) "+
        "LET E = (FOR e IN UTUseIndexRangeBothInd FILTER e.a == 2 RETURN e) "+
        "LET F = (FOR f IN UTUseIndexRangeBothInd FILTER f.a == 2 RETURN f) "+
        "LET G = (FOR g IN UTUseIndexRangeBothInd FILTER g.a == 2 RETURN g) "+
        "LET H = (FOR h IN UTUseIndexRangeBothInd FILTER h.a == 2 RETURN h) "+
        "LET I = (FOR i IN UTUseIndexRangeBothInd FILTER i.a == 2 RETURN i) "+
        "LET J = (FOR j IN UTUseIndexRangeBothInd FILTER j.a == 2 RETURN j) "+
        "FOR k IN UTUseIndexRangeBothInd FILTER k.a == 2 "+
        "  RETURN {A:A, B:B, C:C, D:D, E:E, F:F, G:G, H:H, I:I, J:J, K:k}";

      var result = AQL_EXPLAIN(query, { }, paramEnabledAllPlans);
      assertTrue(result.plans.length < 40, query);
      var result = AQL_EXPLAIN(query, { }, paramAllAllPlans);
      assertTrue(result.plans.length < 40, query);
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test that plan explosion does not happen
////////////////////////////////////////////////////////////////////////////////

    testRuleMakesAll : function () {
      var query =
        "LET A = (FOR a IN UTUseIndexRangeBothInd FILTER a.a == 2 RETURN a) "+
        "LET B = (FOR b IN UTUseIndexRangeBothInd FILTER b.a == 2 RETURN b) "+
        "LET C = (FOR c IN UTUseIndexRangeBothInd FILTER c.a == 2 RETURN c) "+
        "FOR k IN UTUseIndexRangeBothInd FILTER k.a == 2 "+
        "  RETURN {A:A, B:B, C:C, K:k}";

      var result = AQL_EXPLAIN(query, { }, paramEnabledAllPlans);
      assertTrue(result.plans.length == 16, query);
      var result = AQL_EXPLAIN(query, { }, paramAllAllPlans);
      assertTrue(result.plans.length == 16, query);
    }

  };
}

////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suite
////////////////////////////////////////////////////////////////////////////////

jsunity.run(optimizerRuleUseIndexRangeTester);

return jsunity.done();

// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:
<commit_msg>jslint<commit_after>/*jshint strict: false, maxlen: 500 */
/*global require, assertEqual, assertTrue, AQL_EXPLAIN */

////////////////////////////////////////////////////////////////////////////////
/// @brief tests for optimizer rule use index-range
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014-2014 triagens GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Max Neunhoeffer
/// @author Copyright 2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var internal = require("internal");
var jsunity = require("jsunity");
var helper = require("org/arangodb/aql-helper");
var removeAlwaysOnClusterRules = helper.removeAlwaysOnClusterRules;

////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////

function optimizerRuleUseIndexRangeTester () {
  var ruleName = "use-index-range";
  var collBaseName = "UTUseIndexRange";
  var collNames = ["NoInd", "SkipInd", "HashInd", "BothInd"];
  var collNoInd;
  var collSkipInd;
  var collHashInd;
  var collBothInd;

  // various choices to control the optimizer:
  var paramNone     = { optimizer: { rules: [ "-all" ] } };
  var paramEnabled  = { optimizer: { rules: [ "-all", "+" + ruleName ] } };
  var paramAll      = { optimizer: { rules: [ "+all" ] } };
  var paramEnabledAllPlans = { optimizer: { rules: [ "-all", "+" + ruleName ]},
                               allPlans: true };
  var paramAllAllPlans = { optimizer: { rules: [ "+all" ]}, allPlans: true };

  return {

////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////

    setUp : function () {
      var n = collNames.map(function(x) { return collBaseName + x; });
      var colls = [];
      for (var i = 0; i < n.length; i++) {
        var collName = n[i], coll;
        internal.db._drop(collName);
        coll = internal.db._create(collName);
        for (var j = 0; j < 10; j++) {
          coll.insert({"a":j, "s":"s"+j});
        }
        colls.push(coll);
      }
      collNoInd = colls[0];
      collSkipInd = colls[1];
      collSkipInd.ensureSkiplist("a");
      collHashInd = colls[2];
      collHashInd.ensureHashIndex("a");
      collBothInd = colls[3];
      collBothInd.ensureHashIndex("a");
      collBothInd.ensureSkiplist("a");
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////

    tearDown : function () {
      var n = collNames.map(function(x) { return collBaseName + x; });
      for (var i = 0; i < n.length; i++) {
        internal.db._drop(n[i]);
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test that rule has no effect when explicitly disabled
////////////////////////////////////////////////////////////////////////////////

    testRuleDisabled : function () {
      var queries = [
        "FOR i IN UTUseIndexRangeNoInd FILTER i.a >= 2 RETURN i",
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a >= 2 RETURN i",
        "FOR i IN UTUseIndexRangeHashInd FILTER i.a == 2 RETURN i",
        "FOR i IN UTUseIndexRangeBothInd FILTER i.a == 2 RETURN i",
      ];

      queries.forEach(function(query) {
        var result = AQL_EXPLAIN(query, { }, paramNone);
        assertEqual([ ], removeAlwaysOnClusterRules(result.plan.rules), query);
      });
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test that rule has no effect
////////////////////////////////////////////////////////////////////////////////

    testRuleNoEffect : function () {
      var queries = [
        "FOR i IN UTUseIndexRangeNoInd FILTER i.a >= 2 RETURN i",
        "FOR i IN UTUseIndexRangeNoInd FILTER i.a == 2 RETURN i",
        "FOR i IN UTUseIndexRangeHashInd FILTER i.a >= 2 RETURN i"
      ];

      queries.forEach(function(query) {
        var result = AQL_EXPLAIN(query, { }, paramEnabled);
        assertEqual([ ], removeAlwaysOnClusterRules(result.plan.rules), query);
      });
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test that rule has an effect
////////////////////////////////////////////////////////////////////////////////

    testRuleHasEffect : function () {
      var queries = [
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a >= 2 RETURN i",
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a == 2 RETURN i",
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a < 2 RETURN i",
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a < 2 && i.a > 0 RETURN i",
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a < 2 && i.a > 3 RETURN i",
        "FOR i IN UTUseIndexRangeHashInd FILTER i.a == 2 RETURN i",
        "FOR i IN UTUseIndexRangeBothInd FILTER i.a == 2 RETURN i",
        "FOR i IN UTUseIndexRangeBothInd FILTER i.a <= 2 RETURN i",
        "FOR i IN UTUseIndexRangeBothInd FILTER i.a > 2 RETURN i"
      ];

      queries.forEach(function(query) {
        var result = AQL_EXPLAIN(query, { }, paramEnabled);
        assertEqual([ ruleName ], removeAlwaysOnClusterRules(result.plan.rules),
                    query);
      });
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test that rule has an effect
////////////////////////////////////////////////////////////////////////////////

    testRuleHasEffectWithAll : function () {
      var queries = [
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a >= 2 RETURN i",
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a == 2 RETURN i",
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a < 2 RETURN i",
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a < 2 && i.a > 0 RETURN i",
        "FOR i IN UTUseIndexRangeSkipInd FILTER i.a < 2 && i.a > 3 RETURN i",
        "FOR i IN UTUseIndexRangeHashInd FILTER i.a == 2 RETURN i",
        "FOR i IN UTUseIndexRangeBothInd FILTER i.a == 2 RETURN i",
        "FOR i IN UTUseIndexRangeBothInd FILTER i.a <= 2 RETURN i",
        "FOR i IN UTUseIndexRangeBothInd FILTER i.a > 2 RETURN i"
      ];

      queries.forEach(function(query) {
        var result = AQL_EXPLAIN(query, { }, paramAll);
        assertTrue(result.plan.rules.indexOf(ruleName) >= 0, query);
      });
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test that plan explosion does not happen
////////////////////////////////////////////////////////////////////////////////

    testRuleHasNoPlanExplosion : function () {
      var query =
        "LET A = (FOR a IN UTUseIndexRangeBothInd FILTER a.a == 2 RETURN a) "+
        "LET B = (FOR b IN UTUseIndexRangeBothInd FILTER b.a == 2 RETURN b) "+
        "LET C = (FOR c IN UTUseIndexRangeBothInd FILTER c.a == 2 RETURN c) "+
        "LET D = (FOR d IN UTUseIndexRangeBothInd FILTER d.a == 2 RETURN d) "+
        "LET E = (FOR e IN UTUseIndexRangeBothInd FILTER e.a == 2 RETURN e) "+
        "LET F = (FOR f IN UTUseIndexRangeBothInd FILTER f.a == 2 RETURN f) "+
        "LET G = (FOR g IN UTUseIndexRangeBothInd FILTER g.a == 2 RETURN g) "+
        "LET H = (FOR h IN UTUseIndexRangeBothInd FILTER h.a == 2 RETURN h) "+
        "LET I = (FOR i IN UTUseIndexRangeBothInd FILTER i.a == 2 RETURN i) "+
        "LET J = (FOR j IN UTUseIndexRangeBothInd FILTER j.a == 2 RETURN j) "+
        "FOR k IN UTUseIndexRangeBothInd FILTER k.a == 2 "+
        "  RETURN {A:A, B:B, C:C, D:D, E:E, F:F, G:G, H:H, I:I, J:J, K:k}";

      var result = AQL_EXPLAIN(query, { }, paramEnabledAllPlans);
      assertTrue(result.plans.length < 40, query);
      result = AQL_EXPLAIN(query, { }, paramAllAllPlans);
      assertTrue(result.plans.length < 40, query);
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test that plan explosion does not happen
////////////////////////////////////////////////////////////////////////////////

    testRuleMakesAll : function () {
      var query =
        "LET A = (FOR a IN UTUseIndexRangeBothInd FILTER a.a == 2 RETURN a) "+
        "LET B = (FOR b IN UTUseIndexRangeBothInd FILTER b.a == 2 RETURN b) "+
        "LET C = (FOR c IN UTUseIndexRangeBothInd FILTER c.a == 2 RETURN c) "+
        "FOR k IN UTUseIndexRangeBothInd FILTER k.a == 2 "+
        "  RETURN {A:A, B:B, C:C, K:k}";

      var result = AQL_EXPLAIN(query, { }, paramEnabledAllPlans);
      assertTrue(result.plans.length === 16, query);
      result = AQL_EXPLAIN(query, { }, paramAllAllPlans);
      assertTrue(result.plans.length === 16, query);
    }

  };
}

////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suite
////////////////////////////////////////////////////////////////////////////////

jsunity.run(optimizerRuleUseIndexRangeTester);

return jsunity.done();

// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:
<|endoftext|>


<commit_before>import { StyleSheet as baseStyleSheet } from 'aphrodite/no-important';
import store from 'kolibri.coreVue.vuex.store';
import theme from './theme';

const globalSelectorHandler = (selector, _, generateSubtreeStyles) => {
  if (selector[0] !== '*') {
    return null;
  }

  return generateSubtreeStyles(selector.slice(1));
};

const globalExtension = { selectorHandler: globalSelectorHandler };

const { StyleSheet, css } = baseStyleSheet.extend([globalExtension]);

function getter(value) {
  return theme[value]();
}

function generateGlobalStyles() {
  const htmlBodyStyles = {
    color: getter('$coreTextDefault'),
    backgroundColor: getter('$coreBgCanvas'),
  };

  const globalStyles = StyleSheet.create({
    globals: {
      '*html': htmlBodyStyles,
      '*body': htmlBodyStyles,
      '*:focus': getter('$coreOutline'),
      '*hr': {
        borderTop: `1px solid ${getter('$coreTextDisabled')}`,
      },
    },
  });

  // Have to do this to actually generate and inject the stylesheet
  // Return to have a value that will change when the dynamic styles change
  // This should be a cheap computation due to the caching that
  // Aphrodite is doing internally.
  return css(globalStyles.globals);
}

store.watch(generateGlobalStyles, generateGlobalStyles);
<commit_msg>rework globalDynamicStyles.js<commit_after>import { StyleSheet as baseStyleSheet } from 'aphrodite/no-important';
import store from 'kolibri.coreVue.vuex.store';
import theme from './theme';

const globalSelectorHandler = (selector, _, generateSubtreeStyles) => {
  if (selector[0] !== '*') {
    return null;
  }

  return generateSubtreeStyles(selector.slice(1));
};

const globalExtension = { selectorHandler: globalSelectorHandler };

const { StyleSheet, css } = baseStyleSheet.extend([globalExtension]);

function generateGlobalStyles() {
  const htmlBodyStyles = {
    color: theme.$themeTokens().text,
    backgroundColor: theme.$themeColors().palette.grey_v100,
  };

  const globalStyles = StyleSheet.create({
    globals: {
      '*html': htmlBodyStyles,
      '*body': htmlBodyStyles,
      '*:focus': theme.$coreOutline(),
      '*hr': {
        borderTop: `1px solid ${theme.$themeTokens().textDisabled}`,
      },
    },
  });

  // Have to do this to actually generate and inject the stylesheet
  // Return to have a value that will change when the dynamic styles change
  // This should be a cheap computation due to the caching that
  // Aphrodite is doing internally.
  return css(globalStyles.globals);
}

store.watch(generateGlobalStyles, generateGlobalStyles);
<|endoftext|>