kf5 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a3eb3a3fec42ed6f95a4a436ecaece42593d6edd
4
- data.tar.gz: c7d1515809f053724790d54cca8c3e2b12cfdb28
3
+ metadata.gz: 50231b0a61f410d1d4d532d091b04927d9b275c4
4
+ data.tar.gz: fe9f484fd4ae97eb4443e6aceb07b9663933d411
5
5
  SHA512:
6
- metadata.gz: 5aa8979a24e1087d587f50ff52288bc520d3dab17ea589fc42b6e69eb346f28faf5de8fc903945960b39853ddd68f546c3ece1af85273201a409d68776e68e01
7
- data.tar.gz: dab062f39fbdaa8dc5ba06b28c10f9d55ef1123ae1546582c5b467b28f91efdb52f7c73d06bc27ff0118383de023a0081532846118a3822e7a177aee5452ff22
6
+ metadata.gz: 032f67d39110a4cdc78ad65855b2d74c5b4dfc4d544ce67858fab624fef3533ef3056e0437613aa8d98a0dc400cae945401c8bc3805a2b4d16bd4148921feca4
7
+ data.tar.gz: 1b741f647529dee6eb897ea7392937d319edb2f3487efaddf6876f169f135474cd0a114bc0e62a7a447bc811c6bf8eb123d3dd1d1e5867393fd57db50aada80e
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
4
+ before_install: gem install bundler
@@ -1,3 +1,7 @@
1
+ # v0.2.0 / 2015-09-19
2
+
3
+ * add embedded javascript plugin.
4
+
1
5
  # v0.1.0 / 2015-09-03
2
6
 
3
7
  Create project
data/Gemfile CHANGED
@@ -2,3 +2,6 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in presenters.gemspec
4
4
  gemspec
5
+
6
+ gem 'simplecov', :require => false
7
+ gem 'coveralls', :require => false
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # KF5
2
2
 
