camaleon_cms_rating 0.1.0

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.
Files changed (29) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +38 -0
  4. data/Rakefile +37 -0
  5. data/app/assets/config/camaleon_cms_rating_manifest.js +0 -0
  6. data/app/assets/images/plugins/camaleon_cms_rating/star-half.png +0 -0
  7. data/app/assets/images/plugins/camaleon_cms_rating/star-off.png +0 -0
  8. data/app/assets/images/plugins/camaleon_cms_rating/star-on.png +0 -0
  9. data/app/assets/javascripts/plugins/camaleon_cms_rating/jquery.raty.js +762 -0
  10. data/app/assets/javascripts/plugins/camaleon_cms_rating/main.js +31 -0
  11. data/app/controllers/plugins/camaleon_cms_rating/admin_controller.rb +19 -0
  12. data/app/controllers/plugins/camaleon_cms_rating/front_controller.rb +18 -0
  13. data/app/helpers/plugins/camaleon_cms_rating/main_helper.rb +29 -0
  14. data/app/models/plugins/camaleon_cms_rating/rating.rb +8 -0
  15. data/app/views/plugins/camaleon_cms_rating/admin/index.html.erb +9 -0
  16. data/app/views/plugins/camaleon_cms_rating/admin/settings.html.erb +21 -0
  17. data/app/views/plugins/camaleon_cms_rating/front/_index.html.erb +19 -0
  18. data/app/views/plugins/camaleon_cms_rating/front/_new.html.erb +1 -0
  19. data/app/views/plugins/camaleon_cms_rating/front/index.html.erb +2 -0
  20. data/app/views/plugins/camaleon_cms_rating/layouts/readme.txt +2 -0
  21. data/config/camaleon_plugin.json +14 -0
  22. data/config/initializers/custom_models.rb +5 -0
  23. data/config/routes.rb +31 -0
  24. data/db/migrate/20170812143133_create_camaleon_cms_rating_ratings.rb +9 -0
  25. data/lib/camaleon_cms_rating.rb +5 -0
  26. data/lib/camaleon_cms_rating/engine.rb +4 -0
  27. data/lib/camaleon_cms_rating/version.rb +3 -0
  28. data/lib/tasks/camaleon_cms_rating_tasks.rake +4 -0
  29. metadata +99 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e3a0c3fbcbbdf63e5820be68221622a77ae2ea71
