e9_vendors 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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