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,19 @@
|
|
1
|
+
=grid-builder-set-gutter-width($width)
|
2
|
+
$was: $grid-gutter-width
|
3
|
+
$grid-gutter-width: $width !global
|
4
|
+
|
5
|
+
.row
|
6
|
+
+make-row
|
7
|
+
|
8
|
+
+make-grid-columns
|
9
|
+
+make-grid(xs)
|
10
|
+
@media(min-width: 768px)
|
11
|
+
+make-grid(sm)
|
12
|
+
|
13
|
+
@media (min-width: 992px)
|
14
|
+
+make-grid(md)
|
15
|
+
|
16
|
+
@media (min-width: 1200px)
|
17
|
+
+make-grid(lg)
|
18
|
+
|
19
|
+
$grid-gutter-width: $was !global
|
@@ -0,0 +1,172 @@
|
|
1
|
+
<%
|
2
|
+
promethee_id = "promethee-#{SecureRandom.hex 10}"
|
3
|
+
promethee_data = promethee.data
|
4
|
+
promethee_data = promethee_data.to_json unless promethee_data.is_a? String
|
5
|
+
%>
|
6
|
+
|
7
|
+
<script>
|
8
|
+
var promethee = angular
|
9
|
+
.module('<%= promethee_id %>', ['ui.tinymce', 'dndLists'])
|
10
|
+
.constant('data', <%= promethee_data.html_safe %>)
|
11
|
+
.value('state', {
|
12
|
+
editing: false
|
13
|
+
})
|
14
|
+
.value('definitions', [])
|
15
|
+
.filter('htmlSafe', ['$sce', function($sce) {
|
16
|
+
return function(val) {
|
17
|
+
return $sce.trustAsHtml(val);
|
18
|
+
};
|
19
|
+
}])
|
20
|
+
.filter('urlSafe', ['$sce', function($sce) {
|
21
|
+
return function(val) {
|
22
|
+
return $sce.trustAsResourceUrl(val);
|
23
|
+
};
|
24
|
+
}])
|
25
|
+
.filter('humanize', function() {
|
26
|
+
return function(val) {
|
27
|
+
val = (val + '').replace(/_/g, ' ').replace(/([A-Z])/g, ' $1').replace(/\s\s+/, ' ').trim();
|
28
|
+
return val[0].toUpperCase() + val.substring(1).toLowerCase();
|
29
|
+
};
|
30
|
+
});
|
31
|
+
</script>
|
32
|
+
|
33
|
+
<div id="<%= promethee_id %>"
|
34
|
+
class="promethee-editor"
|
35
|
+
ng-app="<%= promethee_id %>"
|
36
|
+
ng-controller="PrometheeController as prometheeController"
|
37
|
+
ng-class="{
|
38
|
+
'fullscreen': fullscreen,
|
39
|
+
'promethee-editor--preview': preview,
|
40
|
+
'promethee-editor--preview--mobile': preview && previewMode == 'mobile',
|
41
|
+
'promethee-editor--preview--tablet': preview && previewMode == 'tablet',
|
42
|
+
'promethee-editor--preview--desktop': preview && previewMode == 'desktop'
|
43
|
+
}">
|
44
|
+
|
45
|
+
<% # TODO custom views %>
|
46
|
+
<% Dir['app/views/promethee/components/*'].each do |file| %>
|
47
|
+
<% end %>
|
48
|
+
<% # TODO iterate over files in gem %>
|
49
|
+
<% ['index', 'show', 'row', 'column', 'text', 'image', 'video'].each do |type| %>
|
50
|
+
<%= render partial: "promethee/components/#{type}_edit", locals: { promethee_id: promethee_id } %>
|
51
|
+
<% end %>
|
52
|
+
|
53
|
+
<input type="hidden" name="page[data]" id="page_data" value="{{data}}" />
|
54
|
+
|
55
|
+
<nav class="navbar navbar-default">
|
56
|
+
<div class="container-fluid">
|
57
|
+
<div class="navbar-header">
|
58
|
+
<%= image_tag 'icon-promethee.png', class: 'navbar-brand' %>
|
59
|
+
</div>
|
60
|
+
<div id="navbar">
|
61
|
+
<ul class="nav navbar-nav navbar-right">
|
62
|
+
<li ng-click="enablePreview()" ng-hide="preview"><a><%= fa_icon :eye %></a></li>
|
63
|
+
<li ng-click="previewMode = 'mobile'" ng-class="{ active: previewMode == 'mobile' }" ng-show="preview">
|
64
|
+
<a><%= fa_icon :mobile %></a>
|
65
|
+
</li>
|
66
|
+
<li ng-click="previewMode = 'tablet'" ng-class="{ active: previewMode == 'tablet' }" ng-show="preview"><a>
|
67
|
+
<%= fa_icon :tablet %></a>
|
68
|
+
</li>
|
69
|
+
<li ng-click="previewMode = 'desktop'" ng-class="{ active: previewMode == 'desktop' }" ng-show="preview"><a>
|
70
|
+
<%= fa_icon :desktop %></a>
|
71
|
+
</li>
|
72
|
+
<li ng-click="disablePreview()" ng-show="preview"><a><%= fa_icon 'eye-slash' %></a>
|
73
|
+
</li>
|
74
|
+
<li ng-click="enableFullscreen()" ng-hide="fullscreen"><a><%= fa_icon :expand %></a></li>
|
75
|
+
<li ng-click="disableFullscreen()" ng-show="fullscreen"><a><%= fa_icon :compress %></a></li>
|
76
|
+
</ul>
|
77
|
+
</div>
|
78
|
+
</div>
|
79
|
+
</nav>
|
80
|
+
<div class="promethee-editor__page" ng-class="{ 'container-fluid': fullscreen }">
|
81
|
+
<ng-include src="'promethee/components/index'"></ng-include>
|
82
|
+
</div>
|
83
|
+
|
84
|
+
<span type="button" class="btn btn-default btn-block" ng-click="addComponentTo(data)" style="margin-bottom: 6px">Add component</span>
|
85
|
+
|
86
|
+
<div class="promethee-editor__adder" ng-controller="AdderController">
|
87
|
+
<div class="modal fade in" tabindex="-1" role="dialog" style="display: {{adding ? 'block' : 'none'}}">
|
88
|
+
<div class="modal-dialog modal-lg" role="document">
|
89
|
+
<div class="modal-content">
|
90
|
+
<div class="modal-header">
|
91
|
+
<button type="button" class="close" ng-click="close()"><span aria-hidden="true">×</span></button>
|
92
|
+
<h4 class="modal-title">Select component</h4>
|
93
|
+
</div>
|
94
|
+
<div class="modal-body">
|
95
|
+
<div class="row">
|
96
|
+
<div ng-repeat="definition in definitions"
|
97
|
+
ng-click="pushComponent(definition)"
|
98
|
+
class="col-md-3">
|
99
|
+
<div class="thumbnail">
|
100
|
+
<img ng-src="{{definition.thumb}}" class="img-responsive">
|
101
|
+
<h4>{{definition.name}}</h4>
|
102
|
+
</div>
|
103
|
+
</div>
|
104
|
+
</div>
|
105
|
+
</div>
|
106
|
+
</div>
|
107
|
+
</div>
|
108
|
+
</div>
|
109
|
+
</div>
|
110
|
+
|
111
|
+
<!-- Work in progress -->
|
112
|
+
<!-- <iframe id="iframe"></iframe> !-->
|
113
|
+
</div>
|
114
|
+
|
115
|
+
<script>
|
116
|
+
promethee.controller('PrometheeController', ['data', '$scope', 'definitions', function(data, $scope, definitions) {
|
117
|
+
if (data === null || data === '') {
|
118
|
+
data = [];
|
119
|
+
}
|
120
|
+
$scope.data = data;
|
121
|
+
$scope.fullscreen = false;
|
122
|
+
$scope.preview = false;
|
123
|
+
$scope.previewMode = 'desktop';
|
124
|
+
$scope.component = {
|
125
|
+
children: data
|
126
|
+
};
|
127
|
+
|
128
|
+
$scope.allowedTypes = definitions.map(function(definition) {
|
129
|
+
return definition.data.type;
|
130
|
+
});
|
131
|
+
|
132
|
+
$scope.enablePreview = function() {
|
133
|
+
this.preview = true;
|
134
|
+
// Work in progress
|
135
|
+
// document.getElementById('iframe').contentWindow.document.documentElement.innerHTML = document.documentElement.innerHTML;
|
136
|
+
}
|
137
|
+
|
138
|
+
$scope.disablePreview = function() {
|
139
|
+
this.preview = false;
|
140
|
+
}
|
141
|
+
|
142
|
+
$scope.enableFullscreen = function() {
|
143
|
+
this.fullscreen = true;
|
144
|
+
}
|
145
|
+
|
146
|
+
$scope.disableFullscreen = function() {
|
147
|
+
this.fullscreen = false;
|
148
|
+
}
|
149
|
+
|
150
|
+
}]);
|
151
|
+
|
152
|
+
promethee.controller('AdderController', ['$scope', '$rootScope', 'definitions', function($scope, $rootScope, definitions) {
|
153
|
+
|
154
|
+
$scope.adding = null;
|
155
|
+
$scope.definitions = definitions;
|
156
|
+
|
157
|
+
$scope.close = function() {
|
158
|
+
$scope.adding = null;
|
159
|
+
};
|
160
|
+
|
161
|
+
$scope.pushComponent = function(definition) {
|
162
|
+
var definition = angular.copy(definition.data);
|
163
|
+
$scope.adding.push(definition);
|
164
|
+
$scope.close();
|
165
|
+
};
|
166
|
+
|
167
|
+
$rootScope.addComponentTo = function(components) {
|
168
|
+
$scope.adding = components;
|
169
|
+
};
|
170
|
+
|
171
|
+
}]);
|
172
|
+
</script>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<%
|
2
|
+
size = component[:attributes][:size]
|
3
|
+
offset = component[:attributes][:offset]
|
4
|
+
children = component[:children]
|
5
|
+
%>
|
6
|
+
<div class="col col-md-<%= size %><%= " col-md-offset-#{offset}" if offset > 0 %> <%= promethee_class_for component %>">
|
7
|
+
<%= render partial: 'promethee/components/index', locals: { components: children } %>
|
8
|
+
</div>
|
@@ -0,0 +1,40 @@
|
|
1
|
+
<script type="text/ng-template" id="promethee/components/column">
|
2
|
+
<div ng-controller="ColumnController">
|
3
|
+
<div class="col col-md-{{component.attributes.size}} col-md-offset-{{component.attributes.offset}}">
|
4
|
+
<div dnd-draggable="component" dnd-moved="remove()" dnd-type="component.type" class="promethee-editor__component promethee-editor__component--column">
|
5
|
+
<div class="promethee-editor__toolbar">
|
6
|
+
Column
|
7
|
+
<%= render 'promethee/partials/toolbar_buttons' %>
|
8
|
+
</div>
|
9
|
+
<div ng-show="editing" class="promethee-editor__wrapper">
|
10
|
+
<div class="form-group">
|
11
|
+
<label class="label-control">Size</label>
|
12
|
+
<input ng-model="component.attributes.size" class="form-control" type="number"/>
|
13
|
+
</div>
|
14
|
+
<div class="form-group">
|
15
|
+
<label class="label-control">Offset</label>
|
16
|
+
<input ng-model="component.attributes.offset" class="form-control" type="number"/>
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
|
20
|
+
<ng-include src="'promethee/components/index'"></ng-include>
|
21
|
+
|
22
|
+
<span type="button" class="btn btn-default btn-block" ng-click="addComponentTo(component.children)" style="margin: 0 6px 6px 6px;width: auto">Add component</span>
|
23
|
+
</div>
|
24
|
+
</div>
|
25
|
+
</div>
|
26
|
+
</script>
|
27
|
+
|
28
|
+
<script>
|
29
|
+
promethee.controller('ColumnController', ['$scope', 'definitions', function($scope, definitions) {
|
30
|
+
|
31
|
+
$scope.allowedTypes = definitions.map(function(definition) {
|
32
|
+
return definition.data.type;
|
33
|
+
});
|
34
|
+
|
35
|
+
$scope.remove = function() {
|
36
|
+
this.components.splice(this.components.indexOf(this.component), 1);
|
37
|
+
};
|
38
|
+
|
39
|
+
}]);
|
40
|
+
</script>
|
@@ -0,0 +1,60 @@
|
|
1
|
+
<script type="text/ng-template" id="promethee/components/image">
|
2
|
+
<div ng-controller="ImageController" style="position: relative">
|
3
|
+
<div dnd-draggable="component"
|
4
|
+
dnd-moved="remove()"
|
5
|
+
dnd-type="component.type"
|
6
|
+
class="promethee-editor__component promethee-editor__component--image promethee-editor__component--final">
|
7
|
+
<div class="promethee-editor__toolbar">
|
8
|
+
Image
|
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.src" class="form-control" type="text"/>
|
15
|
+
</div>
|
16
|
+
<div class="form-group">
|
17
|
+
<label class="label-control">Alt</label>
|
18
|
+
<input ng-model="component.attributes.alt" class="form-control" type="text"/>
|
19
|
+
</div>
|
20
|
+
</div>
|
21
|
+
<div ng-show="component.attributes.src">
|
22
|
+
<img ng-click="edit()" ng-src="{{component.attributes.src}}" class="img-responsive">
|
23
|
+
</div>
|
24
|
+
<div ng-hide="component.attributes.src">
|
25
|
+
<p ng-hide="editing" ng-click="edit()" class="text-center">Click to set the image</p>
|
26
|
+
</div>
|
27
|
+
</div>
|
28
|
+
</div>
|
29
|
+
</script>
|
30
|
+
|
31
|
+
<script>
|
32
|
+
angular.injector(['ng', '<%= promethee_id %>']).get('definitions').push({
|
33
|
+
name: 'Image',
|
34
|
+
thumb: 'http://via.placeholder.com/300x200',
|
35
|
+
data: {
|
36
|
+
type: 'image',
|
37
|
+
attributes: {
|
38
|
+
src: 'https://source.unsplash.com/random/1920x1080'
|
39
|
+
}
|
40
|
+
}
|
41
|
+
});
|
42
|
+
|
43
|
+
promethee.controller('ImageController', ['$scope', function($scope) {
|
44
|
+
|
45
|
+
$scope.editing = false;
|
46
|
+
|
47
|
+
$scope.edit = function() {
|
48
|
+
this.editing = true;
|
49
|
+
};
|
50
|
+
|
51
|
+
$scope.complete = function() {
|
52
|
+
this.editing = false;
|
53
|
+
};
|
54
|
+
|
55
|
+
$scope.remove = function() {
|
56
|
+
this.components.splice(this.components.indexOf(this.component), 1);
|
57
|
+
};
|
58
|
+
|
59
|
+
}]);
|
60
|
+
</script>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<script type="text/ng-template" id="promethee/components/index">
|
2
|
+
<div class="promethee-editor__components" ng-init="components = component.children" dnd-list="components" dnd-allowed-types="allowedTypes">
|
3
|
+
<div ng-repeat="component in components">
|
4
|
+
<ng-include src="'promethee/components/show'"></ng-include>
|
5
|
+
</div>
|
6
|
+
</div>
|
7
|
+
</script>
|
@@ -0,0 +1,53 @@
|
|
1
|
+
<script type="text/ng-template" id="promethee/components/row">
|
2
|
+
<div ng-controller="RowController">
|
3
|
+
<div class="row">
|
4
|
+
<div dnd-draggable="component" dnd-moved="remove()" dnd-type="component.type" class="promethee-editor__component promethee-editor__component--row">
|
5
|
+
<div class="promethee-editor__toolbar">
|
6
|
+
Row
|
7
|
+
<%= render 'promethee/partials/toolbar_buttons' %>
|
8
|
+
</div>
|
9
|
+
<div ng-show="editing" class="promethee-editor__wrapper">
|
10
|
+
Nothing to edit (yet...)
|
11
|
+
</div>
|
12
|
+
|
13
|
+
<ng-include src="'promethee/components/index'"></ng-include>
|
14
|
+
|
15
|
+
<div class="clearfix"></div>
|
16
|
+
<span class="btn btn-default btn-block" ng-click="addColumn()" style="margin: 0 6px 6px 6px;width: auto">Add column</span>
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
</div>
|
20
|
+
</script>
|
21
|
+
|
22
|
+
<script>
|
23
|
+
angular.injector(['ng', '<%= promethee_id %>']).get('definitions').push({
|
24
|
+
name: 'Row',
|
25
|
+
thumb: 'http://via.placeholder.com/300x200',
|
26
|
+
data: {
|
27
|
+
type: 'row',
|
28
|
+
attributes: {},
|
29
|
+
children: []
|
30
|
+
}
|
31
|
+
});
|
32
|
+
|
33
|
+
promethee.controller('RowController', ['$scope', function($scope) {
|
34
|
+
|
35
|
+
$scope.allowedTypes = ['column'];
|
36
|
+
|
37
|
+
$scope.addColumn = function() {
|
38
|
+
this.component.children.push({
|
39
|
+
type: 'column',
|
40
|
+
attributes: {
|
41
|
+
size: 3,
|
42
|
+
offset: 0
|
43
|
+
},
|
44
|
+
children: []
|
45
|
+
})
|
46
|
+
}
|
47
|
+
|
48
|
+
$scope.remove = function() {
|
49
|
+
this.components.splice(this.components.indexOf(this.component), 1);
|
50
|
+
};
|
51
|
+
|
52
|
+
}]);
|
53
|
+
</script>
|
@@ -0,0 +1,59 @@
|
|
1
|
+
<script type="text/ng-template" id="promethee/components/text">
|
2
|
+
<div ng-controller="TextController">
|
3
|
+
<div dnd-draggable="component"
|
4
|
+
dnd-moved="remove()"
|
5
|
+
dnd-type="component.type"
|
6
|
+
class="promethee-editor__component promethee-editor__component--text promethee-editor__component--final">
|
7
|
+
<div class="promethee-editor__toolbar">
|
8
|
+
Text
|
9
|
+
<%= render 'promethee/partials/toolbar_buttons' %>
|
10
|
+
</div>
|
11
|
+
<div ng-show="editing">
|
12
|
+
<textarea ui-tinymce="tinymceOptions" ng-model="component.attributes.body"></textarea>
|
13
|
+
</div>
|
14
|
+
<div ng-hide="editing">
|
15
|
+
<div class="promethee-editor__wrapper" ng-bind-html="component.attributes.body | htmlSafe" ng-click="edit()"></div>
|
16
|
+
</div>
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
</script>
|
20
|
+
|
21
|
+
<script>
|
22
|
+
angular.injector(['ng', '<%= promethee_id %>']).get('definitions').push({
|
23
|
+
name: 'Text',
|
24
|
+
thumb: 'http://via.placeholder.com/300x200',
|
25
|
+
data: {
|
26
|
+
type: 'text',
|
27
|
+
attributes: {
|
28
|
+
body: 'Edit me'
|
29
|
+
}
|
30
|
+
}
|
31
|
+
});
|
32
|
+
|
33
|
+
promethee.controller('TextController', ['$scope', function($scope) {
|
34
|
+
|
35
|
+
$scope.editing = false;
|
36
|
+
|
37
|
+
$scope.edit = function() {
|
38
|
+
this.editing = true;
|
39
|
+
};
|
40
|
+
|
41
|
+
$scope.complete = function() {
|
42
|
+
this.editing = false;
|
43
|
+
};
|
44
|
+
|
45
|
+
$scope.remove = function() {
|
46
|
+
this.components.splice(this.components.indexOf(this.component), 1);
|
47
|
+
};
|
48
|
+
|
49
|
+
$scope.tinymceOptions = {
|
50
|
+
plugins: 'autoresize',
|
51
|
+
toolbar: 'styleselect | bold italic',
|
52
|
+
menubar: false,
|
53
|
+
statusbar: false,
|
54
|
+
branding: false,
|
55
|
+
autoresize_bottom_margin: 0
|
56
|
+
};
|
57
|
+
|
58
|
+
}]);
|
59
|
+
</script>
|