e9_vendors 0.0.1 → 0.0.2

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.
@@ -23,7 +23,10 @@ class E9Vendors::VendorMembersController < Admin::ResourceController
23
23
  end
24
24
 
25
25
  def update
26
- update! { collection_path }
26
+ update! do |success, failure|
27
+ success.html { redirect_to collection_path }
28
+ failure.html { render :edit }
29
+ end
27
30
  end
28
31
 
29
32
  def destroy
@@ -7,7 +7,7 @@ class VendorMemberDecorator < VendorsDecorator
7
7
  :address_1 => model.address_1,
8
8
  :address_2 => model.address_2,
9
9
  :admin_notes => model.admin_notes,
10
- :categories => VendorCategoryDecorator.decorate(VendorCategory.widget_visible),
10
+ :categories => VendorCategoryDecorator.decorate(VendorCategory.widget_visible.ordered),
11
11
  :city => model.city,
12
12
  :contact_email => model.contact_email,
13
13
  :contact_full_name => model.contact_full_name,
@@ -19,9 +19,9 @@ class VendorMemberDecorator < VendorsDecorator
19
19
  :state => model.state,
20
20
  :vendors => VendorProxyDecorator.decorate(model.vendor_proxies.widget_visible),
21
21
  :website => model.website,
22
- :widget_form_text => config_render(:vendorboon_widget_form_text),
23
- :widget_form_title => config_render(:vendorboon_widget_form_title),
24
- :widget_title => config_render(:vendorboon_widget_title),
22
+ :widget_form_text => config_render(:e9_vendors_widget_form_text),
23
+ :widget_form_title => config_render(:e9_vendors_widget_form_title),
24
+ :widget_title => config_render(:e9_vendors_widget_title),
25
25
  :zipcode => model.zipcode
26
26
  }
27
27
  end
@@ -6,9 +6,11 @@ class VendorCategory < ActiveRecord::Base
6
6
  validates :name, :presence => true
7
7
 
8
8
  scope :widget_visible, lambda {
9
- joins(:vendors => :vendor_proxies) & VendorProxy.widget_visible
9
+ joins(:vendors => :vendor_proxies).group('vendor_categories.id') & VendorProxy.widget_visible
10
10
  }
11
11
 
12
+ scope :ordered, lambda { order(:position) }
13
+
12
14
  # On updates, all members are touched, ensuring that widget JSON requests
13
15
  # for the associations are pulling the most recent information
14
16
  after_save :on => :update do
@@ -5,11 +5,14 @@
5
5
  %legend
6
6
  = help_label(:widget_settings, :e9_vendors_widget_settings, :key => :e9_vendors_widget_help, :header => 'Variable Help')
7
7
  .field
8
- = f.label :e9_vendors_widget_title, nil, :class => :req
8
+ = f.label :e9_vendors_widget_title
9
9
  = f.text_field :e9_vendors_widget_title
10
10
  .field
11
- = f.label :e9_vendors_widget_form_title, nil, :class => :req
11
+ = f.label :e9_vendors_widget_form_title
12
12
  = f.text_field :e9_vendors_widget_form_title
13
+ .field
14
+ = f.label :e9_vendors_widget_form_text
15
+ = f.text_area :e9_vendors_widget_form_text
13
16
  - if e9_user?
14
17
  .field
15
18
  = f.label :e9_vendors_logo_size, nil, :class => :req
@@ -11,16 +11,7 @@ en:
11
11
  vendor:
12
12
  vendor_category: Category
13
13
  discount_percentage: Default Member Discount
14
- settings:
15
- e9_vendors_email_to: Email To
16
- e9_vendors_email_from: Email From
17
- e9_vendors_email_subject: Email Subject
18
- e9_vendors_email_intro: Email Introduction
19
- e9_vendors_widget_title: Widget Title
20
- e9_vendors_widget_form_title: Widget Form Title
21
- e9_vendors_widget_form_text: Form Introduction
22
- e9_vendors_widget_settings: Widget Settings
23
- e9_vendors_widget_help: |
14
+ interpolation_instructions: |
24
15
  <h3>Variables usable in short and long descriptions:</h3>
25
16
  <ul>
26
17
  <li>&#123;&#123;member_name&#125;&#125;</li>
@@ -35,7 +26,21 @@ en:
35
26
  <li>&#123;&#123;vendor_sales_phone&#125;&#125;</li>
36
27
  <li>&#123;&#123;vendor_sales_title&#125;&#125;</li>
37
28
  </ul>
38
-
29
+ settings:
30
+ e9_vendors_email_to: Email To
31
+ e9_vendors_email_from: Email From
32
+ e9_vendors_email_subject: Email Subject
33
+ e9_vendors_email_intro: Email Introduction
34
+ e9_vendors_widget_title: Widget Title
35
+ e9_vendors_widget_form_title: Widget Subtitle
36
+ e9_vendors_widget_form_text: Widget Description
37
+ e9_vendors_widget_settings: Widget Settings
38
+ e9_vendors_widget_help: |
39
+ <h3>Variables usable in all fields:</h3>
40
+ <ul>
41
+ <li>&#123;&#123;member_name&#125;&#125;</li>
42
+ <li>&#123;&#123;member_nickname&#125;&#125;</li>
43
+ </ul>
39
44
  e9:
