promethee 0.1.0 → 0.1.1

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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +164 -19
  3. data/Rakefile +33 -2
  4. data/app/assets/images/icon-promethee.png +0 -0
  5. data/app/assets/images/logo-promethee-horizontal.svg +14 -0
  6. data/app/assets/images/logo-promethee-vertical.svg +14 -0
  7. data/app/assets/javascripts/promethee.js +59 -0
  8. data/app/assets/javascripts/promethee/controller.js +22 -0
  9. data/app/assets/stylesheets/promethee-editor.sass +105 -0
  10. data/app/assets/stylesheets/promethee-editor/_mixins.sass +19 -0
  11. data/app/assets/stylesheets/promethee-editor/_variables.sass +4 -0
  12. data/app/assets/stylesheets/promethee.sass +4 -0
  13. data/app/views/promethee/_edit.html.erb +172 -0
  14. data/app/views/promethee/_show.html.erb +6 -0
  15. data/app/views/promethee/components/_column.html.erb +8 -0
  16. data/app/views/promethee/components/_column_edit.html.erb +40 -0
  17. data/app/views/promethee/components/_image.html.erb +7 -0
  18. data/app/views/promethee/components/_image_edit.html.erb +60 -0
  19. data/app/views/promethee/components/_index.html.erb +3 -0
  20. data/app/views/promethee/components/_index_edit.html.erb +7 -0
  21. data/app/views/promethee/components/_row.html.erb +6 -0
  22. data/app/views/promethee/components/_row_edit.html.erb +53 -0
  23. data/app/views/promethee/components/_show.html.erb +4 -0
  24. data/app/views/promethee/components/_show_edit.html.erb +3 -0
  25. data/app/views/promethee/components/_text.html.erb +6 -0
  26. data/app/views/promethee/components/_text_edit.html.erb +59 -0
  27. data/app/views/promethee/components/_video.html.erb +16 -0
  28. data/app/views/promethee/components/_video_edit.html.erb +63 -0
  29. data/app/views/promethee/partials/_toolbar_buttons.html.erb +4 -0
  30. data/lib/promethee.rb +37 -2
  31. data/lib/promethee/component.rb +28 -0
  32. data/lib/promethee/component/attribute.rb +42 -0
  33. data/lib/promethee/component/attribute/boolean.rb +4 -0
  34. data/lib/promethee/component/attribute/float.rb +3 -0
  35. data/lib/promethee/component/attribute/integer.rb +3 -0
  36. data/lib/promethee/component/attribute/string.rb +3 -0
  37. data/lib/promethee/component/attributes.rb +50 -0
  38. data/lib/promethee/component/attributes/definer.rb +13 -0
  39. data/lib/promethee/component/base.rb +68 -0
  40. data/lib/promethee/component/collection.rb +17 -0
  41. data/lib/promethee/component/column.rb +8 -0
  42. data/lib/promethee/component/image.rb +6 -0
  43. data/lib/promethee/component/row.rb +3 -0
  44. data/lib/promethee/component/text.rb +5 -0
  45. data/lib/promethee/component/video.rb +5 -0
  46. data/lib/promethee/core_ext/form_builder.rb +6 -0
  47. data/lib/promethee/core_ext/form_helper.rb +6 -0
  48. data/lib/promethee/core_ext/tags.rb +18 -0
  49. data/lib/promethee/grid.rb +52 -0
  50. data/lib/promethee/rails/engine.rb +7 -0
  51. data/lib/promethee/rails/helper.rb +26 -0
  52. data/lib/promethee/rails/version.rb +5 -0
  53. data/lib/tasks/promethee/promethee.rake +4 -0
  54. metadata +202 -20
  55. data/.gitignore +0 -9
  56. data/CODE_OF_CONDUCT.md +0 -74
  57. data/Gemfile +0 -6
  58. data/LICENSE +0 -21
  59. data/bin/console +0 -14
  60. data/bin/setup +0 -8
  61. data/lib/promethee/version.rb +0 -3
  62. data/promethee.gemspec +0 -24
