support_center 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ define [
2
+ 'jquery',
3
+ 'support_center/form_component'
4
+ ], (
5
+ $,
6
+ FormComponent
7
+ ) ->
8
+ $ ->
9
+ $(document).on 'questionsModalLoaded', (ev, modalData) ->
10
+ FormComponent.attachTo modalData.container
@@ -0,0 +1,11 @@
1
+ // Generated by CoffeeScript 1.7.1
2
+ (function() {
3
+ define(['jquery', 'support_center/form_component'], function($, FormComponent) {
4
+ return $(function() {
5
+ return $(document).on('questionsModalLoaded', function(ev, modalData) {
6
+ return FormComponent.attachTo(modalData.container);
7
+ });
8
+ });
9
+ });
10
+
11
+ }).call(this);
@@ -0,0 +1,11 @@
1
+ require 'support_center/version'
2
+ require 'support_center/config'
3
+ require 'support_center/server'
4
+
5
+ module SupportCenter
6
+ class << self
7
+ def new
8
+ Server.new
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,43 @@
1
+ module SupportCenter
2
+ class Config
3
+ def initialize(data={})
4
+ @data = {}
5
+ update!(data)
6
+ end
7
+
8
+ def update!(data)
9
+ data.each do |key, value|
10
+ self[key] = value
11
+ end
12
+ end
13
+
14
+ def [](key)
15
+ @data[key.to_sym]
16
+ end
17
+
18
+ def []=(key, value)
19
+ if value.class == Hash
20
+ @data[key.to_sym] = Config.new(value)
21
+ else
22
+ @data[key.to_sym] = value
23
+ end
24
+ end
25
+
26
+ def method_missing(sym, *args)
27
+ if sym.to_s =~ /(.+)=$/
28
+ self[$1] = args.first
29
+ else
30
+ self[sym]
31
+ end
32
+ end
33
+ end
34
+
35
+ class << self
36
+ attr_accessor :config
37
+
38
+ def setup
39
+ self.config ||= Config.new
40
+ yield config
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,30 @@
1
+ require 'sinatra/base'
2
+ require 'zendesk_api'
3
+ require 'support_center/server/helpers'
4
+
5
+ module SupportCenter
6
+ class Server < Sinatra::Base
7
+ dir = File.dirname(File.expand_path(__FILE__))
8
+ set :views, "#{dir}/server/views"
9
+
10
+ helpers SupportCenter::Helpers
11
+
12
+ get '/support/tickets/new/?' do
13
+ slim :'new_ticket'
14
+ end
15
+
16
+ get '/support/tickets/:id/?' do
17
+ body support_client.tickets.find(id: params[:id]).to_json
18
+ end
19
+
20
+ post '/support/tickets/?' do
21
+ ticket = support_client.tickets.build params[:ticket]
22
+ if ticket.save
23
+ {ticket:ticket.id}.to_json
24
+ else
25
+ status 422
26
+ {errors:ticket.errors}.to_json
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,24 @@
1
+ module SupportCenter
2
+ module Helpers
3
+ def support_client
4
+ @support_client ||= ZendeskAPI::Client.new do |config|
5
+ settings = SupportCenter.config.config_service_adapter['support_center']
6
+
7
+ config.url = settings['url']
8
+ config.username = settings['username']
9
+ config.password = settings['password']
10
+ config.retry = true
11
+ end
12
+ end
13
+
14
+ def see_more_faqs_link
15
+ if params[:faq_link]
16
+ "<a class='all_faq_link' href=#{params[:faq_link]}>See All FAQs ...</a>"
17
+ end
18
+ end
19
+
20
+ def field_ids
21
+ @field_ids ||= SupportCenter.config.custom_ticket_fields
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,80 @@
1
+ #feedback_pop_head
2
+ h3 Submit Questions or Feedback
3
+ a.icon_close.sprite.close
4
+ #faqlist
5
+ h4 Oops! The popular FAQ list is currently unavailable.
6
+ == see_more_faqs_link
7
+ #feedback_form_holder
8
+ ul.global_tabs
9
+ li
10
+ a#feedback_form.ld_tab.tab_active href="javascript: void(0);" Send Feedback
11
+ li
12
+ a#questions_form.ld_tab href="javascript: void(0);"Ask A Question
13
+ #feedback_form_tab.feedback_popup_tab.active_tab
14
+ .padding-box
15
+ span.error_msg.hidden Missing Required Field
16
+ form id="feedback_form_element"
17
+ p
18
+ label for='feedback_subject'
19
+ | Your idea or suggestion:
20
+ span.required *
21
+ input#feedback_subject type='text' name='ticket[subject]'
22
+ p
23
+ label for='feedback_description'
24
+ | Describe your idea or how we can improve your experience:
25
+ span.required *
26
+ textarea#feedback_description name='ticket[description]' rows="7"
27
+ p
28
+ label for='feedback_name'
29
+ | Name:
30
+ span.required *
31
+ input#feedback_name type='text' name='ticket[requester][name]'
32
+ p
33
+ label for='feedback_email'
34
+ | Email:
35
+ span.required *
36
+ input#feedback_email type='text' name='ticket[requester][email]'
37
+ input#feedback_browser type='hidden' name="ticket[custom_fields][#{field_ids[:browser]}]"
38
+ input#feedback_current_url type='hidden' name="ticket[custom_fields][#{field_ids[:url]}]"
39
+ input type='hidden' name='ticket[tags]' value='feedback'
40
+ span.spinner.hidden
41
+ input class="button btn_large" name="commit" type="submit" value="Submit"
42
+ .clr
43
+ #thanks_feedback_tab.hidden
44
+ span Thank You for your feedback!
45
+ p We will review your feedback shortly.
46
+ .clr
47
+ #questions_form_tab.feedback_popup_tab
48
+ .padding-box
49
+ span.error_msg.hidden Missing Required Field
50
+ form#questions_form_element
51
+ p
52
+ label for='question_subject'
53
+ | Your question:
54
+ span.required *
55
+ input#question_subject type='text' name='ticket[subject]'
56
+ p
57
+ label for='question_description'
58
+ | Describe your question, please provide details:
59
+ span.required *
60
+ textarea#question_description name='ticket[description]' rows="7"
61
+ p
62
+ label for='question_name'
63
+ | Name:
64
+ span.required *
65
+ input#question_name type='text' name='ticket[requester][name]'
66
+ p
67
+ label for='question_email'
68
+ | Email:
69
+ span.required *
70
+ input#question_email type='text' name='ticket[requester][email]'
71
+ input#question_browser type='hidden' name="ticket[custom_fields][#{field_ids[:browser]}]"
72
+ input#question_current_url type='hidden' name="ticket[custom_fields][#{field_ids[:url]}]"
73
+ input type='hidden' name='ticket[tags]' value='question'
74
+ span.spinner.hidden
75
+ input class="button btn_large" name="commit" type="submit" value="Submit"
76
+ .clr
77
+ #thanks_questions_tab.hidden
78
+ span Thank You for your question!
79
+ p We will review your question shortly and try to get back to you.
80
+ .clr
@@ -0,0 +1,3 @@
1
+ module SupportCenter
2
+ VERSION = '0.1.5'
3
+ end
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "support_center",
3
+ "version": "0.0.1",
4
+ "description": "Support Center",
5
+ "homepage": "https://github.com/primedia/support_center",
6
+ "jam": {
7
+ "dependencies": {
8
+ "jquery": null,
9
+ "underscore":null,
10
+ "jquery.cookie": null
11
+ },
12
+ "main": "support_center.js",
13
+ "include": [
14
+ "support_center.js"
15
+ ]
16
+ },
17
+ "author": {
18
+ "name": "Primedia"
19
+ },
20
+ "repositories": [
21
+ {
22
+ "type": "git",
23
+ "url": "https://github.com/primedia/support_center.git"
24
+ }
25
+ ],
26
+ "github": "https://github.com/primedia/support_center.git"
27
+ }
@@ -0,0 +1,20 @@
1
+
2
+ describe "FormComponent", ->
3
+
4
+ formComponent = null
5
+
6
+ beforeEach ->
7
+ ready = false
8
+
9
+ require ['form_component', 'jasmine-jquery'], (_formComponent) ->
10
+ formComponent = _formComponent
11
+ ready = true
12
+
13
+ waitsFor ->
14
+ return ready
15
+
16
+
17
+ describe "initialize", ->
18
+
19
+ it "is defined", ->
20
+ expect(formComponent).toBeDefined()
File without changes
@@ -0,0 +1,19 @@
1
+ requirejs.config({
2
+ waitSeconds: 120,
3
+ baseUrl: "js/support_center",
4
+ paths: {
5
+ "jasmine-jquery": "/vendor/js/jasmine-jquery",
6
+ "jasmine-flight": "/vendor/js/jasmine-flight",
7
+ "jquery": "/vendor/bower/jquery/jquery",
8
+ "es5-shim": "/vendor/bower/es5-shim/es5-shim",
9
+ "es5-sham": "/vendor/bower/es5-shim/es5-sham",
10
+ "flight/lib/component": "/vendor/bower/flight/lib/component",
11
+ "flight/lib/advice": "/vendor/bower/flight/lib/advice",
12
+ "flight/lib/utils": "/vendor/bower/flight/lib/utils",
13
+ "flight/lib/registry": "/vendor/bower/flight/lib/registry",
14
+ "flight/lib/compose": "/vendor/bower/flight/lib/compose",
15
+ "flight/lib/logger": "/vendor/bower/flight/lib/logger",
16
+ "flight/tools/debug": "/vendor/bower/flight/tools/debug"
17
+ }
18
+
19
+ });
@@ -0,0 +1,24 @@
1
+ // Generated by CoffeeScript 1.7.1
2
+ (function() {
3
+ describe("FormComponent", function() {
4
+ var formComponent;
5
+ formComponent = null;
6
+ beforeEach(function() {
7
+ var ready;
8
+ ready = false;
9
+ require(['form_component', 'jasmine-jquery'], function(_formComponent) {
10
+ formComponent = _formComponent;
11
+ return ready = true;
12
+ });
13
+ return waitsFor(function() {
14
+ return ready;
15
+ });
16
+ });
17
+ return describe("initialize", function() {
18
+ return it("is defined", function() {
19
+ return expect(formComponent).toBeDefined();
20
+ });
21
+ });
22
+ });
23
+
24
+ }).call(this);
@@ -0,0 +1,63 @@
1
+ # src_files
2
+ #
3
+ # Return an array of filepaths relative to src_dir to include before jasmine specs.
4
+ # Default: []
5
+ #
6
+ # EXAMPLE:
7
+ #
8
+ # src_files:
9
+ # - lib/source1.js
10
+ # - lib/source2.js
11
+ # - dist/**/*.js
12
+ #
13
+ src_files:
14
+ - vendor/bower/requirejs/require.js
15
+ - spec/javascripts/config/bootstrap.js
16
+
17
+ # helpers
18
+ #
19
+ # Return an array of filepaths relative to spec_dir to include before jasmine specs.
20
+ # Default: ["helpers/**/*.js"]
21
+ #
22
+ # EXAMPLE:
23
+ #
24
+ # helpers:
25
+ # - helpers/**/*.js
26
+ #
27
+ helpers:
28
+ - helpers/**/*.js
29
+
30
+ # spec_files
31
+ #
32
+ # Return an array of filepaths relative to spec_dir to include.
33
+ # Default: ["**/*[sS]pec.js"]
34
+ #
35
+ # EXAMPLE:
36
+ #
37
+ # spec_files:
38
+ # - **/*[sS]pec.js
39
+ #
40
+ spec_files:
41
+ - '**/*[sS]pec.js'
42
+
43
+ # src_dir
44
+ #
45
+ # Source directory path. Your src_files must be returned relative to this path. Will use root if left blank.
46
+ # Default: project root
47
+ #
48
+ # EXAMPLE:
49
+ #
50
+ # src_dir: public
51
+ #
52
+ src_dir:
53
+
54
+ # spec_dir
55
+ #
56
+ # Spec directory path. Your spec_files must be returned relative to this path.
57
+ # Default: spec/javascripts
58
+ #
59
+ # EXAMPLE:
60
+ #
61
+ # spec_dir: spec/javascripts
62
+ #
63
+ spec_dir: spec/javascripts
@@ -0,0 +1,5 @@
1
+ // Generated by CoffeeScript 1.7.1
2
+ (function() {
3
+
4
+
5
+ }).call(this);
@@ -0,0 +1,11 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+
4
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
6
+ require 'rspec'
7
+ require 'support_center'
8
+
9
+ # Requires supporting files with custom matchers and macros, etc,
10
+ # in ./support/ and its subdirectories.
11
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
File without changes
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/support_center/version', __FILE__)
3
+ require 'date'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.authors = ["Joe Dursun", "Matt Perryman", "RentPath Team"]
7
+ gem.email = ["jdursun@rentpath.com", "mperryman@rentpath.com"]
8
+ gem.homepage = 'https://github.com/primedia/support_center'
9
+ gem.description = 'This gem provides an interface to the Zendesk API'
10
+ gem.summary = "Rack middleware to interact with Zendesk API"
11
+ gem.date = Date.today.to_s
12
+ gem.executables = []
13
+ gem.files = `git ls-files | grep -v myapp`.split("\n")
14
+ gem.test_files = `git ls-files -- test/*`.split("\n")
15
+ gem.name = "support_center"
16
+ gem.require_paths = ["lib"]
17
+ gem.version = SupportCenter::VERSION
18
+ gem.required_ruby_version = '>= 1.9'
19
+ gem.add_dependency 'zendesk_api', '~> 1.3'
20
+ gem.add_dependency 'sinatra', '>= 1.2.0'
21
+ gem.add_dependency 'slim'
22
+ end
@@ -0,0 +1,485 @@
1
+ /**
2
+ * This version of the Jasmine Flight framework is a fork of the production version
3
+ * The call to instantiate a new Component has been modified to pass the node.
4
+ * Searck for 'FORK' below to find the differences test
5
+ */
6
+
7
+ /**
8
+ * Copyright 2013, Twitter Inc. and other contributors
9
+ * Licensed under the MIT License
10
+ */
11
+
12
+ (function (root) {
13
+ 'use strict';
14
+
15
+ jasmine.flight = {};
16
+
17
+ /**
18
+ * Wrapper for describe. Load component before each test.
19
+ *
20
+ * @param componentPath
21
+ * @param specDefinitions
22
+ */
23
+
24
+ root.describeComponent = function (componentPath, specDefinitions) {
25
+ jasmine.getEnv().describeComponent(componentPath, specDefinitions);
26
+ };
27
+
28
+ root.ddescribeComponent = function (componentPath, specDefinitions) {
29
+ jasmine.getEnv().ddescribeComponent(componentPath, specDefinitions);
30
+ };
31
+
32
+ var describeComponentFactory = function (componentPath, specDefinitions) {
33
+ return function () {
34
+ beforeEach(function () {
35
+ this.Component = this.component = this.$node = null;
36
+
37
+ var requireCallback = function (registry, Component) {
38
+ registry.reset();
39
+ this.Component = Component;
40
+ }.bind(this);
41
+
42
+ require(['flight/lib/registry', componentPath], requireCallback);
43
+
44
+ waitsFor(function () {
45
+ return this.Component !== null;
46
+ }.bind(this));
47
+ });
48
+
49
+ afterEach(function () {
50
+ if (this.$node) {
51
+ this.$node.remove();
52
+ this.$node = null;
53
+ }
54
+
55
+ var requireCallback = function (defineComponent) {
56
+ if (this.component) {
57
+ this.component = null;
58
+ }
59
+
60
+ this.Component = null;
61
+ defineComponent.teardownAll();
62
+ }.bind(this);
63
+
64
+ require(['flight/lib/component'], requireCallback);
65
+
66
+ waitsFor(function () {
67
+ return this.Component === null;
68
+ }.bind(this));
69
+ });
70
+
71
+ specDefinitions.apply(this);
72
+ };
73
+ };
74
+
75
+ jasmine.Env.prototype.describeComponent = function (componentPath, specDefinitions) {
76
+ describe(componentPath, describeComponentFactory(componentPath, specDefinitions));
77
+ };
78
+
79
+ jasmine.Env.prototype.ddescribeComponent = function (componentPath, specDefinitions) {
80
+ ddescribe(componentPath, describeComponentFactory(componentPath, specDefinitions));
81
+ };
82
+
83
+ /**
84
+ * Wrapper for describe. Load mixin before each test.
85
+ *
86
+ * @param mixinPath
87
+ * @param specDefinitions
88
+ */
89
+
90
+ root.describeMixin = function (mixinPath, specDefinitions) {
91
+ jasmine.getEnv().describeMixin(mixinPath, specDefinitions);
92
+ };
93
+
94
+ root.ddescribeMixin = function (mixinPath, specDefinitions) {
95
+ jasmine.getEnv().ddescribeMixin(mixinPath, specDefinitions);
96
+ };
97
+
98
+ var describeMixinFactory = function (mixinPath, specDefinitions) {
99
+ return function () {
100
+ beforeEach(function () {
101
+ this.Component = this.component = this.$node = null;
102
+
103
+ var requireCallback = function (registry, defineComponent, Mixin) {
104
+ registry.reset();
105
+ this.Component = defineComponent(function () {}, Mixin);
106
+ }.bind(this);
107
+
108
+ require(['flight/lib/registry', 'flight/lib/component', mixinPath], requireCallback);
109
+
110
+ waitsFor(function () {
111
+ return this.Component !== null;
112
+ });
113
+ });
114
+
115
+ afterEach(function () {
116
+ if (this.$node) {
117
+ this.$node.remove();
118
+ this.$node = null;
119
+ }
120
+
121
+ var requireCallback = function (defineComponent) {
122
+ if (this.component) {
123
+ this.component = null;
124
+ }
125
+
126
+ this.Component = null;
127
+ defineComponent.teardownAll();
128
+ }.bind(this);
129
+
130
+ require(['flight/lib/component'], requireCallback);
131
+
132
+ waitsFor(function () {
133
+ return this.Component === null;
134
+ }.bind(this));
135
+ });
136
+
137
+ specDefinitions.apply(this);
138
+ };
139
+ };
140
+
141
+ jasmine.Env.prototype.describeMixin = function (mixinPath, specDefinitions) {
142
+ describe(mixinPath, describeMixinFactory(mixinPath, specDefinitions));
143
+ };
144
+
145
+ jasmine.Env.prototype.ddescribeMixin = function (mixinPath, specDefinitions) {
146
+ ddescribe(mixinPath, describeMixinFactory(mixinPath, specDefinitions));
147
+ };
148
+
149
+ /**
150
+ * Wrapper for describe. Load module before each test.
151
+ *
152
+ * @param modulePath
153
+ * @param specDefinitions
154
+ */
155
+
156
+ root.describeModule = function (modulePath, specDefinitions) {
157
+ return jasmine.getEnv().describeModule(modulePath, specDefinitions);
158
+ };
159
+
160
+ jasmine.Env.prototype.describeModule = function (modulePath, specDefinitions) {
161
+ describe(modulePath, function () {
162
+ beforeEach(function () {
163
+ this.module = null;
164
+
165
+ var requireCallback = function (module) {
166
+ this.module = module;
167
+ }.bind(this);
168
+
169
+ require([modulePath], requireCallback);
170
+
171
+ waitsFor(function () {
172
+ return this.module !== null;
173
+ });
174
+ });
175
+
176
+ specDefinitions.apply(this);
177
+ });
178
+ };
179
+
180
+ /**
181
+ * Create root node and initialize component. Fixture should be html string
182
+ * or jQuery object.
183
+ *
184
+ * @param fixture {String} (Optional)
185
+ * @param options {Options} (Optional)
186
+ */
187
+
188
+ root.setupComponent = function (fixture, options) {
189
+ jasmine.getEnv().currentSpec.setupComponent(fixture, options);
190
+ };
191
+
192
+ jasmine.Spec.prototype.setupComponent = function (fixture, options) {
193
+ if (this.component) {
194
+ this.component.teardown();
195
+ this.$node.remove();
196
+ }
197
+
198
+ if (fixture instanceof jQuery || typeof fixture === 'string') {
199
+ this.$node = $(fixture).addClass('component-root');
200
+ } else {
201
+ this.$node = $('<div class="component-root" />');
202
+ options = fixture;
203
+ fixture = null;
204
+ }
205
+
206
+ $('body').append(this.$node);
207
+
208
+ options = options === undefined ? {} : options;
209
+
210
+ // FORK: Component could not be initialized without a node
211
+ // this.component = (new this.Component()).initialize(this.$node, options);
212
+ this.component = new this.Component(this.$node, options);
213
+ };
214
+
215
+
216
+ (function (namespace) {
217
+ var eventsData = {
218
+ spiedEvents: {},
219
+ handlers: []
220
+ };
221
+
222
+ namespace.formatElement = function ($element) {
223
+ var limit = 200;
224
+ var output = '';
225
+
226
+ if ($element instanceof jQuery) {
227
+ output = jasmine.JQuery.elementToString($element);
228
+ if (output.length > limit) {
229
+ output = output.slice(0, 200) + '...';
230
+ }
231
+ } else {
232
+ //$element should always be a jQuery object
233
+ output = 'element is not a jQuery object';
234
+ }
235
+
236
+ return output;
237
+ };
238
+
239
+ namespace.compareColors = function (color1, color2) {
240
+ if (color1.charAt(0) === color2.charAt(0)) {
241
+ return color1 === color2;
242
+ } else {
243
+ return namespace.hex2rgb(color1) === namespace.hex2rgb(color2);
244
+ }
245
+ };
246
+
247
+ namespace.hex2rgb = function (colorString) {
248
+ if (colorString.charAt(0) !== '#') return colorString;
249
+ // note: hexStr should be #rrggbb
250
+ var hex = parseInt(colorString.substring(1), 16);
251
+ var r = (hex & 0xff0000) >> 16;
252
+ var g = (hex & 0x00ff00) >> 8;
253
+ var b = hex & 0x0000ff;
254
+ return 'rgb(' + r + ', ' + g + ', ' + b + ')';
255
+ };
256
+
257
+ namespace.events = {
258
+ spyOn: function (selector, eventName) {
259
+ eventsData.spiedEvents[[selector, eventName]] = {
260
+ callCount: 0,
261
+ calls: [],
262
+ mostRecentCall: {},
263
+ name: eventName
264
+ };
265
+
266
+ var handler = function (e, data) {
267
+ var call = {
268
+ event: e,
269
+ args: jasmine.util.argsToArray(arguments),
270
+ data: data
271
+ };
272
+ eventsData.spiedEvents[[selector, eventName]].callCount++;
273
+ eventsData.spiedEvents[[selector, eventName]].calls.push(call);
274
+ eventsData.spiedEvents[[selector, eventName]].mostRecentCall = call;
275
+ };
276
+
277
+ jQuery(selector).on(eventName, handler);
278
+ eventsData.handlers.push([selector, eventName, handler]);
279
+ return eventsData.spiedEvents[[selector, eventName]];
280
+ },
281
+
282
+ eventArgs: function (selector, eventName, expectedArg) {
283
+ var actualArgs = eventsData.spiedEvents[[selector, eventName]].mostRecentCall.args;
284
+
285
+ if (!actualArgs) {
286
+ throw 'No event spy found on ' + eventName + '. Try adding a call to spyOnEvent or make sure that the selector the event is triggered on and the selector being spied on are correct.';
287
+ }
288
+
289
+ // remove extra event metadata if it is not tested for
290
+ if ((actualArgs.length === 2) && typeof actualArgs[1] === 'object' &&
291
+ expectedArg && !expectedArg.scribeContext && !expectedArg.sourceEventData && !expectedArg.scribeData) {
292
+ actualArgs[1] = $.extend({}, actualArgs[1]);
293
+ delete actualArgs[1].sourceEventData;
294
+ delete actualArgs[1].scribeContext;
295
+ delete actualArgs[1].scribeData;
296
+ }
297
+
298
+ return actualArgs;
299
+ },
300
+
301
+ wasTriggered: function (selector, event) {
302
+ var spiedEvent = eventsData.spiedEvents[[selector, event]];
303
+ return spiedEvent && spiedEvent.callCount > 0;
304
+ },
305
+
306
+ wasTriggeredWith: function (selector, eventName, expectedArg, env) {
307
+ var actualArgs = jasmine.flight.events.eventArgs(selector, eventName, expectedArg);
308
+ return actualArgs && env.contains_(actualArgs, expectedArg);
309
+ },
310
+
311
+ wasTriggeredWithData: function (selector, eventName, expectedArg, env) {
312
+ var actualArgs = jasmine.flight.events.eventArgs(selector, eventName, expectedArg);
313
+ var valid;
314
+
315
+ if (actualArgs) {
316
+ valid = false;
317
+ for (var i = 0; i < actualArgs.length; i++) {
318
+ if (jasmine.flight.validateHash(expectedArg, actualArgs[i])) {
319
+ return true;
320
+ }
321
+ }
322
+ return valid;
323
+ }
324
+
325
+ return false;
326
+ },
327
+
328
+ cleanUp: function () {
329
+ eventsData.spiedEvents = {};
330
+ // unbind all handlers
331
+ for (var i = 0; i < eventsData.handlers.length; i++) {
332
+ jQuery(eventsData.handlers[i][0]).off(eventsData.handlers[i][1], eventsData.handlers[i][2]);
333
+ }
334
+ eventsData.handlers = [];
335
+ }
336
+ };
337
+
338
+ namespace.validateHash = function (a, b, intersection) {
339
+ var validHash;
340
+ for (var field in a) {
341
+ if ((typeof a[field] === 'object') && (typeof b[field] === 'object')) {
342
+ validHash = a[field] === b[field] || jasmine.flight.validateHash(a[field], b[field]);
343
+ } else if (intersection && (typeof a[field] === 'undefined' || typeof b[field] === 'undefined')) {
344
+ validHash = true;
345
+ } else {
346
+ validHash = (a[field] === b[field]);
347
+ }
348
+ if (!validHash) {
349
+ break;
350
+ }
351
+ }
352
+ return validHash;
353
+ };
354
+ })(jasmine.flight);
355
+
356
+ beforeEach(function () {
357
+ this.addMatchers({
358
+ toHaveBeenTriggeredOn: function () {
359
+ var selector = arguments[0];
360
+ var eventName = typeof this.actual === 'string' ? this.actual : this.actual.name;
361
+ var wasTriggered = jasmine.flight.events.wasTriggered(selector, eventName);
362
+
363
+ this.message = function () {
364
+ var $pp = function (obj) {
365
+ var description;
366
+ var attr;
367
+
368
+ if (!(obj instanceof jQuery)) {
369
+ obj = $(obj);
370
+ }
371
+
372
+ description = [
373
+ obj.get(0).nodeName
374
+ ];
375
+
376
+ attr = obj.get(0).attributes || [];
377
+
378
+ for (var x = 0; x < attr.length; x++) {
379
+ description.push(attr[x].name + '="' + attr[x].value + '"');
380
+ }
381
+
382
+ return '<' + description.join(' ') + '>';
383
+ };
384
+
385
+ if (wasTriggered) {
386
+ return [
387
+ '<div class="value-mismatch">Expected event ' + eventName + ' to have been triggered on' + selector,
388
+ '<div class="value-mismatch">Expected event ' + eventName + ' not to have been triggered on' + selector
389
+ ];
390
+ } else {
391
+ return [
392
+ 'Expected event ' + eventName + ' to have been triggered on ' + $pp(selector),
393
+ 'Expected event ' + eventName + ' not to have been triggered on ' + $pp(selector)
394
+ ];
395
+ }
396
+ };
397
+
398
+ return wasTriggered;
399
+ },
400
+
401
+ toHaveBeenTriggeredOnAndWith: function () {
402
+ var selector = arguments[0];
403
+ var expectedArg = arguments[1];
404
+ var exactMatch = !arguments[2];
405
+ var eventName = typeof this.actual === 'string' ? this.actual : this.actual.name;
406
+ var wasTriggered = jasmine.flight.events.wasTriggered(selector, eventName);
407
+
408
+ this.message = function () {
409
+ var $pp = function (obj) {
410
+ var description;
411
+ var attr;
412
+
413
+ if (!(obj instanceof jQuery)) {
414
+ obj = $(obj);
415
+ }
416
+
417
+ description = [
418
+ obj.get(0).nodeName
419
+ ];
420
+
421
+ attr = obj.get(0).attributes || [];
422
+
423
+ for (var x = 0; x < attr.length; x++) {
424
+ description.push(attr[x].name + '="' + attr[x].value + '"');
425
+ }
426
+
427
+ return '<' + description.join(' ') + '>';
428
+ };
429
+
430
+ if (wasTriggered) {
431
+ var actualArg = jasmine.flight.events.eventArgs(selector, eventName, expectedArg)[1];
432
+ return [
433
+ '<div class="value-mismatch">Expected event ' + eventName + ' to have been triggered on' + selector,
434
+ '<div class="value-mismatch">Expected event ' + eventName + ' not to have been triggered on' + selector
435
+ ];
436
+ } else {
437
+ return [
438
+ 'Expected event ' + eventName + ' to have been triggered on ' + $pp(selector),
439
+ 'Expected event ' + eventName + ' not to have been triggered on ' + $pp(selector)
440
+ ];
441
+ }
442
+ };
443
+
444
+ if (!wasTriggered) {
445
+ return false;
446
+ }
447
+
448
+ if (exactMatch) {
449
+ return jasmine.flight.events.wasTriggeredWith(selector, eventName, expectedArg, this.env);
450
+ } else {
451
+ return jasmine.flight.events.wasTriggeredWithData(selector, eventName, expectedArg, this.env);
452
+ }
453
+ },
454
+
455
+ toHaveCss: function (prop, val) {
456
+ var result;
457
+ if (val instanceof RegExp) {
458
+ result = val.test(this.actual.css(prop));
459
+ } else if (prop.match(/color/)) {
460
+ //IE returns colors as hex strings; other browsers return rgb(r, g, b) strings
461
+ result = jasmine.flight.compareColors(this.actual.css(prop), val);
462
+ } else {
463
+ result = this.actual.css(prop) === val;
464
+ //sometimes .css() returns strings when it should return numbers
465
+ if (!result && typeof val === 'number') {
466
+ result = parseFloat(this.actual.css(prop), 10) === val;
467
+ }
468
+ }
469
+
470
+ this.actual = jasmine.flight.formatElement(this.actual);
471
+ return result;
472
+ }
473
+ });
474
+ });
475
+
476
+ root.spyOnEvent = function (selector, eventName) {
477
+ jasmine.JQuery.events.spyOn(selector, eventName);
478
+ return jasmine.flight.events.spyOn(selector, eventName);
479
+ };
480
+
481
+ afterEach(function () {
482
+ jasmine.flight.events.cleanUp();
483
+ });
484
+
485
+ }(this));