40
45
  e9_vendors:
41
46
  vendor_members:
@@ -53,9 +58,3 @@ en:
53
58
  settings:
54
59
  index_title: Vendors Settings
55
60
  vendorboon_widget_settings_legend: Widget Settings
56
- widget_interpolation_instructions: |
57
- <h3>Variables usable in all fields:</h3>
58
- <ul>
59
- <li>&#123;&#123;member_name&#125;&#125;</li>
60
- <li>&#123;&#123;member_nickname&#125;&#125;</li>
61
- </ul>
@@ -4,6 +4,8 @@ Rails.application.routes.draw do
4
4
  admin_path= "admin/#{base_path}"
5
5
 
6
6
  scope :path => admin_path, :module => :e9_vendors do
7
+ get :root, :to => redirect("/#{admin_path}/vendors")
8
+
7
9
  resource :settings, :only => [:show, :update], :as => :e9_vendors_settings
8
10
 
9
11
  resources :vendor_categories, :path => :categories do
@@ -34,5 +36,5 @@ Rails.application.routes.draw do
34
36
  end
35
37
  end
36
38
 
37
- get "/#{base_path}/members/:id", :as => :vendor_member, :to => 'e9_vendors/vendor_members#show'
39
+ get "/#{base_path}/members/:id", :as => :public_vendor_member, :to => 'e9_vendors/vendor_members#show'
38
40
  end
@@ -1,3 +1,3 @@
1
1
  module E9Vendors
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -23,7 +23,7 @@ module E9Vendors
23
23
  end
24
24
 
25
25
  def copy_files
26
- copy_file 'javascript.js', 'public/javascripts/e9_vendors.js'
26
+ directory 'javascripts', 'app/javascripts'
27
27
  directory 'stylesheets', 'app/stylesheets'
28
28
  end
29
29
  end