@@ -0,0 +1,16 @@
1
+ <%
2
+ url = component[:attributes][:url].to_s
3
+
4
+ if 'vimeo'.in? url
5
+ video_id = url.to_s.gsub(/\A(?:https?:)?\/\/(?:(?:www|player)\.)?vimeo\.com\/(?:video\/)?(\d+).*?\z/, '\1')
6
+ iframe_src = "https://player.vimeo.com/video/#{video_id}?color=ffffff&title=0&byline=0&portrait=0"
7
+ elsif 'youtube'.in? url
8
+ video_id = url.to_s.split('watch?v=').last
9
+ iframe_src = "http://www.youtube.com/embed/#{video_id}"
10
+ end
11
+ %>
12
+ <div class="embed-responsive embed-responsive-16by9 <%= promethee_class_for component %>">
13
+ <% if iframe_src.present? %>
14
+ <iframe frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen="allowfullscreen" src="<%= iframe_src %>"></iframe>
15
+ <% end %>
16
+ </div>
@@ -0,0 +1,63 @@
1
+ <script type="text/ng-template" id="promethee/components/video">
2
+ <div ng-controller="VideoController">
3
+ <div dnd-draggable="component"
4
+ dnd-moved="remove()"
5
+ dnd-type="component.type"
6
+ class="promethee-editor__component promethee-editor__component--video promethee-editor__component--final">
7
+ <div class="promethee-editor__toolbar">
8
+ Video
9
+ <%= render 'promethee/partials/toolbar_buttons' %>
10
+ </div>
11
+ <div ng-show="editing" class="promethee-editor__wrapper">
12
+ <div class="form-group">
13
+ <label class="label-control">Url</label>
14
+ <input ng-model="component.attributes.url" class="form-control" type="text"/>
15
+ </div>
16
+ </div>
17
+ <div class="embed-responsive embed-responsive-16by9">
18
+ <iframe ng-if="embed" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen="allowfullscreen" ng-src="{{embed | urlSafe}}"></iframe>
19
+ </div>
20
+ </div>
21
+ </div>
22
+ </script>
23
+
24
+ <script>
25
+ angular.injector(['ng', '<%= promethee_id %>']).get('definitions').push({
26
+ name: 'Video',
27
+ thumb: 'http://via.placeholder.com/300x200',
28
+ data: {
29
+ type: 'video',
30
+ attributes: {
31
+ url: 'https://vimeo.com/115082758'
32
+ }
33
+ }
34
+ });
35
+
36
+ promethee.controller('VideoController', ['$scope', function($scope) {
37
+
38
+ $scope.editing = false;
39
+
40
+ $scope.remove = function() {
41
+ this.components.splice(this.components.indexOf(this.component), 1);
42
+ };
43
+
44
+ Object.defineProperty($scope, 'embed', {
45
+ get: function() {
46
+ var embed = null;
47
+ var url = this.component.attributes.url + '';
48
+
49
+ if(url.includes('vimeo')) {
50
+ var id = url.replace(/^(?:https?:)?\/\/(?:(?:www|player)\.)?vimeo\.com\/(?:video\/)?(\d+).*?$/, '$1');
51
+ embed = 'https://player.vimeo.com/video/' + id + '?color=ffffff&title=0&byline=0&portrait=0';
52
+ }
53
+ else if(url.includes('youtube')) {
54
+ var parts = url.split('watch?v=');
55
+ var id = parts[parts.length - 1];
56
+ embed = 'http://www.youtube.com/embed/' + id;
57
+ }
58
+
59
+ return embed;
60
+ }
61
+ })
62
+ }]);
63
+ </script>
@@ -0,0 +1,4 @@
1
+ <div class="pull-right">
2
+ <span ng-click="editing = !editing" class="btn btn-default btn-xs"><%= fa_icon :edit %></span>
3
+ <span ng-click="remove()" class="btn btn-default btn-xs"><%= fa_icon :close %></span>
4
+ </div>
data/lib/promethee.rb CHANGED
@@ -1,5 +1,40 @@
1
- require "promethee/version"
1
+ require 'bootstrap-sass'
2
+ require 'font-awesome-rails'
3
+ require 'jquery-rails'
4
+ require 'jquery-ui-rails'
5
+ require 'tinymce-rails'
6
+ require 'angularjs-rails'
7
+ require 'angular-ui-tinymce/rails'
8
+ require 'material_icons'
2
9
 
3
10
  module Promethee
4
- # Your code goes here...
11
+ module Rails
12
+ require 'promethee/rails/helper'
13
+ require 'promethee/rails/engine'
14
+ require 'promethee/rails/version'
15
+ end
16
+
17
+ require 'promethee/component'
18
+ require 'promethee/component/attribute'
19
+ require 'promethee/component/attribute/boolean'
20
+ require 'promethee/component/attribute/integer'
21
+ require 'promethee/component/attribute/float'
22
+ require 'promethee/component/attribute/string'
23
+
24
+ require 'promethee/component/attributes'
25
+ require 'promethee/component/attributes/definer'
26
+
27
+ require 'promethee/component/base'
28
+ require 'promethee/component/collection'
29
+ require 'promethee/component/row'
30
+ require 'promethee/component/column'
31
+ require 'promethee/component/text'
32
+ require 'promethee/component/image'
33
+ require 'promethee/component/video'
34
+
35
+ require 'promethee/grid'
36
+
37
+ require 'promethee/core_ext/tags'
38
+ require 'promethee/core_ext/form_helper'
39
+ require 'promethee/core_ext/form_builder'
5
40
  end
