diff options
| author | Misko Hevery | 2012-03-23 14:03:24 -0700 |
|---|---|---|
| committer | Misko Hevery | 2012-03-28 11:16:35 -0700 |
| commit | 2430f52bb97fa9d682e5f028c977c5bf94c5ec38 (patch) | |
| tree | e7529b741d70199f36d52090b430510bad07f233 /src/scenario/Scenario.js | |
| parent | 944098a4e0f753f06b40c73ca3e79991cec6c2e2 (diff) | |
| download | angular.js-2430f52bb97fa9d682e5f028c977c5bf94c5ec38.tar.bz2 | |
chore(module): move files around in preparation for more modules
Diffstat (limited to 'src/scenario/Scenario.js')
| -rw-r--r-- | src/scenario/Scenario.js | 417 |
1 files changed, 0 insertions, 417 deletions
diff --git a/src/scenario/Scenario.js b/src/scenario/Scenario.js deleted file mode 100644 index cd3c335f..00000000 --- a/src/scenario/Scenario.js +++ /dev/null @@ -1,417 +0,0 @@ -'use strict'; - - -/** - * Setup file for the Scenario. - * Must be first in the compilation/bootstrap list. - */ - -// Public namespace -angular.scenario = angular.scenario || {}; - -/** - * Defines a new output format. - * - * @param {string} name the name of the new output format - * @param {function()} fn function(context, runner) that generates the output - */ -angular.scenario.output = angular.scenario.output || function(name, fn) { - angular.scenario.output[name] = fn; -}; - -/** - * Defines a new DSL statement. If your factory function returns a Future - * it's returned, otherwise the result is assumed to be a map of functions - * for chaining. Chained functions are subject to the same rules. - * - * Note: All functions on the chain are bound to the chain scope so values - * set on "this" in your statement function are available in the chained - * functions. - * - * @param {string} name The name of the statement - * @param {function()} fn Factory function(), return a function for - * the statement. - */ -angular.scenario.dsl = angular.scenario.dsl || function(name, fn) { - angular.scenario.dsl[name] = function() { - function executeStatement(statement, args) { - var result = statement.apply(this, args); - if (angular.isFunction(result) || result instanceof angular.scenario.Future) - return result; - var self = this; - var chain = angular.extend({}, result); - angular.forEach(chain, function(value, name) { - if (angular.isFunction(value)) { - chain[name] = function() { - return executeStatement.call(self, value, arguments); - }; - } else { - chain[name] = value; - } - }); - return chain; - } - var statement = fn.apply(this, arguments); - return function() { - return executeStatement.call(this, statement, arguments); - }; - }; -}; - -/** - * Defines a new matcher for use with the expects() statement. The value - * this.actual (like in Jasmine) is available in your matcher to compare - * against. Your function should return a boolean. The future is automatically - * created for you. - * - * @param {string} name The name of the matcher - * @param {function()} fn The matching function(expected). - */ -angular.scenario.matcher = angular.scenario.matcher || function(name, fn) { - angular.scenario.matcher[name] = function(expected) { - var prefix = 'expect ' + this.future.name + ' '; - if (this.inverse) { - prefix += 'not '; - } - var self = this; - this.addFuture(prefix + name + ' ' + angular.toJson(expected), - function(done) { - var error; - self.actual = self.future.value; - if ((self.inverse && fn.call(self, expected)) || - (!self.inverse && !fn.call(self, expected))) { - error = 'expected ' + angular.toJson(expected) + - ' but was ' + angular.toJson(self.actual); - } - done(error); - }); - }; -}; - -/** - * Initialize the scenario runner and run ! - * - * Access global window and document object - * Access $runner through closure - * - * @param {Object=} config Config options - */ -angular.scenario.setUpAndRun = function(config) { - var href = window.location.href; - var body = _jQuery(document.body); - var output = []; - var objModel = new angular.scenario.ObjectModel($runner); - - if (config && config.scenario_output) { - output = config.scenario_output.split(','); - } - - angular.forEach(angular.scenario.output, function(fn, name) { - if (!output.length || indexOf(output,name) != -1) { - var context = body.append('<div></div>').find('div:last'); - context.attr('id', name); - fn.call({}, context, $runner, objModel); - } - }); - - if (!/^http/.test(href) && !/^https/.test(href)) { - body.append('<p id="system-error"></p>'); - body.find('#system-error').text( - 'Scenario runner must be run using http or https. The protocol ' + - href.split(':')[0] + ':// is not supported.' - ); - return; - } - - var appFrame = body.append('<div id="application"></div>').find('#application'); - var application = new angular.scenario.Application(appFrame); - - $runner.on('RunnerEnd', function() { - appFrame.css('display', 'none'); - appFrame.find('iframe').attr('src', 'about:blank'); - }); - - $runner.on('RunnerError', function(error) { - if (window.console) { - console.log(formatException(error)); - } else { - // Do something for IE - alert(error); - } - }); - - $runner.run(application); -}; - -/** - * Iterates through list with iterator function that must call the - * continueFunction to continute iterating. - * - * @param {Array} list list to iterate over - * @param {function()} iterator Callback function(value, continueFunction) - * @param {function()} done Callback function(error, result) called when - * iteration finishes or an error occurs. - */ -function asyncForEach(list, iterator, done) { - var i = 0; - function loop(error, index) { - if (index && index > i) { - i = index; - } - if (error || i >= list.length) { - done(error); - } else { - try { - iterator(list[i++], loop); - } catch (e) { - done(e); - } - } - } - loop(); -} - -/** - * Formats an exception into a string with the stack trace, but limits - * to a specific line length. - * - * @param {Object} error The exception to format, can be anything throwable - * @param {Number} maxStackLines Optional. max lines of the stack trace to include - * default is 5. - */ -function formatException(error, maxStackLines) { - maxStackLines = maxStackLines || 5; - var message = error.toString(); - if (error.stack) { - var stack = error.stack.split('\n'); - if (stack[0].indexOf(message) === -1) { - maxStackLines++; - stack.unshift(error.message); - } - message = stack.slice(0, maxStackLines).join('\n'); - } - return message; -} - -/** - * Returns a function that gets the file name and line number from a - * location in the stack if available based on the call site. - * - * Note: this returns another function because accessing .stack is very - * expensive in Chrome. - * - * @param {Number} offset Number of stack lines to skip - */ -function callerFile(offset) { - var error = new Error(); - - return function() { - var line = (error.stack || '').split('\n')[offset]; - - // Clean up the stack trace line - if (line) { - if (line.indexOf('@') !== -1) { - // Firefox - line = line.substring(line.indexOf('@')+1); - } else { - // Chrome - line = line.substring(line.indexOf('(')+1).replace(')', ''); - } - } - - return line || ''; - }; -} - -/** - * Triggers a browser event. Attempts to choose the right event if one is - * not specified. - * - * @param {Object} element Either a wrapped jQuery/jqLite node or a DOMElement - * @param {string} type Optional event type. - * @param {Array.<string>=} keys Optional list of pressed keys - * (valid values: 'alt', 'meta', 'shift', 'ctrl') - */ -function browserTrigger(element, type, keys) { - if (element && !element.nodeName) element = element[0]; - if (!element) return; - if (!type) { - type = { - 'text': 'change', - 'textarea': 'change', - 'hidden': 'change', - 'password': 'change', - 'button': 'click', - 'submit': 'click', - 'reset': 'click', - 'image': 'click', - 'checkbox': 'click', - 'radio': 'click', - 'select-one': 'change', - 'select-multiple': 'change' - }[lowercase(element.type)] || 'click'; - } - if (lowercase(nodeName_(element)) == 'option') { - element.parentNode.value = element.value; - element = element.parentNode; - type = 'change'; - } - - keys = keys || []; - function pressed(key) { - return indexOf(keys, key) !== -1; - } - - if (msie < 9) { - switch(element.type) { - case 'radio': - case 'checkbox': - element.checked = !element.checked; - break; - } - // WTF!!! Error: Unspecified error. - // Don't know why, but some elements when detached seem to be in inconsistent state and - // calling .fireEvent() on them will result in very unhelpful error (Error: Unspecified error) - // forcing the browser to compute the element position (by reading its CSS) - // puts the element in consistent state. - element.style.posLeft; - - // TODO(vojta): create event objects with pressed keys to get it working on IE<9 - var ret = element.fireEvent('on' + type); - if (lowercase(element.type) == 'submit') { - while(element) { - if (lowercase(element.nodeName) == 'form') { - element.fireEvent('onsubmit'); - break; - } - element = element.parentNode; - } - } - return ret; - } else { - var evnt = document.createEvent('MouseEvents'), - originalPreventDefault = evnt.preventDefault, - iframe = _jQuery('#application iframe')[0], - appWindow = iframe ? iframe.contentWindow : window, - fakeProcessDefault = true, - finalProcessDefault; - - // igor: temporary fix for https://bugzilla.mozilla.org/show_bug.cgi?id=684208 - appWindow.angular['ff-684208-preventDefault'] = false; - evnt.preventDefault = function() { - fakeProcessDefault = false; - return originalPreventDefault.apply(evnt, arguments); - }; - - evnt.initMouseEvent(type, true, true, window, 0, 0, 0, 0, 0, pressed('ctrl'), pressed('alt'), - pressed('shift'), pressed('meta'), 0, element); - - element.dispatchEvent(evnt); - finalProcessDefault = !(appWindow.angular['ff-684208-preventDefault'] || !fakeProcessDefault) - - delete appWindow.angular['ff-684208-preventDefault']; - - return finalProcessDefault; - } -} - -/** - * Don't use the jQuery trigger method since it works incorrectly. - * - * jQuery notifies listeners and then changes the state of a checkbox and - * does not create a real browser event. A real click changes the state of - * the checkbox and then notifies listeners. - * - * To work around this we instead use our own handler that fires a real event. - */ -(function(fn){ - var parentTrigger = fn.trigger; - fn.trigger = function(type) { - if (/(click|change|keydown|blur)/.test(type)) { - var processDefaults = []; - this.each(function(index, node) { - processDefaults.push(browserTrigger(node, type)); - }); - - // this is not compatible with jQuery - we return an array of returned values, - // so that scenario runner know whether JS code has preventDefault() of the event or not... - return processDefaults; - } - return parentTrigger.apply(this, arguments); - }; -})(_jQuery.fn); - -/** - * Finds all bindings with the substring match of name and returns an - * array of their values. - * - * @param {string} bindExp The name to match - * @return {Array.<string>} String of binding values - */ -_jQuery.fn.bindings = function(windowJquery, bindExp) { - var result = [], match, - bindSelector = '.ng-binding:visible'; - if (angular.isString(bindExp)) { - bindExp = bindExp.replace(/\s/g, ''); - match = function (actualExp) { - if (actualExp) { - actualExp = actualExp.replace(/\s/g, ''); - if (actualExp == bindExp) return true; - if (actualExp.indexOf(bindExp) == 0) { - return actualExp.charAt(bindExp.length) == '|'; - } - } - } - } else if (bindExp) { - match = function(actualExp) { - return actualExp && bindExp.exec(actualExp); - } - } else { - match = function(actualExp) { - return !!actualExp; - }; - } - var selection = this.find(bindSelector); - if (this.is(bindSelector)) { - selection = selection.add(this); - } - - function push(value) { - if (value == undefined) { - value = ''; - } else if (typeof value != 'string') { - value = angular.toJson(value); - } - result.push('' + value); - } - - selection.each(function() { - var element = windowJquery(this), - binding; - if (binding = element.data('$binding')) { - if (typeof binding == 'string') { - if (match(binding)) { - push(element.scope().$eval(binding)); - } - } else { - if (!angular.isArray(binding)) { - binding = [binding]; - } - for(var fns, j=0, jj=binding.length; j<jj; j++) { - fns = binding[j]; - if (fns.parts) { - fns = fns.parts; - } else { - fns = [fns]; - } - for (var scope, fn, i = 0, ii = fns.length; i < ii; i++) { - if(match((fn = fns[i]).exp)) { - push(fn(scope = scope || element.scope())); - } - } - } - } - } - }); - return result; -}; |