@@ -0,0 +1,839 @@
1
+ /*!
2
+ * e9Digital vendor widget - http://www.e9digital.com
3
+ * Copyright (C) 2011 e9Digital
4
+ * Author: Travis Cox
5
+ *
6
+ * For the documented source see http://www.e9digital.com/javascripts/vwidget.js
7
+ *
8
+ * Basic Usage:
9
+ <script type="text/javascript" src="http://%{Your Host}/assets/vwidget.js"></script>
10
+ <script type="text/javascript">
11
+ new E9.VWidget({
12
+ code: "your provided widget code"
13
+ }).render();
14
+ </script>
15
+ *
16
+ * In addition to "code" several other options are available, including callbacks
17
+ * which provide access to the Widget and its generated HTML, these documentation
18
+ * for these options can be found at the above url.
19
+ */
20
+
21
+ /**
22
+ * @namespace E9 VWidget public namespace
23
+ */
24
+ E9 = window.E9 || {};
25
+
26
+
27
+ (function() {
28
+ if (E9 && E9.VWidget) return;
29
+
30
+ /**
31
+ * @constructor
32
+ * @param {Object} opts the configuration options for the page
33
+ */
34
+ E9.VWidget = function(opts) {
35
+ this.init(opts);
36
+ }
37
+
38
+ E9.VWidget.jsonP = function(url, callback) {
39
+ var script = document.createElement('script');
40
+ script.type = 'text/javascript';
41
+ script.src = url;
42
+
43
+ var head = document.getElementsByTagName('head')[0];
44
+ head.insertBefore(script, head.firstChild);
45
+
46
+ callback(script);
47
+ return script;
48
+ }
49
+
50
+ var
51
+
52
+ /*
53
+ Developed by Robert Nyman, http://www.robertnyman.com
54
+ Code/licensing: http://code.google.com/p/getelementsbyclassname/
55
+ */
56
+ getElementsByClassName = function (className, tag, elm){
57
+ if (document.getElementsByClassName) {
58
+ getElementsByClassName = function (className, tag, elm) {
59
+ elm = elm || document;
60
+ var elements = elm.getElementsByClassName(className),
61
+ nodeName = (tag)? new RegExp("\\b" + tag + "\\b", "i") : null,
62
+ returnElements = [],
63
+ current;
64
+ for(var i=0, il=elements.length; i<il; i+=1){
65
+ current = elements[i];
66
+ if(!nodeName || nodeName.test(current.nodeName)) {
67
+ returnElements.push(current);
68
+ }
69
+ }
70
+ return returnElements;
71
+ };
72
+ }
73
+ else if (document.evaluate) {
74
+ getElementsByClassName = function (className, tag, elm) {
75
+ tag = tag || "*";
76
+ elm = elm || document;
77
+ var classes = className.split(" "),
78
+ classesToCheck = "",
79
+ xhtmlNamespace = "http://www.w3.org/1999/xhtml",
80
+ namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace : null,
81
+ returnElements = [],
82
+ elements,
83
+ node;
84
+ for(var j=0, jl=classes.length; j<jl; j+=1){
85
+ classesToCheck += "[contains(concat(' ', @class, ' '), ' " + classes[j] + " ')]";
86
+ }
87
+ try {
88
+ elements = document.evaluate(".//" + tag + classesToCheck, elm, namespaceResolver, 0, null);
89
+ }
90
+ catch (e) {
91
+ elements = document.evaluate(".//" + tag + classesToCheck, elm, null, 0, null);
92
+ }
93
+ while ((node = elements.iterateNext())) {
94
+ returnElements.push(node);
95
+ }
96
+ return returnElements;
97
+ };
98
+ }
99
+ else {
100
+ getElementsByClassName = function (className, tag, elm) {
101
+ tag = tag || "*";
102
+ elm = elm || document;
103
+ var classes = className.split(" "),
104
+ classesToCheck = [],
105
+ elements = (tag === "*" && elm.all)? elm.all : elm.getElementsByTagName(tag),
106
+ current,
107
+ returnElements = [],
108
+ match;
109
+ for(var k=0, kl=classes.length; k<kl; k+=1){
110
+ classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
111
+ }
112
+ for(var l=0, ll=elements.length; l<ll; l+=1){
113
+ current = elements[l];
114
+ match = false;
115
+ for(var m=0, ml=classesToCheck.length; m<ml; m+=1){
116
+ match = classesToCheck[m].test(current.className);
117
+ if (!match) {
118
+ break;
119
+ }
120
+ }
121
+ if (match) {
122
+ returnElements.push(current);
123
+ }
124
+ }
125
+ return returnElements;
126
+ };
127
+ }
128
+ return getElementsByClassName(className, tag, elm);
129
+ },
130
+
131
+ // basic implementation to get the y position
132
+ // of an element (the page attempts to scroll to it after form completion)
133
+ getYPos = function(el) {
134
+ var pos = 0;
135
+ try {
136
+ if (el.offsetParent) {
137
+ do {
138
+ pos += el.offsetTop;
139
+ } while (el = el.offsetParent);
140
+ }
141
+ } catch (e) {
142
+ } finally {
143
+ return pos;
144
+ }
145
+ },
146
+
147
+ /*
148
+ * helper function to check if an object is "empty"
149
+ */
150
+ isEmpty = function(obj) {
151
+ for(var i in obj) { if (obj.hasOwnProperty(i)){return false;}}
152
+ return true;
153
+ },
154
+
155
+ /*
156
+ * helper function to check for IE
157
+ */
158
+ browser = function() {
159
+ var rv = 999,
160
+ ua = navigator.userAgent,
161
+ re = new RegExp("MSIE ([0-9]+[\.0-9]{0,})");
162
+
163
+ if (re.exec(ua) != null) rv = parseFloat( RegExp.$1 );
164
+
165
+ return { version: rv };
166
+ },
167
+
168
+ isFirebug = function() {
169
+ var retv = false;
170
+ try {
171
+ retv = window.hasOwnProperty('console');
172
+ } catch(e) {
173
+ } finally {
174
+ return retv;
175
+ }
176
+ },
177
+
178
+ head = function() {
179
+ return document.getElementsByTagName("head")[0];
180
+ },
181
+
182
+ addHeadElement = function(el) {
183
+ head().appendChild(el);
184
+ },
185
+
186
+ removeHeadElement = function(el) {
187
+ head().removeChild(el);
188
+ },
189
+
190
+ /*
191
+ * helper function to create element tags.
192
+ * attrs accepts a hash of attributes or a string id
193
+ *
194
+ * writes a singleton tag unless content is passed.
195
+ * to force a closing tag with no content, pass an empty string.
196
+ */
197
+ tag = function(element, attrs, content) {
198
+ if (!attrs) attrs = {};
199
+
200
+ var html = '<' + element;
201
+ if (typeof attrs == 'string') {
202
+ html += ' id="' + attrs + '"';
203
+ } else {
204
+ for (var attr in attrs) {
205
+ html += ' '+attr+'="'+attrs[attr]+'"';
206
+ }
207
+ }
208
+
209
+ if (typeof content == 'string') {
210
+ html += '>'+content+'</' + element + '>';
211
+ } else {
212
+ html += '/>';
213
+ }
214
+
215
+ return html;
216
+ },
217
+
218
+ /*
219
+ * helper function to create divs, simple interface to #tag
220
+ */
221
+ div = function(attrs, content) {
222
+ return tag('div', attrs, content);
223
+ },
224
+
225
+ boolCheckbox = function(default_value, attrs, label) {
226
+ attrs['type'] = 'checkbox';
227
+ attrs['checked'] = 'checked';
228
+ attrs['value'] = '0';
229
+ attrs['style'] = 'display:none;visibility:hidden';
230
+
231
+ var retv = tag('input', attrs);
232
+
233
+ if (!default_value) delete attrs['checked'];
234
+ delete attrs['style'];
235
+ attrs['value'] = '1';
236
+
237
+ retv += tag('input', attrs);
238
+
239
+ if (label) retv += tag('label', {'class':'vb-label'}, label);
240
+
241
+ return retv;
242
+ },
243
+
244
+ timestamp = function() {
245
+ return new Date().getTime();
246
+ },
247
+
248
+ wait = function(options) {
249
+ options.success = options.success || function() {};
250
+ options.until = options.until || function() { return false; };
251
+ options.error = options.error || function() {};
252
+ options.timeout = options.timeout || 5000;
253
+ options.interval = options.interval || 2;
254
+
255
+ var start = timestamp(), elapsed, now;
256
+
257
+ window.setTimeout(function() {
258
+ now = timestamp();
259
+ elapsed = now - start;
260
+
261
+ if (options.until(elapsed)) {
262
+ options.success();
263
+ return false;
264
+ }
265
+
266
+ if (now >= start + options.timeout) {
267
+ options.error();
268
+ return false;
269
+ }
270
+
271
+ window.setTimeout(arguments.callee, options.interval);
272
+ }, options.interval)
273
+ },
274
+
275
+ resetForm = function() {
276
+ var form = document.getElementById('vb-form'),
277
+ inputs = form.getElementsByTagName('input');
278
+
279
+ for (var i=0;i<inputs.length;i++) {
280
+ if(inputs[i].type == 'text') { inputs[i].value = ''; }
281
+ }
282
+ }
283
+
284
+ E9.VWidget.COUNT = 0;
285
+ E9.VWidget.ERROR_MESSAGE = '\
286
+ <h3 id="vb-timeout-message">Error loading content.</h3>\
287
+ <p>The vendor list is down for scheduled maintenance. Please check back soon.</p>';
288
+
289
+ E9.VWidget.prototype = function () {
290
+ var
291
+
292
+ // recaptcha key is unchangeable client side as it corresponds to
293
+ // the private key held on the server
294
+ recaptchaPublicKey = "6LfGdMASAAAAAHfYpORJWsFUtqJGM7WhxMElUMlo",
295
+
296
+ defaults = {
297
+ /**
298
+ * The url of vendorboon.
299
+ *
300
+ * This is overridable mainly for testing purposes. It is one of the
301
+ * two variables included in the output of the generated widget code and
302
+ * shouldn't be changed under normal circumstances.
303
+ */
304
+ url: 'http://www.vendorboon.com',
305
+
306
+ /**
307
+ * The element ID of the div where the widget should be written.
308
+ *
309
+ * The init process first looks for an existing element by this ID.
310
+ * If found it will use it as the base HTML element where the widget is
311
+ * written. If not found, it will create it in place wherever
312
+ * E9.VWidget#render is called, with the ID defined here.
313
+ *
314
+ * This means there are two ways to call VWidget#render:
315
+ *
316
+ * A. Inline:
317
+ * <div id="foo">
318
+ * <script type="text/javascript">
319
+ * new E9.VWidget({
320
+ * code: 'yourcode'
321
+ * }).render();
322
+ * </script>
323
+ * </div>
324
+ *
325
+ * B. Deferred:
326
+ * <div id="foo"></div>
327
+ * ...
328
+ * <script type="text/javascript">
329
+ * new E9.VWidget({
330
+ * code: 'yourcode',
331
+ * elementId: 'foo'
332
+ * }).render();
333
+ * </script>
334
+ *
335
+ * In case A, the widget will be written in place where it is called.
336
+ * In case B, the widget will be written inside the div "foo" that
337
+ * already exists. In this way you could defer the loading til the end
338
+ * of the page, or in, for example, the jQuery.ready handler;
339
+ *
340
+ * Note that in case B, if elementId is passed but does not exist,
341
+ * the widget will still write itself in place, but inside an element
342
+ * with the ID passed.
343
+ */
344
+ elementId: 'vb-widget-container',
345
+
346
+ /**
347
+ * By default the widget prepends a stylesheet link to <head> which
348
+ * contains widget specific styles (plus an additional IE stylesheet if
349
+ * an IE browser is detected).
350
+ *
351
+ * Passing this as false prevents the style load from happening.
352
+ */
353
+ styles: true,
354
+
355
+ /**
356
+ * A callback which occurs at the end of the init process, before render.
357
+ * At this point the widget is fully configured, but waiting on initial
358
+ * response from the server before rendering HTML.
359
+ *
360
+ * To manipulate HTML you should not use this, but onRender
361
+ *
362
+ * @param {Function} widget The E9.VWidget instance being created
363
+ */
364
+ onInit: function(widget) {},
365
+
366
+ /**
367
+ * A callback which occurs after the HTML has been rendered, immediately
368
+ * before it is made visible. At this point you have access to all the
369
+ * HTML generated by the widget, referenced by the widget property 'element'.
370
+ *
371
+ * @param {Function} widget the E9.VWidget instance being created
372
+ */
373
+ onRender: function(widget) {},
374
+
375
+ /**
376
+ * Callback that occurs on timeout error. You may override this if, e.g.
377
+ * you wanted to change the error message or HTML.
378
+ */
379
+ onError: function(widget) {},
380
+
381
+ /**
382
+ * the timeout to wait for a response from the vendorboon server before displaying
383
+ * an error.
384
+ */
385
+ timeout: 10000,
386
+
387
+ /**
388
+ * the timeout to wait for a response from the google recaptcha server before displaying
389
+ * an error.
390
+ */
391
+ recaptcha_timeout: 10000,
392
+
393
+ /**
394
+ * The html tag used for widget headings. The class of these elements
395
+ * is 'vb-heading', regardless of the tag.
396
+ */
397
+ headingTag: 'h2',
398
+
399
+ /**
400
+ * The html tag used for widget subheadings. The class of these elements
401
+ * is 'vb-subheading', regardless of the tag.
402
+ */
403
+ subheadingTag: 'h3',
404
+
405
+ /**
406
+ * The text of the "Show Description" links which show or hide the long
407
+ * description for each vendor.
408
+ */
409
+ showDescText: 'View More Info',
410
+
411
+ /**
412
+ * The recaptcha theme used.
413
+ *
414
+ * Accepted options: red, white, blackglass, clean
415
+ *
416
+ * For details, see:
417
+ * http://code.google.com/apis/recaptcha/docs/customization.html
418
+ *
419
+ */
420
+ recaptchaTheme: 'white'
421
+ };
422
+
423
+ return {
424
+ init: function(opts) {
425
+ var that = this, html;
426
+
427
+ if (!opts) opts = {};
428
+
429
+ this.url = opts.url || defaults.url;
430
+
431
+ // if url is protocol relative, prepend protocol
432
+ if (/^\/\//.test(this.url)) {
433
+ this.url = location.protocol + this.url;
434
+
435
+ // else if we're https, ensure the url is
436
+ } else if (location.protocol.match(/^https/)) {
437
+ this.url = this.url.replace(/^http:/, 'https:');
438
+ }
439
+
440
+ // cut trailing / from url if present
441
+ if (/\/$/.test(this.url)) this.url = this.url.substr(0, this.url.length - 1);
442
+
443
+ // defines a callback in case of more than one widget on a page (unlikely)...
444
+ this.callback = 'cb' + ++E9.VWidget.COUNT;
445
+
446
+ // and defines a global callback on E9.VWidget for jsonp
447
+ E9.VWidget[this.callback] = function(response) {
448
+ clearTimeout(that.jsonRequestTimer);
449
+ that.renderHtmlFromResponse(response);
450
+ that.removeScriptElement();
451
+ }
452
+
453
+ // code must be passed
454
+ if (!opts.code) {
455
+ html = tag('h3', {'class':'vb-error'}, 'E9.VWidget requires that you pass a code identifying yourself as a member');
456
+ } else {
457
+ html = tag('h3', {'class':'vb-loading'}, 'Loading...');
458
+ this.scriptUrl = this.url + '/directory/members/' + opts.code + '.json?jsonp=E9.VWidget.' + this.callback;
459
+ this.formUrl = this.url + '/contact_requests.json';
460
+ }
461
+
462
+ /* form is currently off */
463
+ this.showForm = false;
464
+
465
+ this.recaptchaPublicKey = recaptchaPublicKey;
466
+ this.recaptchaTheme = opts.recaptchaTheme || defaults.recaptchaTheme;
467
+ this.recaptcha_timeout = opts.recaptcha_timeout || defaults.recaptcha_timeout;
468
+
469
+ this.styles = opts.hasOwnProperty('styles') ? opts.styles : true
470
+ this.timeout = opts.timeout || defaults.timeout;
471
+ this.elementId = opts.elementId || defaults.elementId;
472
+ this.onRender = opts.onRender || defaults.onRender;
473
+ this.onInit = opts.onInit || defaults.onInit;
474
+ this.timeout = opts.timeout || defaults.timeout;
475
+ this.headingTag = opts.headingTag || defaults.headingTag;
476
+ this.subheadingTag = opts.subheadingTag || defaults.subheadingTag;
477
+ this.showDescText = opts.showDescText || defaults.showDescText;
478
+
479
+ this.element = document.getElementById(this.elementId);
480
+ if (!this.element) {
481
+ document.write(div(this.elementId, ''));
482
+ this.element = document.getElementById(this.elementId);
483
+ }
484
+ if (opts.width) this.element.style.width = opts.width;
485
+ if (opts.height) this.element.style.height = opts.height;
486
+ this.element.innerHTML = html;
487
+
488
+ this.onInit(this);
489
+ },
490
+
491
+ removeScriptElement: function() {
492
+ removeHeadElement(this.scriptElement);
493
+ },
494
+
495
+ addReCAPTCHAScript: function() {
496
+ var script = document.createElement('script');
497
+ script.type = 'text/javascript';
498
+ // NOTE protocol relative recaptcha url
499
+ script.src = "//www.google.com/recaptcha/api/js/recaptcha_ajax.js";
500
+
501
+ var head = document.getElementsByTagName('head')[0];
502
+ head.insertBefore(script, head.firstChild);
503
+ },
504
+
505
+ displayReCAPTCHA: function() {
506
+ Recaptcha.create(this.recaptchaPublicKey, "vb-recaptcha", {
507
+ theme: this.recaptchaTheme,
508
+ callback: function() {}
509
+ });
510
+ },
511
+
512
+ addStylesheets: function() {
513
+ var link = document.createElement("link");
514
+ link.href = this.url + "/stylesheets/vb-widget.css";
515
+ link.rel = "stylesheet";
516
+ link.type = "text/css";
517
+ addHeadElement(link);
518
+
519
+ if (browser().version < 8) {
520
+ link = document.createElement("link");
521
+ link.href = this.url + "/stylesheets/vb-widget-ie.css";
522
+ link.rel = "stylesheet";
523
+ link.type = "text/css";
524
+ addHeadElement(link);
525
+ }
526
+ },
527
+
528
+ setTimeout: function(e) {
529
+ var that = this;
530
+ this.jsonRequestTimer = window.setTimeout(function() {
531
+ that.element.innerHTML = E9.VWidget.ERROR_MESSAGE;
532
+ }, this.timeout);
533
+ },
534
+
535
+ getFieldElements: function() {
536
+ var elements = new Array();
537
+ try {
538
+ elements.push(document.getElementById('vb-form-name'));
539
+ elements.push(document.getElementById('vb-form-phone'));
540
+ elements.push(document.getElementById('vb-form-email'));
541
+ } catch(e) {
542
+ } finally {
543
+ return elements;
544
+ }
545
+ },
546
+
547
+ getShowLinks: function() {
548
+ var showlinks = new Array();
549
+ try {
550
+ var links = document.getElementById('vb-vendor-list').getElementsByTagName('a');
551
+ for(var i=0;i<links.length;i++) {
552
+ if(links[i].name == 'vb-ldl') { showlinks.push(links[i]); }
553
+ }
554
+ } catch (e) {
555
+ } finally {
556
+ return showlinks;
557
+ }
558
+ },
559
+
560
+ renderHtmlFromResponse: function(response) {
561
+ if (isFirebug()) console.dir(response);
562
+
563
+ if (response && typeof response === 'object' && response.type == 'contact-request' || response.type == 'member') {
564
+ var that = this, html = '';
565
+
566
+ if (response.type == 'contact-request') {
567
+ // reload the captcha no matter what, it's not good for a 2nd pass.
568
+ Recaptcha.reload();
569
+
570
+ // re-enable the submit button if it was disabled on press
571
+ var submit = document.getElementById('vb-form-submit');
572
+ if (submit) { submit.removeAttribute('disabled'); }
573
+
574
+ var m = document.getElementById('vb-feedback');
575
+
576
+ if (isEmpty(response.errors)) {
577
+ m.className = 'vb-feedback vb-feedback-success';
578
+ resetForm();
579
+
580
+ html = 'Your request has been submitted.';
581
+ } else {
582
+ var field;
583
+ m.className = 'vb-feedback vb-feedback-error';
584
+ for (var e in response.errors) {
585
+ if (field = document.getElementById('vb-form-' + e)) {
586
+ field.className = 'vb-field vb-field-error';
587
+ }
588
+ html += div({'class':'vb-feedback-error-field'}, response.errors[e])
589
+ }
590
+ }
591
+
592
+ m.innerHTML = html;
593
+ m.style.display = 'block';
594
+
595
+ window.scrollTo(0, getYPos(m));
596
+ } else {
597
+ response = response.resource;
598
+
599
+ // TODO these html buffer variables are a bit chaotic...
600
+ var vc, vendor, contentHtml = '', formHtml = '', formHtmlInner, fHtml, cHtml, vHtml, vHtmlInner;
601
+
602
+ var vendorlist = '', optionList = '';
603
+
604
+ optionList += tag('option', {'value': 0}, 'All');
605
+ response.categories.forEach(function(c) {
606
+ optionList += tag('option', {'value': c.id }, c.name);
607
+ });
608
+
609
+ contentHtml += tag(that.subheadingTag, {'id':'vb-contact-form-heading','class':'vb-subheading'}, response.widget_form_title);
610
+ contentHtml += tag('select', {'id':'vb-category-select'}, optionList);
611
+ contentHtml += div({'class':'vb-text'}, response.widget_form_text);
612
+
613
+ response.vendors.forEach(function(vendor) {
614
+ vHtml = '';
615
+ formHtmlInner = '';
616
+
617
+ // next if vendor is not present or it shouldn't display
618
+ if (!vendor || !vendor.display_on_widget) return;
619
+
620
+ vHtmlInner = '';
621
+
622
+ // logo
623
+ if (vendor.logo) {
624
+ vHtmlInner += div({'class':'vb-vendor-logo'}, tag('img', {'src':vendor.logo}));
625
+ }
626
+
627
+ var cbHtml = '', vendorClass = 'vb-vendor';
628
+
629
+ // title
630
+ cbHtml += div({'class':'vb-vendor-name'}, vendor.name);
631
+
632
+ // short desc & link
633
+ cbHtml += div({'class':'vb-vendor-short-description'},
634
+ vendor.short_description + ' ' +
635
+ tag('a', {'data-id':vendor.id, 'class':'vb-show-desc-link', 'name':'vb-ldl', href:'javascript:;'}, that.showDescText)
636
+ );
637
+
638
+ // long desc
639
+ cbHtml += div({'style':'display:none', 'class':'vb-vendor-long-description', 'id':'vb-ld'+vendor.id}, vendor.long_description);
640
+
641
+ vHtmlInner += div({'class':'vb-vendor-content'}, cbHtml);
642
+
643
+ vendor.categories.forEach(function(cat) {
644
+ vendorClass += ' vb-c' + cat.id;
645
+ });
646
+
647
+ // wrap it up
648
+ vendorlist += div({'class': vendorClass}, vHtmlInner);
649
+
650
+ // continue if there is no contact form, or vendor shouldn't display on it
651
+ if (!that.showForm || !vendor.display_on_widget_contact_form) return;
652
+
653
+ // otherwise add them
654
+ formHtmlInner += div({'class':'vb-field'},
655
+ tag('input', {
656
+ 'name':'contact_request[vendor_detail_ids][]',
657
+ 'type':'checkbox',
658
+ 'value':vendor.id,
659
+ 'checked':'checked'
660
+ }) +
661
+ tag('label', {'class':'vb-label'}, vendor.name)
662
+ );
663
+
664
+ if (formHtmlInner.length) {
665
+ fHtml = div({'class':'vb-vendor-category-name'}, vc),
666
+ fHtml += div({'class':'vb-vendors'}, formHtmlInner);
667
+ formHtml += div({'class':'vb-vendor-category'}, fHtml);
668
+ }
669
+ });
670
+
671
+ contentHtml += div({'id':'vb-vendor-list'}, vendorlist);
672
+
673
+ if (that.showForm) {
674
+ // if vendors were added to formHtml, wrap them in fieldset
675
+ if (formHtml.length) {
676
+ formHtml =
677
+ tag('fieldset', {'class':'vb-fieldset vb-checkbox'},
678
+ tag('legend', 'vb-fieldset-legend', 'Vendors') +
679
+ formHtml
680
+ )
681
+ ;
682
+ }
683
+
684
+ formHtml += div({'class':'vb-field', 'id':'vb-form-name'},
685
+ tag('label', {'class':'vb-label vb-req'}, 'Full Name *') +
686
+ tag('input', { 'name':'contact_request[name]', 'type':'text' })
687
+ );
688
+
689
+ formHtml += div({'class':'vb-field', 'id':'vb-form-email'},
690
+ tag('label', {'class':'vb-label vb-req'}, 'Contact Email *') +
691
+ tag('input', { 'name':'contact_request[email]', 'type':'text' })
692
+ );
693
+
694
+ formHtml += div({'class':'vb-field', 'id':'vb-form-phone'},
695
+ tag('label', {'class':'vb-label'}, 'Contact Phone') +
696
+ tag('input', { 'name':'contact_request[phone]', 'type':'text' })
697
+ );
698
+
699
+ formHtml += div("vb-recaptcha", '');
700
+
701
+ formHtml += div({'class':'vb-actions'},
702
+ tag('input', {
703
+ 'id':'vb-form-submit',
704
+ 'name':'vb-form-submit',
705
+ 'type':'submit',
706
+ 'value':'Submit'
707
+ })
708
+ );
709
+
710
+ contentHtml += div({'id':'vb-form'}, formHtml);
711
+ contentHtml += div({'id':'vb-feedback', 'class':'vb-feedback', 'style':'display:none'}, '');
712
+ }
713
+
714
+ html += tag(that.headingTag, {'id':'vb-heading','class':'vb-heading'}, response.widget_title);
715
+ html += div('vb-content', contentHtml);
716
+
717
+ // hide the element so it can be manipulated by onRender
718
+ this.element.style.display = 'none';
719
+
720
+ this.element.innerHTML = div('vb-widget', html);
721
+
722
+ var select = document.getElementById('vb-category-select'),
723
+ el = this.element,
724
+ vendors = document.getElementsByClassName('vb-vendor', 'div', el);
725
+
726
+ function toggleViz(v, els) {
727
+ for (i in els) {
728
+ if (els.hasOwnProperty(i)) els[i].style.display = v ? 'block' : 'none';
729
+ }
730
+ }
731
+
732
+ select.onchange = function() {
733
+ if (this.value == '0') {
734
+ toggleViz(true, vendors);
735
+ } else {
736
+ toggleViz(false, vendors);
737
+ toggleViz(true, getElementsByClassName('vb-c'+this.value, 'div', el));
738
+ }
739
+ }
740
+
741
+ var showlink, showlinks = this.getShowLinks();
742
+ for (var i=0;i<showlinks.length;i++) {
743
+ showlink = showlinks[i];
744
+
745
+ showlink['element'] = document.getElementById('vb-ld' + showlink.attributes['data-id'].value);
746
+
747
+ showlink.onclick = function() {
748
+ this.element.style.display = this.element.style.display == 'none' ? 'block' : 'none';
749
+ }
750
+
751
+ showlink.onmouseover = function() {
752
+ window.status = 'Toggle full description';
753
+ return true;
754
+ }
755
+ }
756
+
757
+ if (this.showForm) {
758
+ var form = document.getElementById('vb-form'),
759
+ submit = document.getElementById('vb-form-submit');
760
+
761
+ submit.onclick = function(e) {
762
+ this.setAttribute("disabled", "disabled");
763
+
764
+ var fields = that.getFieldElements();
765
+ for(var i=0;i<fields.length;i++) {
766
+ fields[i].className = 'vb-field';
767
+ }
768
+
769
+ var inputs = form.getElementsByTagName('input');
770
+
771
+ var formData = '', formLen = inputs.length;
772
+ for(var i=0;i<formLen;i++) {
773
+ if(!inputs[i].name) continue;
774
+ if(inputs[i].type == 'submit') continue;
775
+ if(inputs[i].type != 'checkbox' || inputs[i].checked) {
776
+ formData += inputs[i].name + '=' + encodeURIComponent(inputs[i].value)
777
+ }
778
+ formData += '&';
779
+ }
780
+
781
+ formData += 'jsonp=E9.VWidget.' + that.callback;
782
+
783
+ that.setTimeout();
784
+ E9.VWidget.jsonP(that.formUrl + '?' + formData, function(el) {
785
+ that.scriptElement = el;
786
+ });
787
+
788
+ return false;
789
+ }
790
+
791
+ this.displayReCAPTCHA();
792
+ }
793
+
794
+ this.onRender(this);
795
+ this.element.style.display = 'block';
796
+ }
797
+ } else {
798
+ this.element.style.display = 'none';
799
+ this.element.innerHTML = E9.VWidget.ERROR_MESSAGE;
800
+ this.onError(this);
801
+ this.element.style.display = 'block';
802
+ }
803
+ },
804
+
805
+ /**
806
+ * @access public
807
+ * @return {Object} self
808
+ */
809
+ render: function() {
810
+ that = this;
811
+
812
+ if (this.styles) {
813
+ this.addStylesheets();
814
+ }
815
+
816
+ if (this.scriptUrl) {
817
+ function loadJSON() {
818
+ that.setTimeout();
819
+ E9.VWidget.jsonP(that.scriptUrl, function(el) { that.scriptElement = el; });
820
+ }
821
+
822
+ if (this.showForm) {
823
+ this.addReCAPTCHAScript();
824
+ wait({
825
+ timeout : that.recaptcha_timeout,
826
+ until : function(elapsed) { return typeof Recaptcha !== 'undefined'; },
827
+ error : function() { that.element.innerHTML = E9.VWidget.ERROR_MESSAGE; },
828
+ success : loadJSON
829
+ });
830
+ } else {
831
+ loadJSON();
832
+ }
833
+ }
834
+ return this;
835
+ }
836
+ };
837
+ }();
838
+ })();
839
+
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: e9_vendors
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.1
5
+ version: 0.0.2
6
6
  platform: ruby
7
7
  authors:
8
8
  - Travis Cox
@@ -85,7 +85,7 @@ files:
85
85
  - app/views/e9_vendors/vendors/index.html.haml
86
86
  - app/views/e9_vendors/vendors/index.js.erb
87
87
  - app/views/e9_vendors/vendors/new.html.haml
88
- - config/locales/vendorboon.en.yml
88
+ - config/locales/e9_vendors.en.yml
89
89
  - config/routes.rb
90
90
  - e9_vendors.gemspec
91
91
  - lib/e9_vendors.rb
@@ -93,7 +93,8 @@ files:
93
93
  - lib/e9_vendors/model.rb
94
94
  - lib/e9_vendors/version.rb
95
95
  - lib/generators/e9_vendors/install_generator.rb
96
- - lib/generators/e9_vendors/templates/javascript.js
96
+ - lib/generators/e9_vendors/templates/javascripts/e9_vendors.js
97
+ - lib/generators/e9_vendors/templates/javascripts/widget.js
97
98
  - lib/generators/e9_vendors/templates/migration.rb
98
99
  - lib/generators/e9_vendors/templates/stylesheets/vb-widget-ie.scss
99
100
  - lib/generators/e9_vendors/templates/stylesheets/vb-widget.scss