4
+ data.tar.gz: 68d1ae70ad03ff567ad780c6a4c1a92f91cdd492
5
+ SHA512:
6
+ metadata.gz: b814077798bef9d0e1a8b63876cfb482fc2d88ead276db4afe727743c7ca0d268a82cb0c9798eac238a5ef075a67cd7286ab3f0c8232c99fa9b0a72d1da7d563
7
+ data.tar.gz: aaf9c71a4743c9ec92b45eaca3e60c26826ff487c8d154688426ff5d7a506d7e9c3725afeed13077edfe6adfa82bb00aacd1458362e598f12303458283cca961
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2017 Richard Li
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # Camaleon CMS Rating
2
+ A star rating plugin for the Camaleon CMS.
3
+
4
+ ## Preview
5
+ ![](art/preview.png)
6
+
7
+ ## Usage
8
+ ```erb
9
+ <!-- including scripts into the layout file -->
10
+ <%= javascript_include_tag plugin_asset_path('main', 'camaleon_cms_rating') %>
11
+
12
+ <!-- including partials into the post template file -->
13
+ <%= render partial: plugin_view('front/index', 'camaleon_cms_rating'), locals: { post: @post } %>
14
+ <%= render partial: plugin_view('front/new', 'camaleon_cms_rating'), locals: { post: @post } %>
15
+ ```
16
+
17
+ ## Installation
18
+ Add this line to your application's Gemfile:
19
+
20
+ ```ruby
21
+ gem 'camaleon_cms_rating'
22
+ ```
23
+
24
+ And then execute:
25
+ ```bash
26
+ $ bundle
27
+ ```
28
+
29
+ Or install it yourself as:
30
+ ```bash
31
+ $ gem install camaleon_cms_rating
32
+ ```
33
+
34
+ ## Contributing
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/aspirewit/camaleon_cms_rating. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
36
+
37
+ ## License
38
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'CamaleonCmsRating'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+
25
+ require 'bundler/gem_tasks'
26
+
27
+ require 'rake/testtask'
28
+
29
+ Rake::TestTask.new(:test) do |t|
30
+ t.libs << 'lib'
31
+ t.libs << 'test'
32
+ t.pattern = 'test/**/*_test.rb'
33
+ t.verbose = false
34
+ end
35
+
36
+
37
+ task default: :test
File without changes
@@ -0,0 +1,762 @@
1
+ /*!
2
+ * jQuery Raty - A Star Rating Plugin
3
+ *
4
+ * The MIT License
5
+ *
6
+ * @author : Washington Botelho
7
+ * @doc : http://wbotelhos.com/raty
8
+ * @version : 2.7.1
9
+ *
10
+ */
11
+
12
+ ;
13
+ (function($) {
14
+ 'use strict';
15
+
16
+ var methods = {
17
+ init: function(options) {
18
+ return this.each(function() {
19
+ this.self = $(this);
20
+
21
+ methods.destroy.call(this.self);
22
+
23
+ this.opt = $.extend(true, {}, $.fn.raty.defaults, options);
24
+
25
+ methods._adjustCallback.call(this);
26
+ methods._adjustNumber.call(this);
27
+ methods._adjustHints.call(this);
28
+
29
+ this.opt.score = methods._adjustedScore.call(this, this.opt.score);
30
+
31
+ if (this.opt.starType !== 'img') {
32
+ methods._adjustStarType.call(this);
33
+ }
34
+
35
+ methods._adjustPath.call(this);
36
+ methods._createStars.call(this);
37
+
38
+ if (this.opt.cancel) {
39
+ methods._createCancel.call(this);
40
+ }
41
+
42
+ if (this.opt.precision) {
43
+ methods._adjustPrecision.call(this);
44
+ }
45
+
46
+ methods._createScore.call(this);
47
+ methods._apply.call(this, this.opt.score);
48
+ methods._setTitle.call(this, this.opt.score);
49
+ methods._target.call(this, this.opt.score);
50
+
51
+ if (this.opt.readOnly) {
52
+ methods._lock.call(this);
53
+ } else {
54
+ this.style.cursor = 'pointer';
55
+
56
+ methods._binds.call(this);
57
+ }
58
+ });
59
+ },
60
+
61
+ _adjustCallback: function() {
62
+ var options = ['number', 'readOnly', 'score', 'scoreName', 'target', 'path'];
63
+
64
+ for (var i = 0; i < options.length; i++) {
65
+ if (typeof this.opt[options[i]] === 'function') {
66
+ this.opt[options[i]] = this.opt[options[i]].call(this);
67
+ }
68
+ }
69
+ },
70
+
71
+ _adjustedScore: function(score) {
72
+ if (!score) {
73
+ return score;
74
+ }
75
+
76
+ return methods._between(score, 0, this.opt.number);
77
+ },
78
+
79
+ _adjustHints: function() {
80
+ if (!this.opt.hints) {
81
+ this.opt.hints = [];
82
+ }
83
+
84
+ if (!this.opt.halfShow && !this.opt.half) {
85
+ return;
86
+ }
87
+
88
+ var steps = this.opt.precision ? 10 : 2;
89
+
90
+ for (var i = 0; i < this.opt.number; i++) {
91
+ var group = this.opt.hints[i];
92
+
93
+ if (Object.prototype.toString.call(group) !== '[object Array]') {
94
+ group = [group];
95
+ }
96
+
97
+ this.opt.hints[i] = [];
98
+
99
+ for (var j = 0; j < steps; j++) {
100
+ var
101
+ hint = group[j],
102
+ last = group[group.length - 1];
103
+
104
+ if (last === undefined) {
105
+ last = null;
106
+ }
107
+
108
+ this.opt.hints[i][j] = hint === undefined ? last : hint;
109
+ }
110
+ }
111
+ },
112
+
113
+ _adjustNumber: function() {
114
+ this.opt.number = methods._between(this.opt.number, 1, this.opt.numberMax);
115
+ },
116
+
117
+ _adjustPath: function() {
118
+ this.opt.path = this.opt.path || '';
119
+
120
+ if (this.opt.path && this.opt.path.charAt(this.opt.path.length - 1) !== '/') {
121
+ this.opt.path += '/';
122
+ }
123
+ },
124
+
125
+ _adjustPrecision: function() {
126
+ this.opt.half = true;
127
+ },
128
+
129
+ _adjustStarType: function() {
130
+ var replaces = ['cancelOff', 'cancelOn', 'starHalf', 'starOff', 'starOn'];
131
+
132
+ this.opt.path = '';
133
+
134
+ for (var i = 0; i < replaces.length; i++) {
135
+ this.opt[replaces[i]] = this.opt[replaces[i]].replace('.', '-');
136
+ }
137
+ },
138
+
139
+ _apply: function(score) {
140
+ methods._fill.call(this, score);
141
+
142
+ if (score) {
143
+ if (score > 0) {
144
+ this.score.val(score);
145
+ }
146
+
147
+ methods._roundStars.call(this, score);
148
+ }
149
+ },
150
+
151
+ _between: function(value, min, max) {
152
+ return Math.min(Math.max(parseFloat(value), min), max);
153
+ },
154
+
155
+ _binds: function() {
156
+ if (this.cancel) {
157
+ methods._bindOverCancel.call(this);
158
+ methods._bindClickCancel.call(this);
159
+ methods._bindOutCancel.call(this);
160
+ }
161
+
162
+ methods._bindOver.call(this);
163
+ methods._bindClick.call(this);
164
+ methods._bindOut.call(this);
165
+ },
166
+
167
+ _bindClick: function() {
168
+ var that = this;
169
+
170
+ that.stars.on('click.raty', function(evt) {
171
+ var
172
+ execute = true,
173
+ score = (that.opt.half || that.opt.precision) ? that.self.data('score') : (this.alt || $(this).data('alt'));
174
+
175
+ if (that.opt.click) {
176
+ execute = that.opt.click.call(that, +score, evt);
177
+ }
178
+
179
+ if (execute || execute === undefined) {
180
+ if (that.opt.half && !that.opt.precision) {
181
+ score = methods._roundHalfScore.call(that, score);
182
+ }
183
+
184
+ methods._apply.call(that, score);
185
+ }
186
+ });
187
+ },
188
+
189
+ _bindClickCancel: function() {
190
+ var that = this;
191
+
192
+ that.cancel.on('click.raty', function(evt) {
193
+ that.score.removeAttr('value');
194
+
195
+ if (that.opt.click) {
196
+ that.opt.click.call(that, null, evt);
197
+ }
198
+ });
199
+ },
200
+
201
+ _bindOut: function() {
202
+ var that = this;
203
+
204
+ that.self.on('mouseleave.raty', function(evt) {
205
+ var score = +that.score.val() || undefined;
206
+
207
+ methods._apply.call(that, score);
208
+ methods._target.call(that, score, evt);
209
+ methods._resetTitle.call(that);
210
+
211
+ if (that.opt.mouseout) {
212
+ that.opt.mouseout.call(that, score, evt);
213
+ }
214
+ });
215
+ },
216
+
217
+ _bindOutCancel: function() {
218
+ var that = this;
219
+
220
+ that.cancel.on('mouseleave.raty', function(evt) {
221
+ var icon = that.opt.cancelOff;
222
+
223
+ if (that.opt.starType !== 'img') {
224
+ icon = that.opt.cancelClass + ' ' + icon;
225
+ }
226
+
227
+ methods._setIcon.call(that, this, icon);
228
+
229
+ if (that.opt.mouseout) {
230
+ var score = +that.score.val() || undefined;
231
+
232
+ that.opt.mouseout.call(that, score, evt);
233
+ }
234
+ });
235
+ },
236
+
237
+ _bindOver: function() {
238
+ var
239
+ that = this,
240
+ action = that.opt.half ? 'mousemove.raty' : 'mouseover.raty';
241
+
242
+ that.stars.on(action, function(evt) {
243
+ var score = methods._getScoreByPosition.call(that, evt, this);
244
+
245
+ methods._fill.call(that, score);
246
+
247
+ if (that.opt.half) {
248
+ methods._roundStars.call(that, score, evt);
249
+ methods._setTitle.call(that, score, evt);
250
+
251
+ that.self.data('score', score);
252
+ }
253
+
254
+ methods._target.call(that, score, evt);
255
+
256
+ if (that.opt.mouseover) {
257
+ that.opt.mouseover.call(that, score, evt);
258
+ }
259
+ });
260
+ },
261
+
262
+ _bindOverCancel: function() {
263
+ var that = this;
264
+
265
+ that.cancel.on('mouseover.raty', function(evt) {
266
+ var
267
+ starOff = that.opt.path + that.opt.starOff,
268
+ icon = that.opt.cancelOn;
269
+
270
+ if (that.opt.starType === 'img') {
271
+ that.stars.attr('src', starOff);
272
+ } else {
273
+ icon = that.opt.cancelClass + ' ' + icon;
274
+
275
+ that.stars.attr('class', starOff);
276
+ }
277
+
278
+ methods._setIcon.call(that, this, icon);
279
+ methods._target.call(that, null, evt);
280
+
281
+ if (that.opt.mouseover) {
282
+ that.opt.mouseover.call(that, null);
283
+ }
284
+ });
285
+ },
286
+
287
+ _buildScoreField: function() {
288
+ return $('<input />', { name: this.opt.scoreName, type: 'hidden' }).appendTo(this);
289
+ },
290
+
291
+ _createCancel: function() {
292
+ var
293
+ icon = this.opt.path + this.opt.cancelOff,
294
+ cancel = $('<' + this.opt.starType + ' />', { title: this.opt.cancelHint, 'class': this.opt.cancelClass });
295
+
296
+ if (this.opt.starType === 'img') {
297
+ cancel.attr({ src: icon, alt: 'x' });
298
+ } else {
299
+ // TODO: use $.data
300
+ cancel.attr('data-alt', 'x').addClass(icon);
301
+ }
302
+
303
+ if (this.opt.cancelPlace === 'left') {
304
+ this.self.prepend('&#160;').prepend(cancel);
305
+ } else {
306
+ this.self.append('&#160;').append(cancel);
307
+ }
308
+
309
+ this.cancel = cancel;
310
+ },
311
+
312
+ _createScore: function() {
313
+ var score = $(this.opt.targetScore);
314
+
315
+ this.score = score.length ? score : methods._buildScoreField.call(this);
316
+ },
317
+
318
+ _createStars: function() {
319
+ for (var i = 1; i <= this.opt.number; i++) {
320
+ var
321
+ name = methods._nameForIndex.call(this, i),
322
+ attrs = { alt: i, src: this.opt.path + this.opt[name] };
323
+
324
+ if (this.opt.starType !== 'img') {
325
+ attrs = { 'data-alt': i, 'class': attrs.src }; // TODO: use $.data.
326
+ }
327
+
328
+ attrs.title = methods._getHint.call(this, i);
329
+
330
+ $('<' + this.opt.starType + ' />', attrs).appendTo(this);
331
+
332
+ if (this.opt.space) {
333
+ this.self.append(i < this.opt.number ? '&#160;' : '');
334
+ }
335
+ }
336
+
337
+ this.stars = this.self.children(this.opt.starType);
338
+ },
339
+
340
+ _error: function(message) {
341
+ $(this).text(message);
342
+
343
+ $.error(message);
344
+ },
345
+
346
+ _fill: function(score) {
347
+ var hash = 0;
348
+
349
+ for (var i = 1; i <= this.stars.length; i++) {
350
+ var
351
+ icon,
352
+ star = this.stars[i - 1],
353
+ turnOn = methods._turnOn.call(this, i, score);
354
+
355
+ if (this.opt.iconRange && this.opt.iconRange.length > hash) {
356
+ var irange = this.opt.iconRange[hash];
357
+
358
+ icon = methods._getRangeIcon.call(this, irange, turnOn);
359
+
360
+ if (i <= irange.range) {
361
+ methods._setIcon.call(this, star, icon);
362
+ }
363
+
364
+ if (i === irange.range) {
365
+ hash++;
366
+ }
367
+ } else {
368
+ icon = this.opt[turnOn ? 'starOn' : 'starOff'];
369
+
370
+ methods._setIcon.call(this, star, icon);
371
+ }
372
+ }
373
+ },
374
+
375
+ _getFirstDecimal: function(number) {
376
+ var
377
+ decimal = number.toString().split('.')[1],
378
+ result = 0;
379
+
380
+ if (decimal) {
381
+ result = parseInt(decimal.charAt(0), 10);
382
+
383
+ if (decimal.slice(1, 5) === '9999') {
384
+ result++;
385
+ }
386
+ }
387
+
388
+ return result;
389
+ },
390
+
391
+ _getRangeIcon: function(irange, turnOn) {
392
+ return turnOn ? irange.on || this.opt.starOn : irange.off || this.opt.starOff;
393
+ },
394
+
395
+ _getScoreByPosition: function(evt, icon) {
396
+ var score = parseInt(icon.alt || icon.getAttribute('data-alt'), 10);
397
+
398
+ if (this.opt.half) {
399
+ var
400
+ size = methods._getWidth.call(this),
401
+ percent = parseFloat((evt.pageX - $(icon).offset().left) / size);
402
+
403
+ score = score - 1 + percent;
404
+ }
405
+
406
+ return score;
407
+ },
408
+
409
+ _getHint: function(score, evt) {
410
+ if (score !== 0 && !score) {
411
+ return this.opt.noRatedMsg;
412
+ }
413
+
414
+ var
415
+ decimal = methods._getFirstDecimal.call(this, score),
416
+ integer = Math.ceil(score),
417
+ group = this.opt.hints[(integer || 1) - 1],
418
+ hint = group,
419
+ set = !evt || this.move;
420
+
421
+ if (this.opt.precision) {
422
+ if (set) {
423
+ decimal = decimal === 0 ? 9 : decimal - 1;
424
+ }
425
+
426
+ hint = group[decimal];
427
+ } else if (this.opt.halfShow || this.opt.half) {
428
+ decimal = set && decimal === 0 ? 1 : decimal > 5 ? 1 : 0;
429
+
430
+ hint = group[decimal];
431
+ }
432
+
433
+ return hint === '' ? '' : hint || score;
434
+ },
435
+
436
+ _getWidth: function() {
437
+ var width = this.stars[0].width || parseFloat(this.stars.eq(0).css('font-size'));
438
+
439
+ if (!width) {
440
+ methods._error.call(this, 'Could not get the icon width!');
441
+ }
442
+
443
+ return width;
444
+ },
445
+
446
+ _lock: function() {
447
+ var hint = methods._getHint.call(this, this.score.val());
448
+
449
+ this.style.cursor = '';
450
+ this.title = hint;
451
+
452
+ this.score.prop('readonly', true);
453
+ this.stars.prop('title', hint);
454
+
455
+ if (this.cancel) {
456
+ this.cancel.hide();
457
+ }
458
+
459
+ this.self.data('readonly', true);
460
+ },
461
+
462
+ _nameForIndex: function(i) {
463
+ return this.opt.score && this.opt.score >= i ? 'starOn' : 'starOff';
464
+ },
465
+
466
+ _resetTitle: function(star) {
467
+ for (var i = 0; i < this.opt.number; i++) {
468
+ this.stars[i].title = methods._getHint.call(this, i + 1);
469
+ }
470
+ },
471
+
472
+ _roundHalfScore: function(score) {
473
+ var integer = parseInt(score, 10),
474
+ decimal = methods._getFirstDecimal.call(this, score);
475
+
476
+ if (decimal !== 0) {
477
+ decimal = decimal > 5 ? 1 : 0.5;
478
+ }
479
+
480
+ return integer + decimal;
481
+ },
482
+
483
+ _roundStars: function(score, evt) {
484
+ var
485
+ decimal = (score % 1).toFixed(2),
486
+ name ;
487
+
488
+ if (evt || this.move) {
489
+ name = decimal > 0.5 ? 'starOn' : 'starHalf';
490
+ } else if (decimal > this.opt.round.down) { // Up: [x.76 .. x.99]
491
+ name = 'starOn';
492
+
493
+ if (this.opt.halfShow && decimal < this.opt.round.up) { // Half: [x.26 .. x.75]
494
+ name = 'starHalf';
495
+ } else if (decimal < this.opt.round.full) { // Down: [x.00 .. x.5]
496
+ name = 'starOff';
497
+ }
498
+ }
499
+
500
+ if (name) {
501
+ var
502
+ icon = this.opt[name],
503
+ star = this.stars[Math.ceil(score) - 1];
504
+
505
+ methods._setIcon.call(this, star, icon);
506
+ } // Full down: [x.00 .. x.25]
507
+ },
508
+
509
+ _setIcon: function(star, icon) {
510
+ star[this.opt.starType === 'img' ? 'src' : 'className'] = this.opt.path + icon;
511
+ },
512
+
513
+ _setTarget: function(target, score) {
514
+ if (score) {
515
+ score = this.opt.targetFormat.toString().replace('{score}', score);
516
+ }
517
+
518
+ if (target.is(':input')) {
519
+ target.val(score);
520
+ } else {
521
+ target.html(score);
522
+ }
523
+ },
524
+
525
+ _setTitle: function(score, evt) {
526
+ if (score) {
527
+ var
528
+ integer = parseInt(Math.ceil(score), 10),
529
+ star = this.stars[integer - 1];
530
+
531
+ star.title = methods._getHint.call(this, score, evt);
532
+ }
533
+ },
534
+
535
+ _target: function(score, evt) {
536
+ if (this.opt.target) {
537
+ var target = $(this.opt.target);
538
+
539
+ if (!target.length) {
540
+ methods._error.call(this, 'Target selector invalid or missing!');
541
+ }
542
+
543
+ var mouseover = evt && evt.type === 'mouseover';
544
+
545
+ if (score === undefined) {
546
+ score = this.opt.targetText;
547
+ } else if (score === null) {
548
+ score = mouseover ? this.opt.cancelHint : this.opt.targetText;
549
+ } else {
550
+ if (this.opt.targetType === 'hint') {
551
+ score = methods._getHint.call(this, score, evt);
552
+ } else if (this.opt.precision) {
553
+ score = parseFloat(score).toFixed(1);
554
+ }
555
+
556
+ var mousemove = evt && evt.type === 'mousemove';
557
+
558
+ if (!mouseover && !mousemove && !this.opt.targetKeep) {
559
+ score = this.opt.targetText;
560
+ }
561
+ }
562
+
563
+ methods._setTarget.call(this, target, score);
564
+ }
565
+ },
566
+
567
+ _turnOn: function(i, score) {
568
+ return this.opt.single ? (i === score) : (i <= score);
569
+ },
570
+
571
+ _unlock: function() {
572
+ this.style.cursor = 'pointer';
573
+ this.removeAttribute('title');
574
+
575
+ this.score.removeAttr('readonly');
576
+
577
+ this.self.data('readonly', false);
578
+
579
+ for (var i = 0; i < this.opt.number; i++) {
580
+ this.stars[i].title = methods._getHint.call(this, i + 1);
581
+ }
582
+
583
+ if (this.cancel) {
584
+ this.cancel.css('display', '');
585
+ }
586
+ },
587
+
588
+ cancel: function(click) {
589
+ return this.each(function() {
590
+ var self = $(this);
591
+
592
+ if (self.data('readonly') !== true) {
593
+ methods[click ? 'click' : 'score'].call(self, null);
594
+
595
+ this.score.removeAttr('value');
596
+ }
597
+ });
598
+ },
599
+
600
+ click: function(score) {
601
+ return this.each(function() {
602
+ if ($(this).data('readonly') !== true) {
603
+ score = methods._adjustedScore.call(this, score);
604
+
605
+ methods._apply.call(this, score);
606
+
607
+ if (this.opt.click) {
608
+ this.opt.click.call(this, score, $.Event('click'));
609
+ }
610
+
611
+ methods._target.call(this, score);
612
+ }
613
+ });
614
+ },
615
+
616
+ destroy: function() {
617
+ return this.each(function() {
618
+ var self = $(this),
619
+ raw = self.data('raw');
620
+
621
+ if (raw) {
622
+ self.off('.raty').empty().css({ cursor: raw.style.cursor }).removeData('readonly');
623
+ } else {
624
+ self.data('raw', self.clone()[0]);
625
+ }
626
+ });
627
+ },
628
+
629
+ getScore: function() {
630
+ var score = [],
631
+ value ;
632
+
633
+ this.each(function() {
634
+ value = this.score.val();
635
+
636
+ score.push(value ? +value : undefined);
637
+ });
638
+
639
+ return (score.length > 1) ? score : score[0];
640
+ },
641
+
642
+ move: function(score) {
643
+ return this.each(function() {
644
+ var
645
+ integer = parseInt(score, 10),
646
+ decimal = methods._getFirstDecimal.call(this, score);
647
+
648
+ if (integer >= this.opt.number) {
649
+ integer = this.opt.number - 1;
650
+ decimal = 10;
651
+ }
652
+
653
+ var
654
+ width = methods._getWidth.call(this),
655
+ steps = width / 10,
656
+ star = $(this.stars[integer]),
657
+ percent = star.offset().left + steps * decimal,
658
+ evt = $.Event('mousemove', { pageX: percent });
659
+
660
+ this.move = true;
661
+
662
+ star.trigger(evt);
663
+
664
+ this.move = false;
665
+ });
666
+ },
667
+
668
+ readOnly: function(readonly) {
669
+ return this.each(function() {
670
+ var self = $(this);
671
+
672
+ if (self.data('readonly') !== readonly) {
673
+ if (readonly) {
674
+ self.off('.raty').children(this.opt.starType).off('.raty');
675
+
676
+ methods._lock.call(this);
677
+ } else {
678
+ methods._binds.call(this);
679
+ methods._unlock.call(this);
680
+ }
681
+
682
+ self.data('readonly', readonly);
683
+ }
684
+ });
685
+ },
686
+
687
+ reload: function() {
688
+ return methods.set.call(this, {});
689
+ },
690
+
691
+ score: function() {
692
+ var self = $(this);
693
+
694
+ return arguments.length ? methods.setScore.apply(self, arguments) : methods.getScore.call(self);
695
+ },
696
+
697
+ set: function(options) {
698
+ return this.each(function() {
699
+ $(this).raty($.extend({}, this.opt, options));
700
+ });
701
+ },
702
+
703
+ setScore: function(score) {
704
+ return this.each(function() {
705
+ if ($(this).data('readonly') !== true) {
706
+ score = methods._adjustedScore.call(this, score);
707
+
708
+ methods._apply.call(this, score);
709
+ methods._target.call(this, score);
710
+ }
711
+ });
712
+ }
713
+ };
714
+
715
+ $.fn.raty = function(method) {
716
+ if (methods[method]) {
717
+ return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
718
+ } else if (typeof method === 'object' || !method) {
719
+ return methods.init.apply(this, arguments);
720
+ } else {
721
+ $.error('Method ' + method + ' does not exist!');
722
+ }
723
+ };
724
+
725
+ $.fn.raty.defaults = {
726
+ cancel : false,
727
+ cancelClass : 'raty-cancel',
728
+ cancelHint : 'Cancel this rating!',
729
+ cancelOff : 'cancel-off.png',
730
+ cancelOn : 'cancel-on.png',
731
+ cancelPlace : 'left',
732
+ click : undefined,
733
+ half : false,
734
+ halfShow : true,
735
+ hints : ['bad', 'poor', 'regular', 'good', 'gorgeous'],
736
+ iconRange : undefined,
737
+ mouseout : undefined,
738
+ mouseover : undefined,
739
+ noRatedMsg : 'Not rated yet!',
740
+ number : 5,
741
+ numberMax : 20,
742
+ path : undefined,
743
+ precision : false,
744
+ readOnly : false,
745
+ round : { down: 0.25, full: 0.6, up: 0.76 },
746
+ score : undefined,
747
+ scoreName : 'score',
748
+ single : false,
749
+ space : true,
750
+ starHalf : 'star-half.png',
751
+ starOff : 'star-off.png',
752
+ starOn : 'star-on.png',
753
+ starType : 'img',
754
+ target : undefined,
755
+ targetFormat : '{score}',
756
+ targetKeep : false,
757
+ targetScore : undefined,
758
+ targetText : '',
759
+ targetType : 'hint'
760
+ };
761
+
762
+ })(jQuery);
@@ -0,0 +1,31 @@
1
+ //= require ./jquery.raty
2
+ //
3
+ jQuery(function(){
4
+ $.ajaxSetup({
5
+ beforeSend: function(xhr) {
6
+ xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
7
+ }
8
+ });
9
+
10
+ $('.read-only-rating').raty({
11
+ path: '/assets/plugins/camaleon_cms_rating',
12
+ readOnly: true,
13
+ score: function() {
14
+ return $(this).data('score');
15
+ }
16
+ });
17
+
18
+ $('.editable-rating').raty({
19
+ path: '/assets/plugins/camaleon_cms_rating',
20
+ click: function(score, event) {
21
+ $this = $(this);
22
+ $this.raty({
23
+ path: '/assets/plugins/camaleon_cms_rating',
24
+ readOnly: true
25
+ });
26
+
27
+ data = { post_id: $this.data('post-id'), score: score };
28
+ $.post("/plugins/camaleon_cms_rating/create", data);
29
+ }
30
+ });
31
+ });
@@ -0,0 +1,19 @@
1
+ class Plugins::CamaleonCmsRating::AdminController < CamaleonCms::Apps::PluginsAdminController
2
+ include Plugins::CamaleonCmsRating::MainHelper
3
+
4
+ def index
5
+ end
6
+
7
+ # show settings form
8
+ def settings
9
+ end
10
+
11
+ # save values from settings form
12
+ def save_settings
13
+ @plugin.set_options(params[:options]) if params[:options].present? # save option values
14
+ @plugin.set_metas(params[:metas]) if params[:metas].present? # save meta values
15
+ @plugin.set_field_values(params[:field_options]) if params[:field_options].present? # save custom field values
16
+ redirect_to url_for(action: :settings), notice: 'Settings Saved Successfully'
17
+ end
18
+ # add custom methods below ....
19
+ end
@@ -0,0 +1,18 @@
1
+ class Plugins::CamaleonCmsRating::FrontController < CamaleonCms::Apps::PluginsFrontController
2
+ include Plugins::CamaleonCmsRating::MainHelper
3
+
4
+ def index
5
+ # actions for frontend module
6
+ end
7
+
8
+ # add custom methods below
9
+ def create
10
+ @rating = Plugins::CamaleonCmsRating::Rating.new(
11
+ score: params[:score],
12
+ post_id: params[:post_id],
13
+ rater_id: cama_current_user.try(:id)
14
+ )
15
+
16
+ head @rating.save ? :ok : :bad_request
17
+ end
18
+ end
@@ -0,0 +1,29 @@
1
+ module Plugins::CamaleonCmsRating::MainHelper
2
+ def self.included(klass)
3
+ # klass.helper_method [:my_helper_method] rescue "" # here your methods accessible from views
4
+ end
5
+
6
+ # here all actions on going to active
7
+ # you can run sql commands like this:
8
+ # results = ActiveRecord::Base.connection.execute(query);
9
+ # plugin: plugin model
10
+ def camaleon_cms_rating_on_active(plugin)
11
+ end
12
+
13
+ # here all actions on going to inactive
14
+ # plugin: plugin model
15
+ def camaleon_cms_rating_on_inactive(plugin)
16
+ end
17
+
18
+ # here all actions to upgrade for a new version
19
+ # plugin: plugin model
20
+ def camaleon_cms_rating_on_upgrade(plugin)
21
+ end
22
+
23
+ # hook listener to add settings link below the title of current plugin (if it is installed)
24
+ # args: {plugin (Hash), links (Array)}
25
+ # permit to add unlimmited of links...
26
+ def camaleon_cms_rating_on_plugin_options(args)
27
+ args[:links] << link_to('Settings', admin_plugins_camaleon_cms_rating_settings_path)
28
+ end
29
+ end
@@ -0,0 +1,8 @@
1
+ class Plugins::CamaleonCmsRating::Rating < ActiveRecord::Base
2
+ self.table_name = 'camaleon_cms_rating_ratings'
3
+
4
+ belongs_to :post, class_name: 'CamaleonCms::Post'
5
+ belongs_to :rater, class_name: PluginRoutes.static_system_info['user_model'].presence || 'CamaleonCms::User'
6
+
7
+ validates_inclusion_of :score, in: (1..5).to_a
8
+ end
@@ -0,0 +1,9 @@
1
+ <%#= javascript_include_tag plugin_asset("my_file.js") %>
2
+ <div class="panel panel-default">
3
+ <div class="panel-heading">
4
+ <h4>My Title</h4>
5
+ </div>
6
+ <div class="panel-body">
7
+ <p>Plugin ready to use in admin panel!.</p>
8
+ </div>
9
+ </div>
@@ -0,0 +1,21 @@
1
+ <div class="panel panel-default">
2
+ <div class="panel-heading">
3
+ <h4>My Plugin Settings</h4>
4
+ </div>
5
+ <div class="panel-body">
6
+ <%= form_tag(url_for(action: :save_settings), class: 'validate') do %>
7
+ <div class="form-group">
8
+ <label>My Option Setting</label>
9
+ <%= text_field_tag 'options[my_setting]', @plugin.get_option('my_setting'), class: 'form-control required' %>
10
+ </div>
11
+ <div class="form-group">
12
+ <label>My Meta Setting</label>
13
+ <%= text_field_tag 'metas[my_setting]', @plugin.get_meta('my_setting'), class: 'form-control required' %>
14
+ </div>
15
+ <%= render partial: "camaleon_cms/admin/settings/custom_fields/render", locals: {record: @plugin, field_groups: @plugin.get_field_groups} %>
16
+ <div class="form-group text-right">
17
+ <%= submit_tag 'Save Settings', class: 'btn btn-primary' %>
18
+ </div>
19
+ <% end %>
20
+ </div>
21
+ </div>
@@ -0,0 +1,19 @@
1
+ <div>
2
+ <% ratings = post.ratings %>
3
+ <% count = ratings.count %>
4
+ <% average = ratings.average(:score).to_f.round(2) %>
5
+
6
+ <div class="read-only-rating" data-score="<%== average %>"></div>
7
+
8
+ <p><%= "#{average} average based on #{count} ratings." %></p>
9
+
10
+ <% groups = ratings.order(:score).group(:score).count %>
11
+ <% 5.downto(1) do |score| %>
12
+ <div>
13
+ <span><%= "#{score} Star" %></span>
14
+ <span class="read-only-rating" data-score="<%== score %>"></span>
15
+ <% percentage = count.nonzero? ? Array(groups.assoc(score)).second.to_i.fdiv(count) * 100 : 0 %>
16
+ <%= number_to_percentage(percentage, precision: 0) %>
17
+ </div>
18
+ <% end %>
19
+ </div>
@@ -0,0 +1 @@
1
+ <div class="editable-rating" data-post-id="<%== post.id %>"></div>
@@ -0,0 +1,2 @@
1
+ <%#= javascript_include_tag plugin_gem_asset("js/my_file.js") %>
2
+ Plugin ready to use! in frontend.
@@ -0,0 +1,2 @@
1
+ You can create your layouts here.
2
+ To load your custom layout you can use: layout: plugin_layout(<layout_name>) in your controller
@@ -0,0 +1,14 @@
1
+ {
2
+ "title": "Camaleon CMS Rating",
3
+ "descr": "A star rating plugin for the Camaleon CMS.",
4
+ "key": "camaleon_cms_rating", // must be the name of the folder of your plugin, sample: app/views/plugins/<my_plugin> ==> 'my_plugin'
5
+ "helpers": [
6
+ "Plugins::CamaleonCmsRating::MainHelper"
7
+ ],
8
+ "hooks": {
9
+ "on_active": ["camaleon_cms_rating_on_active"],
10
+ "on_inactive": ["camaleon_cms_rating_on_inactive"],
11
+ "plugin_options": ["camaleon_cms_rating_on_plugin_options"]
12
+ //here you can add all your hooks (read documentation)
13
+ }
14
+ }
@@ -0,0 +1,5 @@
1
+ Rails.application.config.to_prepare do
2
+ CamaleonCms::Post.class_eval do
3
+ has_many :ratings, class_name: 'Plugins::CamaleonCmsRating::Rating'
4
+ end
5
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,31 @@
1
+ Rails.application.routes.draw do
2
+ scope PluginRoutes.system_info["relative_url_root"] do
3
+ scope '(:locale)', locale: /#{PluginRoutes.all_locales}/, :defaults => { } do
4
+ # frontend
5
+ namespace :plugins do
6
+ namespace 'camaleon_cms_rating' do
7
+ get 'index' => 'front#index'
8
+ post 'create' => 'front#create'
9
+ end
10
+ end
11
+ end
12
+
13
+ #Admin Panel
14
+ scope :admin, as: 'admin', path: PluginRoutes.system_info['admin_path_name'] do
15
+ namespace 'plugins' do
16
+ namespace 'camaleon_cms_rating' do
17
+ controller :admin do
18
+ get :index
19
+ get :settings
20
+ post :save_settings
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ # main routes
27
+ #scope 'camaleon_cms_rating', module: 'plugins/camaleon_cms_rating/', as: 'camaleon_cms_rating' do
28
+ # Here my routes for main routes
29
+ #end
30
+ end
31
+ end
@@ -0,0 +1,9 @@
1
+ class CreateCamaleonCmsRatingRatings < ActiveRecord::Migration[5.0]
2
+ def change
3
+ create_table :camaleon_cms_rating_ratings do |t|
4
+ t.integer :score
5
+ t.belongs_to :post
6
+ t.belongs_to :rater
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ require "camaleon_cms_rating/engine"
2
+
3
+ module CamaleonCmsRating
4
+ # Your code goes here...
5
+ end
@@ -0,0 +1,4 @@
1
+ module CamaleonCmsRating
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ module CamaleonCmsRating
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :camaleon_cms_rating do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: camaleon_cms_rating
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Richard Li
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-08-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 4.1.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 4.1.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: sqlite3
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: A star rating plugin for the Camaleon CMS.
42
+ email:
43
+ - aspirewit@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - MIT-LICENSE
49
+ - README.md
50
+ - Rakefile
51
+ - app/assets/config/camaleon_cms_rating_manifest.js
52
+ - app/assets/images/plugins/camaleon_cms_rating/star-half.png
53
+ - app/assets/images/plugins/camaleon_cms_rating/star-off.png
54
+ - app/assets/images/plugins/camaleon_cms_rating/star-on.png
55
+ - app/assets/javascripts/plugins/camaleon_cms_rating/jquery.raty.js
56
+ - app/assets/javascripts/plugins/camaleon_cms_rating/main.js
57
+ - app/controllers/plugins/camaleon_cms_rating/admin_controller.rb
58
+ - app/controllers/plugins/camaleon_cms_rating/front_controller.rb
59
+ - app/helpers/plugins/camaleon_cms_rating/main_helper.rb
60
+ - app/models/plugins/camaleon_cms_rating/rating.rb
61
+ - app/views/plugins/camaleon_cms_rating/admin/index.html.erb
62
+ - app/views/plugins/camaleon_cms_rating/admin/settings.html.erb
63
+ - app/views/plugins/camaleon_cms_rating/front/_index.html.erb
64
+ - app/views/plugins/camaleon_cms_rating/front/_new.html.erb
65
+ - app/views/plugins/camaleon_cms_rating/front/index.html.erb
66
+ - app/views/plugins/camaleon_cms_rating/layouts/readme.txt
67
+ - config/camaleon_plugin.json
68
+ - config/initializers/custom_models.rb
69
+ - config/routes.rb
70
+ - db/migrate/20170812143133_create_camaleon_cms_rating_ratings.rb
71
+ - lib/camaleon_cms_rating.rb
72
+ - lib/camaleon_cms_rating/engine.rb
73
+ - lib/camaleon_cms_rating/version.rb
74
+ - lib/tasks/camaleon_cms_rating_tasks.rake
75
+ homepage: https://github.com/aspirewit/camaleon_cms_rating
76
+ licenses:
77
+ - MIT
78
+ metadata: {}
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 2.6.12
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: A star rating plugin for the Camaleon CMS.
99
+ test_files: []