@@ -0,0 +1,28 @@
1
+ module Promethee::Component
2
+ def self.types
3
+ Base.descendants.map &:type
4
+ end
5
+
6
+ def self.as type
7
+ begin
8
+ class_name = "::Promethee::Component::#{type.to_s.classify}"
9
+ require "promethee/component/#{type}" unless Object.const_defined? class_name
10
+ class_name.constantize
11
+ rescue LoadError
12
+ raise "Unknown Prométhée component type \"#{type}\". Available types: \"#{types.join '", "'}\"."
13
+ end
14
+ end
15
+
16
+ def self.from data
17
+ raise "Invalid data provided, expected a Hash got a #{data.class}." unless data.is_a? Hash
18
+
19
+ data = data.deep_dup
20
+
21
+ data[:attributes] = {} unless data[:attributes].is_a? Hash
22
+ data[:children] = [] unless data[:children].is_a? Array
23
+
24
+ data[:children].map! { |data| from data }
25
+
26
+ as(data[:type]).new attributes: data[:attributes], children: data[:children]
27
+ end
28
+ end
@@ -0,0 +1,42 @@
1
+ module Promethee::Component::Attribute
2
+ class Base
3
+ attr_reader :name, :value
4
+
5
+ def initialize name, value = default
6
+ @name = name.to_s.to_sym
7
+ self.value = value
8
+ end
9
+
10
+ def value= value
11
+ @value = value == default ? default : cast(value)
12
+ end
13
+
14
+ def default
15
+ self.class.default
16
+ end
17
+
18
+ def cast value
19
+ self.class.cast.call value
20
+ end
21
+
22
+ def dup
23
+ self.class.new name, (value.dup rescue value)
24
+ end
25
+
26
+ private
27
+
28
+ def self.type
29
+ to_s.split('::').last.underscore
30
+ end
31
+
32
+ def self.default value = nil
33
+ @value = value unless value.nil?
34
+ @value
35
+ end
36
+
37
+ def self.cast &block
38
+ @cast = block if block_given?
39
+ @cast ||= -> (value) { value }
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,4 @@
1
+ class Promethee::Component::Attribute::Boolean < Promethee::Component::Attribute::Base
2
+ default false
3
+ cast { |value| !!value }
4
+ end
@@ -0,0 +1,3 @@
1
+ class Promethee::Component::Attribute::Float < Promethee::Component::Attribute::Base
2
+ cast { |value| value&.to_f or default }
3
+ end
@@ -0,0 +1,3 @@
1
+ class Promethee::Component::Attribute::Integer < Promethee::Component::Attribute::Base
2
+ cast { |value| value&.to_i or default }
3
+ end
@@ -0,0 +1,3 @@
1
+ class Promethee::Component::Attribute::String < Promethee::Component::Attribute::Base
2
+ cast { |value| value&.to_s or default }
3
+ end
@@ -0,0 +1,50 @@
1
+ class Promethee::Component::Attributes
2
+ def update hash
3
+ (names & hash.keys.map(&:to_sym)).each { |name| attributes[name].value = hash[name] }
4
+
5
+ self
6
+ end
7
+
8
+ def to_hash
9
+ attributes.map{ |name, attribute| [name, attribute.value] }.to_h
10
+ end
11
+ alias_method :to_h, :to_hash
12
+ alias_method :as_json, :to_hash
13
+
14
+ def [](method)
15
+ send method
16
+ end
17
+
18
+ def keys
19
+ attributes.keys
20
+ end
21
+ alias_method :names, :keys
22
+
23
+ def each &block
24
+ attributes.values.each &block
25
+ end
26
+
27
+ def << attribute
28
+ attributes[attribute.name] = attribute
29
+
30
+ define_singleton_method(attribute.name) { attribute.value }
31
+ define_singleton_method("#{attribute.name}=") { |value| attribute.value = value }
32
+ end
33
+
34
+ def dup
35
+ duplicate = self.class.new
36
+ each { |attribute| duplicate << attribute.dup }
37
+
38
+ duplicate
39
+ end
40
+
41
+ def copy hash
42
+ dup.update hash
43
+ end
44
+
45
+ private
46
+
47
+ def attributes
48
+ @attributes ||= {}
49
+ end
50
+ end
@@ -0,0 +1,13 @@
1
+ class Promethee::Component::Attributes::Definer
2
+ attr_reader :component
3
+
4
+ def initialize(component)
5
+ @component = component
6
+ end
7
+
8
+ ::Promethee::Component::Attribute::Base.descendants.each do |attribute|
9
+ define_method attribute.type do |name, default: nil|
10
+ component.attributes << attribute.new(name, default)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,68 @@
1
+ class Promethee::Component::Base
2
+ attr_reader :attributes, :children
3
+
4
+ def initialize(attributes: {}, children: [])
5
+ @attributes = self.class.attributes.copy attributes
6
+ @children = Promethee::Component::Collection.new children
7
+ end
8
+
9
+ def to_hash *options
10
+ {
11
+ type: type,
12
+ attributes: attributes.to_hash,
13
+ children: children.to_ary
14
+ }
15
+ end
16
+ alias_method :to_h, :to_hash
17
+ alias_method :as_json, :to_hash
18
+
19
+ def to_html
20
+ ApplicationController.renderer.render partial: "promethee/components/#{type}", locals: { component: self }
21
+ end
22
+
23
+ def [](method)
24
+ send method
25
+ end
26
+
27
+ def class_name
28
+ "promethee__component promethee__component--#{type}"
29
+ end
30
+
31
+ def type
32
+ self.class.type
33
+ end
34
+
35
+ def self.attributes
36
+ @attributes ||= Promethee::Component::Attributes.new
37
+ end
38
+
39
+ def self.children
40
+ @children ||= []
41
+ end
42
+
43
+ def self.type
44
+ to_s.split('::').last.underscore.to_sym
45
+ end
46
+
47
+ def self.final?
48
+ children.empty?
49
+ end
50
+
51
+ # def self.class_name
52
+ # "promethee-editor__component promethee__component--#{type}#{' promethee__component--final' if final?}"
53
+ # end
54
+
55
+ private
56
+
57
+ def self.has_attributes
58
+ yield Promethee::Component::Attributes::Definer.new(self) if block_given?
59
+ end
60
+
61
+ def self.has_children *components
62
+ children.concat(components.flatten.map{ |component| component.is_a?(Class) && component < self ? component : Promethee::Component.as(component) }).uniq!
63
+ end
64
+
65
+ class << self
66
+ alias_method :has_child, :has_children
67
+ end
68
+ end
@@ -0,0 +1,17 @@
1
+ class Promethee::Component::Collection < Array
2
+ def to_ary
3
+ map &:to_hash
4
+ end
5
+ alias_method :to_a, :to_ary
6
+ alias_method :as_json, :to_ary
7
+
8
+ def to_html
9
+ map(&:to_html).join.html_safe
10
+ end
11
+
12
+ def self.from data
13
+ raise "Invalid data provided, expected a Array got a #{data.class}." unless data.is_a? Array
14
+
15
+ new data.map{ |component| Promethee::Component.from component }
16
+ end
17
+ end
@@ -0,0 +1,8 @@
1
+ class Promethee::Component::Column < Promethee::Component::Base
2
+ has_attributes do |a|
3
+ a.integer :size, default: 4
4
+ a.integer :offset, default: 0
5
+ end
6
+
7
+ has_children :row, :text, :image, :video
8
+ end
@@ -0,0 +1,6 @@
1
+ class Promethee::Component::Image < Promethee::Component::Base
2
+ has_attributes do |a|
3
+ a.string :src
4
+ a.string :alt
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ class Promethee::Component::Row < Promethee::Component::Base
2
+ has_child :column
3
+ end
@@ -0,0 +1,5 @@
1
+ class Promethee::Component::Text < Promethee::Component::Base
2
+ has_attributes do |a|
3
+ a.string :body, default: ''
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Promethee::Component::Video < Promethee::Component::Base
2
+ has_attributes do |a|
3
+ a.string :url
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ ActionView::Helpers::FormBuilder.class_eval do
2
+ # https://github.com/rails/rails/blob/13c5aa818e9284fe30f83469b340e579195bda3f/actionview/lib/action_view/helpers/form_helper.rb#L2148
3
+ def promethee(method, options = {})
4
+ @template.promethee_editor(@object_name, method, objectify_options(options))
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ ActionView::Helpers::FormHelper.class_eval do
2
+ # https://github.com/rails/rails/blob/13c5aa818e9284fe30f83469b340e579195bda3f/actionview/lib/action_view/helpers/form_helper.rb#L1193
3
+ def promethee_editor(object_name, method, options = {})
4
+ ActionView::Helpers::Tags::PrometheeEditor.new(object_name, method, self, options).render
5
+ end
6
+ end
@@ -0,0 +1,18 @@
1
+ require 'promethee'
2
+
3
+ module ActionView
4
+ module Helpers
5
+ module Tags
6
+ # https://github.com/rails/rails/blob/bdc581616b760d1e2be3795c6f0f3ab4b1e125a5/actionview/lib/action_view/helpers/tags/text_field.rb
7
+ class PrometheeEditor < Base
8
+ def render
9
+ options = @options.stringify_keys
10
+ add_default_name_and_id(options)
11
+ data = options.fetch("value") { value_before_type_cast(object) }
12
+
13
+ Promethee::Grid.new(data, name: options["name"]).edit
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end