promethee 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +164 -19
- data/Rakefile +33 -2
- data/app/assets/images/icon-promethee.png +0 -0
- data/app/assets/images/logo-promethee-horizontal.svg +14 -0
- data/app/assets/images/logo-promethee-vertical.svg +14 -0
- data/app/assets/javascripts/promethee.js +59 -0
- data/app/assets/javascripts/promethee/controller.js +22 -0
- data/app/assets/stylesheets/promethee-editor.sass +105 -0
- data/app/assets/stylesheets/promethee-editor/_mixins.sass +19 -0
- data/app/assets/stylesheets/promethee-editor/_variables.sass +4 -0
- data/app/assets/stylesheets/promethee.sass +4 -0
- data/app/views/promethee/_edit.html.erb +172 -0
- data/app/views/promethee/_show.html.erb +6 -0
- data/app/views/promethee/components/_column.html.erb +8 -0
- data/app/views/promethee/components/_column_edit.html.erb +40 -0
- data/app/views/promethee/components/_image.html.erb +7 -0
- data/app/views/promethee/components/_image_edit.html.erb +60 -0
- data/app/views/promethee/components/_index.html.erb +3 -0
- data/app/views/promethee/components/_index_edit.html.erb +7 -0
- data/app/views/promethee/components/_row.html.erb +6 -0
- data/app/views/promethee/components/_row_edit.html.erb +53 -0
- data/app/views/promethee/components/_show.html.erb +4 -0
- data/app/views/promethee/components/_show_edit.html.erb +3 -0
- data/app/views/promethee/components/_text.html.erb +6 -0
- data/app/views/promethee/components/_text_edit.html.erb +59 -0
- data/app/views/promethee/components/_video.html.erb +16 -0
- data/app/views/promethee/components/_video_edit.html.erb +63 -0
- data/app/views/promethee/partials/_toolbar_buttons.html.erb +4 -0
- data/lib/promethee.rb +37 -2
- data/lib/promethee/component.rb +28 -0
- data/lib/promethee/component/attribute.rb +42 -0
- data/lib/promethee/component/attribute/boolean.rb +4 -0
- data/lib/promethee/component/attribute/float.rb +3 -0
- data/lib/promethee/component/attribute/integer.rb +3 -0
- data/lib/promethee/component/attribute/string.rb +3 -0
- data/lib/promethee/component/attributes.rb +50 -0
- data/lib/promethee/component/attributes/definer.rb +13 -0
- data/lib/promethee/component/base.rb +68 -0
- data/lib/promethee/component/collection.rb +17 -0
- data/lib/promethee/component/column.rb +8 -0
- data/lib/promethee/component/image.rb +6 -0
- data/lib/promethee/component/row.rb +3 -0
- data/lib/promethee/component/text.rb +5 -0
- data/lib/promethee/component/video.rb +5 -0
- data/lib/promethee/core_ext/form_builder.rb +6 -0
- data/lib/promethee/core_ext/form_helper.rb +6 -0
- data/lib/promethee/core_ext/tags.rb +18 -0
- data/lib/promethee/grid.rb +52 -0
- data/lib/promethee/rails/engine.rb +7 -0
- data/lib/promethee/rails/helper.rb +26 -0
- data/lib/promethee/rails/version.rb +5 -0
- data/lib/tasks/promethee/promethee.rake +4 -0
- metadata +202 -20
- data/.gitignore +0 -9
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -6
- data/LICENSE +0 -21
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/lib/promethee/version.rb +0 -3
- 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>
|
data/lib/promethee.rb
CHANGED
@@ -1,5 +1,40 @@
|
|
1
|
-
require
|
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
|
-
|
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,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,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
|