3
+ [![Build Status](https://api.travis-ci.org/emn178/kf5.png)](https://travis-ci.org/emn178/kf5)
4
+ [![Coverage Status](https://coveralls.io/repos/emn178/kf5/badge.svg?branch=master)](https://coveralls.io/r/emn178/kf5?branch=master)
5
+
3
6
  A library to integrate with KF5 help desk.[逸創云客服](http://www.kf5.com/)
4
7
 
5
8
  ## Installation
@@ -50,6 +53,11 @@ Or you can assaign arguments manaully
50
53
  redirect_to_kf5 :username => 'username' # others....
51
54
  ```
52
55
 
56
+ In view, you can use `kf5_tag` to include javascript plugin.
57
+ ```ruby
58
+ = kf5_tag
59
+ ```
60
+
53
61
  ## License
54
62
 
55
63
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,561 @@
1
+ (function(window, config)
2
+ {
3
+ "use strict";
4
+
5
+ var
6
+ script = window.document.getElementById('kf5-provide-supportBox'),
7
+ parts = script.src.split('//'),
8
+ host = parts.length > 1 ? parts[0] + '//' + parts[1].split('/')[0] : '',
9
+ kf5Domain = script.getAttribute('kf5-domain'),
10
+ supportboxConfigURL = '//' + kf5Domain + '/supportbox/buttonconfig',
11
+ _config = {
12
+ btn_name : '帮助按钮',
13
+ facade : '1',
14
+ color : '#7A88FF',
15
+ position : 'right',
16
+ iframeURL : '//' + kf5Domain + '/supportbox/index',
17
+ btn_icon : '//assets.kf5.com/supportbox/images/icon2.png',
18
+ styleURL : '//assets.kf5.com/supportbox/css/btn.css',
19
+ template : '<div id="kw-tab" class="kf5-support-btn" style="{{bg_color}}"> <img src="{{btn_icon}}" alt=""><span>{{title}}</span> </div> <div id="kw-block" class="kf5-support"> <a id="kw-close" class="kf5-close" title="关闭"><i class="icon-clear"></i></a> <div id="kw-loading" class="kf5-loading"> </div> <iframe id="kw-widget-iframe" src="" scrolling="no" frameborder="0"></iframe> </div>'
20
+ };
21
+
22
+ function KF5SupportBox(config)
23
+ {
24
+ this.config = config || {};
25
+
26
+ this.init();
27
+ }
28
+
29
+ window.KF5SupportBox = KF5SupportBox;
30
+
31
+ KF5SupportBox.prototype = {
32
+
33
+ el: null,
34
+
35
+ getElement: function(selector)
36
+ {
37
+ return window.document.getElementById(selector.replace('#', ''));
38
+ },
39
+
40
+ getOpt: function(key)
41
+ {
42
+ if(this.config.hasOwnProperty(key))
43
+ {
44
+ return this.config[key];
45
+ }
46
+ else
47
+ {
48
+ return _config[key];
49
+ }
50
+ },
51
+
52
+ init: function()
53
+ {
54
+ this._prepareStyle();
55
+
56
+ return this;
57
+ },
58
+
59
+ initElements: function()
60
+ {
61
+ this._prepareElement();
62
+ this.append();
63
+
64
+ this._bindEvents();
65
+ },
66
+
67
+ append: function()
68
+ {
69
+ window.document.body.appendChild(this.el);
70
+
71
+ return this;
72
+ },
73
+
74
+ _prepareStyle: function()
75
+ {
76
+ var link = window.document.createElement('link');
77
+
78
+ link.rel = 'styleSheet';
79
+ link.type = 'text/css';
80
+ link.href = this.getOpt('styleURL');
81
+
82
+ var self = this;
83
+ link.onload = function()
84
+ {
85
+ self.initElements();
86
+ link.onload = null;
87
+ };
88
+
89
+ window.document.body.appendChild(link);
90
+
91
+ return this;
92
+ },
93
+
94
+ _prepareElement: function()
95
+ {
96
+ var className = 'kf5-support-123456789';
97
+
98
+ // 位置
99
+ if(this.getOpt('position') === 'left')
100
+ {
101
+ className += ' kf5-left';
102
+ }
103
+ else
104
+ {
105
+ className += ' kf5-right'
106
+ }
107
+
108
+ // 外观
109
+ className += ' kf5-style' + (parseInt(this.getOpt('facade')) || 1);
110
+
111
+ // 设备
112
+ if(this.getOpt('is_mobile'))
113
+ {
114
+ className += ' kf5-mobile';
115
+ }
116
+
117
+ this.el = window.document.createElement('div');
118
+ this.el.setAttribute('class', className);
119
+ this.el.innerHTML = this.getOpt('template')
120
+ .replace('{{title}}', this.getOpt('btn_name') || '获取帮助')
121
+ .replace('{{btn_icon}}', this.getOpt('btn_icon'))
122
+ .replace('{{bg_color}}', this.getOpt('color') ? 'background:' + this.getOpt('color') : '');
123
+
124
+ return this;
125
+ },
126
+
127
+ _bindEvents: function()
128
+ {
129
+ var self = this;
130
+ this.getElement('#kw-tab').onclick = function()
131
+ {
132
+ self.open();
133
+ };
134
+
135
+ this.getElement('#kw-close').onclick = function()
136
+ {
137
+ self.close();
138
+ };
139
+
140
+ this.getElement('#kw-widget-iframe').onload = function()
141
+ {
142
+ // setTimeout(function()
143
+ // {
144
+ self.getElement('#kw-loading').style.display = 'none';
145
+ // }, 2000);
146
+
147
+ };
148
+
149
+ if(cookie('kf5-supportBox-autoOpen'))
150
+ {
151
+ this.open();
152
+ }
153
+
154
+ return this;
155
+ },
156
+
157
+ loadIframe: function()
158
+ {
159
+ var iframe = this.getElement('#kw-widget-iframe');
160
+
161
+ if(!iframe.getAttribute('src'))
162
+ {
163
+ iframe.setAttribute('src', this.getOpt('iframeURL'));
164
+ }
165
+
166
+ return this;
167
+ },
168
+
169
+ // resizeIframe: function(data)
170
+ // {
171
+ // var elem = this.getElement('#kw-block');
172
+
173
+ // if(elem)
174
+ // {
175
+ // elem.style.height = parseFloat(data) + 'px';
176
+ // }
177
+ // },
178
+
179
+ open: function(e)
180
+ {
181
+ if(!this.isOpened)
182
+ {
183
+ hideElement(this.getElement('#kw-tab'));
184
+
185
+ this.loadIframe();
186
+ // slideUp(this.getElement('#kw-widget-iframe'), 400);
187
+ slideUp(this.getElement('#kw-block'), 400);
188
+
189
+ cookie('kf5-supportBox-autoOpen', 1, {expires: 3 / 24, path: '/'});
190
+
191
+ this.isOpened = true;
192
+ }
193
+ },
194
+
195
+ close: function(e)
196
+ {
197
+ // slideDown(this.getElement('#kw-widget-iframe'), 400);
198
+ slideDown(this.getElement('#kw-block'), 400);
199
+
200
+ showElement(this.getElement('#kw-tab'));
201
+ // this.getElement('#kw-widget-iframe').setAttribute('src', '');
202
+
203
+ cookie('kf5-supportBox-autoOpen', null, {path: '/'});
204
+
205
+ this.isOpened = false;
206
+ }
207
+ };
208
+
209
+ var supportbox;
210
+ function onload()
211
+ {
212
+ var script = window.document.createElement('script'),
213
+ configURL = supportboxConfigURL;
214
+
215
+ embed(configURL, function(win)
216
+ {
217
+ if(win.KF5_SUPPORTBOX_BUTTON && win.KF5_SUPPORTBOX_BUTTON.show)
218
+ {
219
+ supportbox = new KF5SupportBox(win.KF5_SUPPORTBOX_BUTTON);
220
+
221
+ // 延时自动加载iframe
222
+ // setTimeout(function()
223
+ // {
224
+ // supportbox.loadIframe();
225
+ // }, 30 * 1000);
226
+ }
227
+ });
228
+ }
229
+
230
+ document.addEventListener('page:load', onload, false);
231
+ window.addEventListener('load', onload, false);
232
+
233
+ // allow cross origin operation
234
+ window.addEventListener('message', function(e)
235
+ {
236
+ var context, cmd, data;
237
+
238
+ if(e.data)
239
+ {
240
+ context = e.data.match(/^([^ ]+)(?: +(.*))?/);
241
+ cmd = context[1];
242
+ data = context[2];
243
+ }
244
+
245
+ if(cmd === 'CMD::showSupportbox')
246
+ {
247
+ if(supportbox)
248
+ {
249
+ supportbox.open();
250
+ }
251
+ }
252
+ else if(cmd === 'CMD::hideSupportbox')
253
+ {
254
+ if(supportbox)
255
+ {
256
+ supportbox.close();
257
+ }
258
+ }
259
+ else if(cmd === 'CMD::resizeIframe')
260
+ {
261
+ // supportbox.resizeIframe(data);
262
+ }
263
+ });
264
+
265
+ function embed(mainJS, output)
266
+ {
267
+ var domain, doc, iframeWindow, iframeDoc,
268
+ iframe = window.document.createElement("iframe");
269
+
270
+ iframe.src = "javascript:false",
271
+ iframe.title = "",
272
+ iframe.role = "presentation",
273
+ (iframe.frameElement || iframe).style.cssText = "display: none",
274
+ window.document.body.appendChild(iframe);
275
+ iframeWindow = iframe.contentWindow,
276
+ iframeDoc = iframeWindow.document;
277
+
278
+ try {
279
+ doc = iframeDoc
280
+ } catch (c) {
281
+ domain = window.document.domain,
282
+ iframe.src = 'javascript:var doc=document.open();doc.domain="' + domain + '";void(0);',
283
+ doc = iframeDoc
284
+ }
285
+
286
+ doc.open().start = function() {
287
+ if(output)
288
+ {
289
+ if(typeof output === 'object')
290
+ {
291
+ output.iframeWindow = iframeWindow;
292
+ }
293
+ else if(typeof output === 'function')
294
+ {
295
+ output(iframeWindow);
296
+ }
297
+ }
298
+ },
299
+
300
+ doc.write('<body onload="document.start();">'),
301
+ doc.write('<script src="' + mainJS + '""></script>'),
302
+ doc.close();
303
+ }
304
+
305
+ function getStyle(el, style)
306
+ {
307
+ var
308
+ pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source,
309
+ rmargin = /^margin/,
310
+ rposition = /^(top|right|bottom|left)$/,
311
+ rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ),
312
+
313
+ getStyles, curCSS;
314
+
315
+ if ( window.getComputedStyle ) {
316
+ getStyles = function( elem ) {
317
+ return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
318
+ };
319
+
320
+ curCSS = function( elem, name, computed ) {
321
+ var width, minWidth, maxWidth, ret,
322
+ style = elem.style;
323
+
324
+ computed = computed || getStyles( elem );
325
+
326
+ // getPropertyValue is only needed for .css('filter') in IE9, see #12537
327
+ ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined;
328
+
329
+ if ( computed ) {
330
+
331
+ // if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
332
+ // ret = jQuery.style( elem, name );
333
+ // }
334
+
335
+ // A tribute to the "awesome hack by Dean Edwards"
336
+ // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
337
+ // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
338
+ // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
339
+ if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
340
+
341
+ // Remember the original values
342
+ width = style.width;
343
+ minWidth = style.minWidth;
344
+ maxWidth = style.maxWidth;
345
+
346
+ // Put in the new values to get a computed value out
347
+ style.minWidth = style.maxWidth = style.width = ret;
348
+ ret = computed.width;
349
+
350
+ // Revert the changed values
351
+ style.width = width;
352
+ style.minWidth = minWidth;
353
+ style.maxWidth = maxWidth;
354
+ }
355
+ }
356
+
357
+ // Support: IE
358
+ // IE returns zIndex value as an integer.
359
+ return ret === undefined ?
360
+ ret :
361
+ ret + "";
362
+ };
363
+ } else if ( document.documentElement.currentStyle ) {
364
+ getStyles = function( elem ) {
365
+ return elem.currentStyle;
366
+ };
367
+
368
+ curCSS = function( elem, name, computed ) {
369
+ var left, rs, rsLeft, ret,
370
+ style = elem.style;
371
+
372
+ computed = computed || getStyles( elem );
373
+ ret = computed ? computed[ name ] : undefined;
374
+
375
+ // Avoid setting ret to empty string here
376
+ // so we don't default to auto
377
+ if ( ret == null && style && style[ name ] ) {
378
+ ret = style[ name ];
379
+ }
380
+
381
+ // From the awesome hack by Dean Edwards
382
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
383
+
384
+ // If we're not dealing with a regular pixel number
385
+ // but a number that has a weird ending, we need to convert it to pixels
386
+ // but not position css attributes, as those are proportional to the parent element instead
387
+ // and we can't measure the parent instead because it might trigger a "stacking dolls" problem
388
+ if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
389
+
390
+ // Remember the original values
391
+ left = style.left;
392
+ rs = elem.runtimeStyle;
393
+ rsLeft = rs && rs.left;
394
+
395
+ // Put in the new values to get a computed value out
396
+ if ( rsLeft ) {
397
+ rs.left = elem.currentStyle.left;
398
+ }
399
+ style.left = name === "fontSize" ? "1em" : ret;
400
+ ret = style.pixelLeft + "px";
401
+
402
+ // Revert the changed values
403
+ style.left = left;
404
+ if ( rsLeft ) {
405
+ rs.left = rsLeft;
406
+ }
407
+ }
408
+
409
+ // Support: IE
410
+ // IE returns zIndex value as an integer.
411
+ return ret === undefined ?
412
+ ret :
413
+ ret + "" || "auto";
414
+ };
415
+ }
416
+
417
+ return curCSS && curCSS(el, style);
418
+ }
419
+
420
+ function slideUp(elem, duration)
421
+ {
422
+ var originalStyle = elem.getAttribute('style');
423
+ elem.style.display = 'block';
424
+ var originalHeight = parseInt(getStyle(elem, 'height'));
425
+
426
+ elem.style.height = '0px';
427
+
428
+ duration = duration || 500;
429
+ var tStart = Date.now(),
430
+ cost = 0,
431
+ timer = setInterval(function()
432
+ {
433
+ cost = (Date.now() - tStart) / duration;
434
+ cost = cost > 1 ? 1 : cost;
435
+
436
+ elem.style.height = cost * originalHeight + 'px';
437
+
438
+ if(cost >= 1)
439
+ {
440
+ clearInterval(timer);
441
+ timer = null;
442
+
443
+ if(originalStyle)
444
+ {
445
+ elem.setAttribute('style', originalStyle);
446
+ }
447
+ else
448
+ {
449
+ elem.removeAttribute('style');
450
+ }
451
+ elem.style.display = 'block';
452
+ }
453
+ }, 1000 / 60);
454
+ }
455
+
456
+ function slideDown(elem, duration)
457
+ {
458
+ var originalStyle = elem.getAttribute('style');
459
+ elem.style.display = 'block';
460
+
461
+ var originalHeight = parseInt(getStyle(elem, 'height'));
462
+
463
+ duration = duration || 500;
464
+ var tStart = Date.now(),
465
+ cost = 0,
466
+ timer = setInterval(function()
467
+ {
468
+ cost = (Date.now() - tStart) / duration;
469
+ cost = cost > 1 ? 1 : cost;
470
+
471
+ elem.style.height = (1 - cost) * originalHeight + 'px';
472
+
473
+ if(cost >= 1)
474
+ {
475
+ clearInterval(timer);
476
+ timer = null;
477
+
478
+ if(originalStyle)
479
+ {
480
+ elem.setAttribute('style', originalStyle);
481
+ }
482
+ else
483
+ {
484
+ elem.removeAttribute('style');
485
+ }
486
+ elem.style.display = 'none';
487
+ }
488
+ }, 1000 / 60);
489
+ }
490
+
491
+ function hideElement(el)
492
+ {
493
+ el.style.display = 'none';
494
+ }
495
+
496
+ function showElement(el)
497
+ {
498
+ el.style.display = 'block';
499
+ }
500
+
501
+ function cookie(name, value, options)
502
+ {
503
+ if (typeof value != 'undefined')
504
+ { // name and value given, set cookie
505
+ options = options || {};
506
+ if (value === null) {
507
+ value = '';
508
+ options.expires = -1;
509
+ }
510
+ var expires = '';
511
+ if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
512
+ var date;
513
+ if (typeof options.expires == 'number') {
514
+ date = new Date();
515
+ date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
516
+ } else {
517
+ date = options.expires;
518
+ }
519
+ expires = '; expires=' + date.toUTCString();
520
+ }
521
+ var path = options.path ? '; path=' + (options.path) : '';
522
+ var domain = options.domain ? '; domain=' + (options.domain) : '';
523
+ var secure = options.secure ? '; secure' : '';
524
+ document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
525
+ } else {
526
+ var cookieValue = null;
527
+ if (document.cookie && document.cookie != '') {
528
+ var cookies = document.cookie.split(';');
529
+ for (var i = 0; i < cookies.length; i++) {
530
+ var cookie = cookies[i].replace(/^\s+|\s+$/g, '');
531
+ if (cookie.substring(0, name.length + 1) == (name + '=')) {
532
+ cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
533
+ break;
534
+ }
535
+ }
536
+ }
537
+ return cookieValue;
538
+ }
539
+ }
540
+
541
+ function isPC()
542
+ {
543
+ var userAgentInfo = navigator.userAgent;
544
+ var Agents = ['Android', 'iPhone',
545
+ 'SymbianOS', 'Windows Phone',
546
+ 'iPad', 'iPod'];
547
+ var flag = true;
548
+
549
+ for(var i = 0; i < Agents.length; i++)
550
+ {
551
+ if(userAgentInfo.indexOf(Agents[i]) !== -1)
552
+ {
553
+ flag = false;
554
+ break;
555
+ }
556
+ }
557
+
558
+ return flag;
559
+ }
560
+
561
+ })(window);
data/lib/kf5.rb CHANGED
@@ -5,6 +5,7 @@ require "kf5/version"
5
5
  require "kf5/configuration"
6
6
  require "kf5/properties"
7
7
  require "kf5/helper"
8
+ require "kf5/view_helper"
8
9
 
9
10
  module KF5
10
11
  def self.configure(&block)
@@ -21,6 +22,10 @@ module KF5
21
22
  ActiveSupport.on_load :action_controller do
22
23
  include KF5::Helper
23
24
  end
25
+ ActiveSupport.on_load :action_view do
26
+ include KF5::ViewHelper
27
+ end
28
+ Rails.application.config.assets.precompile += %w( kf5.js )
24
29
  end
25
30
  end
26
31
  end
@@ -1,3 +1,3 @@
1
1
  module KF5
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -0,0 +1,7 @@
1
+ module KF5
2
+ module ViewHelper
3
+ def kf5_tag
4
+ javascript_include_tag "kf5.js", :id => "kf5-provide-supportBox", :"kf5-domain" => "#{KF5.configuration.domain}.kf5.com"
5
+ end
6
+ end
7
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kf5
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chen Yi-Cyuan
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-09-03 00:00:00.000000000 Z
11
+ date: 2015-09-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -75,18 +75,21 @@ extra_rdoc_files: []
75
75
  files:
76
76
  - ".gitignore"
77
77
  - ".rspec"
78
+ - ".travis.yml"
78
79
  - CHANGELOG.md
79
80
  - Gemfile
80
81
  - Gemfile.lock
81
82
  - LICENSE.txt
82
83
  - README.md
83
84
  - Rakefile
85
+ - app/assets/javascripts/kf5.js
84
86
  - kf5.gemspec
85
87
  - lib/kf5.rb
86
88
  - lib/kf5/configuration.rb
87
89
  - lib/kf5/helper.rb
88
90
  - lib/kf5/properties.rb
89
91
  - lib/kf5/version.rb
92
+ - lib/kf5/view_helper.rb
90
93
  homepage: https://github.com/emn178/kf5
91
94
  licenses:
92
95
  - MIT