promethee 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -39
- data/app/assets/javascripts/promethee-edit.js +209 -0
- data/app/assets/stylesheets/{promethee-editor.sass → promethee-edit.sass} +6 -6
- data/app/assets/stylesheets/{promethee-editor → promethee-edit}/_move.sass +7 -7
- data/app/assets/stylesheets/{promethee-editor → promethee-edit}/_preview.sass +1 -1
- data/app/assets/stylesheets/{promethee-editor → promethee-edit}/_write.sass +8 -8
- data/app/views/promethee/_edit.html.erb +33 -115
- data/app/views/promethee/_localize.html.erb +11 -7
- data/app/{assets/javascripts/promethee-editor.js → views/promethee/components/column/_edit.define.html.erb} +0 -0
- data/app/views/promethee/{edit/inspector/component/_column.html.erb → components/column/_edit.inspect.html.erb} +1 -1
- data/app/views/promethee/{edit/move/component/_column.html.erb → components/column/_edit.move.html.erb} +4 -4
- data/app/views/promethee/components/column/_edit.write.html.erb +17 -0
- data/app/views/promethee/components/column/_localize.html.erb +3 -0
- data/app/views/promethee/{show/component/_column.html.erb → components/column/_show.html.erb} +0 -0
- data/app/views/promethee/components/cover/_edit.define.html.erb +13 -0
- data/app/views/promethee/{edit/inspector/component/_cover.html.erb → components/cover/_edit.inspect.html.erb} +1 -1
- data/app/views/promethee/components/cover/_edit.move.html.erb +7 -0
- data/app/views/promethee/components/cover/_edit.write.html.erb +39 -0
- data/app/views/promethee/{localize/component/_cover.html.erb → components/cover/_localize.html.erb} +4 -2
- data/app/views/promethee/{show/component/_cover.html.erb → components/cover/_show.html.erb} +0 -0
- data/app/views/promethee/components/details/_edit.define.html.erb +13 -0
- data/app/views/promethee/{edit/inspector/component/_details.html.erb → components/details/_edit.inspect.html.erb} +1 -1
- data/app/views/promethee/{edit/move/component/_details.html.erb → components/details/_edit.move.html.erb} +1 -1
- data/app/views/promethee/components/details/_edit.write.html.erb +35 -0
- data/app/views/promethee/{localize/component/_details.html.erb → components/details/_localize.html.erb} +3 -1
- data/app/views/promethee/{show/component/_details.html.erb → components/details/_show.html.erb} +0 -0
- data/app/views/promethee/components/image/_edit.define.html.erb +14 -0
- data/app/views/promethee/{edit/inspector/component/_image.html.erb → components/image/_edit.inspect.html.erb} +1 -1
- data/app/views/promethee/{edit/move/component/_image.html.erb → components/image/_edit.move.html.erb} +1 -1
- data/app/views/promethee/{edit/write/component/_image.html.erb → components/image/_edit.write.html.erb} +7 -23
- data/app/views/promethee/{localize/component/_image.html.erb → components/image/_localize.html.erb} +5 -2
- data/app/views/promethee/{show/component/_image.html.erb → components/image/_show.html.erb} +0 -0
- data/app/views/promethee/components/row/_edit.define.html.erb +11 -0
- data/app/views/promethee/components/row/_edit.inspect.html.erb +3 -0
- data/app/views/promethee/{edit/move/component/_row.html.erb → components/row/_edit.move.html.erb} +1 -1
- data/app/views/promethee/components/row/_edit.write.html.erb +33 -0
- data/app/views/promethee/components/row/_localize.html.erb +3 -0
- data/app/views/promethee/{show/component/_row.html.erb → components/row/_show.html.erb} +0 -0
- data/app/views/promethee/components/slider/_edit.define.html.erb +11 -0
- data/app/views/promethee/components/slider/_edit.inspect.html.erb +3 -0
- data/app/views/promethee/{edit/move/component/_slider.html.erb → components/slider/_edit.move.html.erb} +2 -3
- data/app/views/promethee/{edit/write/component/_slider.html.erb → components/slider/_edit.write.html.erb} +25 -32
- data/app/views/promethee/components/slider/_localize.html.erb +3 -0
- data/app/views/promethee/{show/component/_slider.html.erb → components/slider/_show.html.erb} +0 -0
- data/app/views/promethee/components/text/_edit.define.html.erb +12 -0
- data/app/views/promethee/{edit/inspector/component/_text.html.erb → components/text/_edit.inspect.html.erb} +1 -1
- data/app/views/promethee/{edit/move/component/_text.html.erb → components/text/_edit.move.html.erb} +1 -1
- data/app/views/promethee/components/text/_edit.write.html.erb +32 -0
- data/app/views/promethee/{localize/component/_text.html.erb → components/text/_localize.html.erb} +4 -2
- data/app/views/promethee/{show/component/_text.html.erb → components/text/_show.html.erb} +0 -0
- data/app/views/promethee/components/video/_edit.define.html.erb +12 -0
- data/app/views/promethee/{edit/inspector/component/_video.html.erb → components/video/_edit.inspect.html.erb} +1 -1
- data/app/views/promethee/{edit/move/component/_video.html.erb → components/video/_edit.move.html.erb} +1 -1
- data/app/views/promethee/{edit/write/component/_video.html.erb → components/video/_edit.write.html.erb} +7 -39
- data/app/views/promethee/components/video/_localize.html.erb +3 -0
- data/app/views/promethee/{show/component/_video.html.erb → components/video/_show.html.erb} +0 -0
- data/app/views/promethee/edit/_move.html.erb +35 -74
- data/app/views/promethee/edit/_preview.html.erb +3 -3
- data/app/views/promethee/edit/_write.html.erb +67 -17
- data/app/views/promethee/show/_component.html.erb +1 -1
- data/lib/promethee/rails/version.rb +1 -1
- metadata +55 -57
- data/app/views/promethee/edit/inspector/_inspector.html.erb +0 -11
- data/app/views/promethee/edit/inspector/component/_row.html.erb +0 -3
- data/app/views/promethee/edit/inspector/component/_slider.html.erb +0 -3
- data/app/views/promethee/edit/move/_component.html.erb +0 -5
- data/app/views/promethee/edit/move/_components.html.erb +0 -26
- data/app/views/promethee/edit/move/component/_cover.html.erb +0 -8
- data/app/views/promethee/edit/shared/_data.html.erb +0 -1
- data/app/views/promethee/edit/shared/_navbar.html.erb +0 -25
- data/app/views/promethee/edit/write/_add_button.html.erb +0 -66
- data/app/views/promethee/edit/write/_component.html.erb +0 -3
- data/app/views/promethee/edit/write/_components.html.erb +0 -7
- data/app/views/promethee/edit/write/_toolbar.html.erb +0 -5
- data/app/views/promethee/edit/write/component/_column.html.erb +0 -21
- data/app/views/promethee/edit/write/component/_cover.html.erb +0 -55
- data/app/views/promethee/edit/write/component/_details.html.erb +0 -52
- data/app/views/promethee/edit/write/component/_row.html.erb +0 -42
- data/app/views/promethee/edit/write/component/_text.html.erb +0 -44
- data/app/views/promethee/localize/_component.html.erb +0 -3
- data/app/views/promethee/localize/component/_column.html.erb +0 -3
- data/app/views/promethee/localize/component/_row.html.erb +0 -3
- data/app/views/promethee/localize/component/_slider.html.erb +0 -3
- data/app/views/promethee/localize/component/_video.html.erb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b6fd84303285742e3b357dde0c4fcf780d3de1b3
|
4
|
+
data.tar.gz: 1b5d5b514e70ee8ac836f0ad341e5287479d970a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac96f5b9991320ae569efcd8d63632f74b387477942aeb7009a2fb1647b0bd2f3cb575da37f097fc5445f8b76eb78f99c0ddd8cab8f9c54c88e05bb3fbda307e
|
7
|
+
data.tar.gz: c44d83d03795e3ae3cda160d47aa5d5b94004db1d164298ea62e3a7125679375ca06a97c5e0a3273ed30d27b36a85452d1db284a54ad8a2deb5ec2220e985a51
|
data/README.md
CHANGED
@@ -1,43 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# Bring fire to your page
|
1
|
+
# Prométhée
|
4
2
|
|
5
3
|
[![Maintainability](https://api.codeclimate.com/v1/badges/98a8649f411bc9f50786/maintainability)](https://codeclimate.com/github/lespoupeesrusses/promethee/maintainability)
|
6
4
|
|
7
|
-
## Where does it come from?
|
8
|
-
As we build sites and digital solutions for some of the most prestigious brands (Givenchy, L’Oréal, Lancôme, Cartier, Hermès…) we often need to build spectacular pages, with a responsive layout, using a predefined design system or visual guidelines. Very often, our clients need to be able to do some creation or adaptation on their own. And in most situation, it has to be translated very easily, with no technical cost.
|
9
|
-
|
10
|
-
Our first approach was to generate custom templates. For example, 10 years ago, before responsivity, we did a lot of multilingual content for Parfums Lolita Lempicka using a simple read/write system with something like 10 templates. We soon made a “Do what you feel” template, allowing the designer to put fields wherever he needed on the page, but it was completely unusable for people who lacked either design or development background.
|
11
|
-
|
12
|
-
We then built a system for Cartier, where the content was made by a designer, then implemented by a front end developer with keys allowing the translation. This was good because creation was very free, but the client could make no content on its own.
|
13
|
-
|
14
|
-
We built another tool for Diptyque, with content bricks that we assembled. Basically, it looked like vertical slides doing a nice one-page. It seemed like the perfect solution, but in the end it had so many options it became very hard to use, and still the different pages like quite similar.
|
15
|
-
|
16
|
-
Then came the page builder. Inspired by Divi, the idea was to offer rows and columns, based on bootstrap. We built that for Hermès, as one of the different components available to build pages. Translation was fine, responsivity was fine, content was not super simple to do, but still quite simple, and the use of presets provided a good “easy to use” solution.
|
17
|
-
|
18
|
-
We re-used the concept for Céline, and realized we had a mis-conception: the builder was the basic page editor, and we could add components in it.
|
19
|
-
|
20
|
-
As we needed the solution for 2 projects, and a third one coming, we decided to make it a gem.
|
21
|
-
|
22
|
-
Prométhée was born.
|
23
|
-
|
24
|
-
## What does it do?
|
25
|
-
It builds responsive pages!
|
26
|
-
|
27
|
-
There are 2 parts: the editor, which lets you build the pages, and the renderer. The pages are stored as json data, which can easily be added to a model in rails, and saved via a regular form.
|
28
|
-
|
29
|
-
## How does it relate to existing solutions?
|
30
|
-
|
31
|
-
### Regarding wysiwyg editors like tinymce, trix...
|
32
|
-
|
33
|
-
It's not only rich text: it lets you build complete pages, with a grid system.
|
34
|
-
|
35
|
-
### Regarding page builders like Divi, Semplice, Shogun
|
36
|
-
|
37
|
-
It's for Rails (unlike Divi or Semplice which are for Wordpress).
|
38
|
-
It's open source.
|
39
|
-
It does not provide as many options, as it's intended to be integrated in a website with specific brand guidelines through some custom css.
|
40
|
-
|
41
5
|
## Installation
|
42
6
|
Add this line to your application's Gemfile:
|
43
7
|
|
@@ -169,7 +133,7 @@ With javascript set:
|
|
169
133
|
//= require angular-ui-bootstrap
|
170
134
|
//= require angular-summernote
|
171
135
|
//= require promethee
|
172
|
-
//= require promethee-
|
136
|
+
//= require promethee-edit
|
173
137
|
```
|
174
138
|
|
175
139
|
With stylesheets set:
|
@@ -179,7 +143,7 @@ With stylesheets set:
|
|
179
143
|
@import 'material_icons.css'
|
180
144
|
@import 'summernote'
|
181
145
|
@import 'promethee'
|
182
|
-
@import 'promethee-
|
146
|
+
@import 'promethee-edit'
|
183
147
|
```
|
184
148
|
|
185
149
|
#### The editor has components
|
@@ -0,0 +1,209 @@
|
|
1
|
+
var promethee = angular
|
2
|
+
.module('Promethee', ['summernote', 'ngAnimate'])
|
3
|
+
.value('definitions', [])
|
4
|
+
// What does the next 3 lines do? Why?
|
5
|
+
.config(function($rootScopeProvider) {
|
6
|
+
$rootScopeProvider.digestTtl(20);
|
7
|
+
})
|
8
|
+
.filter('htmlSafe', ['$sce', function($sce) {
|
9
|
+
return function(val) {
|
10
|
+
return $sce.trustAsHtml(val);
|
11
|
+
};
|
12
|
+
}])
|
13
|
+
.filter('urlSafe', ['$sce', function($sce) {
|
14
|
+
return function(val) {
|
15
|
+
return $sce.trustAsResourceUrl(val);
|
16
|
+
};
|
17
|
+
}])
|
18
|
+
.filter('humanize', function() {
|
19
|
+
return function(val) {
|
20
|
+
val = (val + '').replace(/_/g, ' ').replace(/([A-Z])/g, ' $1').replace(/\s\s+/, ' ').trim();
|
21
|
+
return val[0].toUpperCase() + val.substring(1).toLowerCase();
|
22
|
+
};
|
23
|
+
})
|
24
|
+
.filter('textContentFromHTML', function() {
|
25
|
+
return function(val, distinctParagraphs) {
|
26
|
+
var element = document.createElement('div');
|
27
|
+
element.innerHTML = val;
|
28
|
+
|
29
|
+
if(distinctParagraphs === 'distinctParagraphs') {
|
30
|
+
var paragraphs = element.querySelectorAll('p');
|
31
|
+
for(var i = 0; i < paragraphs.length; i++) paragraphs[i].textContent += ' ';
|
32
|
+
}
|
33
|
+
|
34
|
+
return element.textContent;
|
35
|
+
}
|
36
|
+
})
|
37
|
+
.filter('numberOfCharacters', function() {
|
38
|
+
return function(val) {
|
39
|
+
return val.length;
|
40
|
+
};
|
41
|
+
})
|
42
|
+
.filter('numberOfWords', function() {
|
43
|
+
return function(val) {
|
44
|
+
var words = val
|
45
|
+
.replace(/\bhttps?:\/\/[a-z0-9\-\._]+(?:\/[^\s\n\r]+)?/gi, 'a') // A URL is one word
|
46
|
+
.replace(/\b[a-z0-9\-\._]+@[a-z0-9\-\._]+\.[a-z0-9\-\._]+\b/gi, 'a') // An email is one word
|
47
|
+
.replace(/[^a-z0-9\s\n\r]/gi, ' ')
|
48
|
+
.replace(/[\s\n\r]+/g, ' ')
|
49
|
+
.trim()
|
50
|
+
.split(' ');
|
51
|
+
|
52
|
+
return words[0] === '' ? 0 : words.length;
|
53
|
+
};
|
54
|
+
});
|
55
|
+
|
56
|
+
promethee.controller('PrometheeController', ['$scope', 'definitions', '$http', function($scope, definitions, $http) {
|
57
|
+
|
58
|
+
// Data (TODO use Adder and probably page definition to init)
|
59
|
+
if($scope.data === null || $scope.data === '') {
|
60
|
+
$scope.data = {
|
61
|
+
id: '',
|
62
|
+
type: 'page',
|
63
|
+
version: 1,
|
64
|
+
children: []
|
65
|
+
};
|
66
|
+
}
|
67
|
+
|
68
|
+
$scope.promethee = {
|
69
|
+
data: $scope.data,
|
70
|
+
inspected: null,
|
71
|
+
mode: 'write',
|
72
|
+
preview: 'desktop',
|
73
|
+
fullscreen: false
|
74
|
+
};
|
75
|
+
|
76
|
+
$scope.inspect = function(component, event) {
|
77
|
+
$scope.promethee.inspected = component;
|
78
|
+
event.stopPropagation();
|
79
|
+
}
|
80
|
+
|
81
|
+
$scope.enablePreview = function() {
|
82
|
+
if (this.promethee.mode === 'preview') return;
|
83
|
+
this.promethee.mode = 'preview';
|
84
|
+
|
85
|
+
var form = document.createElement('form');
|
86
|
+
document.body.appendChild(form);
|
87
|
+
form.method = 'POST';
|
88
|
+
form.action = '/promethee/preview';
|
89
|
+
form.target = 'preview';
|
90
|
+
|
91
|
+
var input = document.createElement('input');
|
92
|
+
input.type = 'text';
|
93
|
+
input.value = JSON.stringify($scope.promethee.data);
|
94
|
+
input.name = 'data';
|
95
|
+
form.appendChild(input);
|
96
|
+
form.submit();
|
97
|
+
document.body.removeChild(form);
|
98
|
+
}
|
99
|
+
|
100
|
+
$scope.remove = function(component, components) {
|
101
|
+
var index = components.indexOf(component);
|
102
|
+
components.splice(index, 1);
|
103
|
+
}
|
104
|
+
|
105
|
+
}]);
|
106
|
+
|
107
|
+
|
108
|
+
promethee.controller('AdderController', ['$scope', '$rootScope', 'definitions', function($scope, $rootScope, definitions) {
|
109
|
+
|
110
|
+
$scope.adding = false;
|
111
|
+
$scope.childrenToAddTo = null;
|
112
|
+
$scope.definitions = definitions;
|
113
|
+
|
114
|
+
$scope.close = function() {
|
115
|
+
$scope.adding = false;
|
116
|
+
$scope.addingToChildren = null;
|
117
|
+
};
|
118
|
+
|
119
|
+
$scope.pushComponent = function(definition) {
|
120
|
+
var definition = angular.copy(definition.data);
|
121
|
+
definition.id = $scope.createIdentifier();
|
122
|
+
$scope.childrenToAddTo.push(definition);
|
123
|
+
$scope.close();
|
124
|
+
};
|
125
|
+
|
126
|
+
$rootScope.addComponentTo = function(components) {
|
127
|
+
$scope.adding = true;
|
128
|
+
$scope.childrenToAddTo = components;
|
129
|
+
};
|
130
|
+
|
131
|
+
// https://gist.github.com/gordonbrander/2230317
|
132
|
+
$scope.createIdentifier = function () {
|
133
|
+
// Math.random should be unique because of its seeding algorithm.
|
134
|
+
// Convert it to base 36 (numbers + letters), and grab the first 9 characters
|
135
|
+
// after the decimal.
|
136
|
+
return '' + Math.random().toString(36).substr(2, 9);
|
137
|
+
};
|
138
|
+
|
139
|
+
}])
|
140
|
+
|
141
|
+
|
142
|
+
|
143
|
+
promethee
|
144
|
+
.directive('draggable', function() {
|
145
|
+
return {
|
146
|
+
restrict:'A',
|
147
|
+
link: function(scope, element, attrs) {
|
148
|
+
element.draggable({
|
149
|
+
revert: true,
|
150
|
+
revertDuration: 0,
|
151
|
+
scroll: true,
|
152
|
+
refreshPositions: true,
|
153
|
+
start: function() {
|
154
|
+
var $elementDragged = $(element[0]);
|
155
|
+
var type = $elementDragged.data('type');
|
156
|
+
$('.promethee-edit__move').addClass('promethee-edit__move--dragging promethee-edit__move--dragging--' + type);
|
157
|
+
|
158
|
+
// The droppable zone immediately before has no use, it would put the object at the same position
|
159
|
+
// FIXME the selector is not correct
|
160
|
+
/*
|
161
|
+
var $droppableBefore = $elementDragged.prev('.promethee-edit__move__draggable').find('.promethee-edit__move__droppable').last();
|
162
|
+
if ($droppableBefore.length === 0) {
|
163
|
+
// For the first child, we look for the previous droppable zone
|
164
|
+
$droppableBefore = $elementDragged.prev('.promethee-edit__move__droppable');
|
165
|
+
}
|
166
|
+
$droppableBefore.addClass('promethee-edit__move__droppable--hidden');
|
167
|
+
*/
|
168
|
+
},
|
169
|
+
stop: function() {
|
170
|
+
var $elementDragged = $(element[0]);
|
171
|
+
var type = $elementDragged.data('type');
|
172
|
+
$('.promethee-edit__move').removeClass('promethee-edit__move--dragging promethee-edit__move--dragging--' + type);
|
173
|
+
// $('.promethee-edit__move__droppable').removeClass('promethee-edit__move__droppable--hidden');
|
174
|
+
}
|
175
|
+
});
|
176
|
+
}
|
177
|
+
}
|
178
|
+
})
|
179
|
+
.directive('droppable', function($compile) {
|
180
|
+
return {
|
181
|
+
restrict: 'A',
|
182
|
+
link: function(scope, element, attrs) {
|
183
|
+
element.droppable({
|
184
|
+
tolerance: 'pointer',
|
185
|
+
drop: function(event, ui) {
|
186
|
+
var draggedFromList = angular.element(ui.draggable).parent().scope().components;
|
187
|
+
var draggedFromIndex = parseInt(ui.draggable[0].getAttribute('data-index'));
|
188
|
+
// console.log('dragged', draggedFromList, draggedFromIndex);
|
189
|
+
draggedFromList.splice(draggedFromIndex, 1);
|
190
|
+
|
191
|
+
var component = angular.element(ui.draggable).scope().component;
|
192
|
+
var droppedToList = angular.element(this).scope().components;
|
193
|
+
var droppedToIndex = parseInt(this.getAttribute('data-index'));
|
194
|
+
if (draggedFromList == droppedToList) {
|
195
|
+
// The object we dragged was removed from the list
|
196
|
+
if (draggedFromIndex < droppedToIndex) {
|
197
|
+
// It was before the dropped index, so removing it changed the index
|
198
|
+
droppedToIndex -= 1;
|
199
|
+
}
|
200
|
+
}
|
201
|
+
// console.log('dropped', component, droppedToList, droppedToIndex);
|
202
|
+
droppedToList.splice(droppedToIndex, 0, component);
|
203
|
+
|
204
|
+
scope.$apply();
|
205
|
+
}
|
206
|
+
});
|
207
|
+
}
|
208
|
+
}
|
209
|
+
});
|
@@ -3,11 +3,11 @@ $promethee-transparent-grey: transparentize($promethee-grey, .8)
|
|
3
3
|
$promethee-light-grey: #eee
|
4
4
|
$promethee-color: #ff9900 !default
|
5
5
|
|
6
|
-
@import 'promethee-
|
7
|
-
@import 'promethee-
|
8
|
-
@import 'promethee-
|
6
|
+
@import 'promethee-edit/write'
|
7
|
+
@import 'promethee-edit/move'
|
8
|
+
@import 'promethee-edit/preview'
|
9
9
|
|
10
|
-
.promethee-
|
10
|
+
.promethee-edit
|
11
11
|
background: white
|
12
12
|
position: relative
|
13
13
|
&--fullscreen
|
@@ -18,10 +18,10 @@ $promethee-color: #ff9900 !default
|
|
18
18
|
top: 50px
|
19
19
|
z-index: 10000
|
20
20
|
overflow: auto
|
21
|
-
.promethee-
|
21
|
+
.promethee-edit__write
|
22
22
|
padding-right: 300px
|
23
23
|
padding-top: 15px
|
24
|
-
.promethee-
|
24
|
+
.promethee-edit__inspect
|
25
25
|
top: 65px
|
26
26
|
|
27
27
|
&__navbar
|
@@ -1,4 +1,4 @@
|
|
1
|
-
.promethee-
|
1
|
+
.promethee-edit__move
|
2
2
|
width: 432px
|
3
3
|
margin: 0 auto
|
4
4
|
padding-bottom: 200px
|
@@ -82,21 +82,21 @@
|
|
82
82
|
z-index: 1000
|
83
83
|
opacity: 0.5
|
84
84
|
// Nothing is droppable inside components being dragged
|
85
|
-
.promethee-
|
85
|
+
.promethee-edit__move__droppable
|
86
86
|
visibility: hidden !important
|
87
87
|
|
88
88
|
// By default, nothing is dropped in rows
|
89
89
|
&--dragging
|
90
|
-
.promethee-
|
90
|
+
.promethee-edit__move__droppable--row
|
91
91
|
display: none
|
92
92
|
|
93
93
|
// Except for columns, which can be dropped only on rows
|
94
|
-
&--dragging.promethee-
|
95
|
-
.promethee-
|
94
|
+
&--dragging.promethee-edit__move--dragging--column
|
95
|
+
.promethee-edit__move__droppable
|
96
96
|
display: none
|
97
97
|
// It's a little specific, columns can be dropped on rows "first droppable", or on columns "inside droppables"
|
98
|
-
&.promethee-
|
99
|
-
&.promethee-
|
98
|
+
&.promethee-edit__move__droppable--row--inside-column,
|
99
|
+
&.promethee-edit__move__droppable--row--first
|
100
100
|
display: block
|
101
101
|
|
102
102
|
|
@@ -1,6 +1,6 @@
|
|
1
|
-
.promethee-
|
1
|
+
.promethee-edit__write
|
2
2
|
|
3
|
-
.promethee-
|
3
|
+
.promethee-edit__toolbar
|
4
4
|
background: #253742
|
5
5
|
padding: 10px
|
6
6
|
font-size: 11px
|
@@ -10,7 +10,7 @@
|
|
10
10
|
&, *
|
11
11
|
user-select: none
|
12
12
|
|
13
|
-
.promethee-
|
13
|
+
.promethee-edit__inspect
|
14
14
|
background: #fff
|
15
15
|
width: 300px
|
16
16
|
top: 15px
|
@@ -31,22 +31,22 @@
|
|
31
31
|
&-content
|
32
32
|
padding: 15px
|
33
33
|
|
34
|
-
.promethee-
|
34
|
+
.promethee-edit__adder__button
|
35
35
|
display: block
|
36
36
|
text-align: center
|
37
37
|
margin: 50px 0
|
38
38
|
|
39
|
-
.promethee-
|
39
|
+
.promethee-edit__component
|
40
40
|
margin-bottom: 5px
|
41
41
|
&--cover
|
42
|
-
.promethee-
|
42
|
+
.promethee-edit__cover-content
|
43
43
|
padding: 150px 30px
|
44
44
|
background-repeat: no-repeat
|
45
45
|
background-position: center center
|
46
46
|
background-size: cover
|
47
|
-
&--row > div > .promethee-
|
47
|
+
&--row > div > .promethee-edit__toolbar
|
48
48
|
margin-bottom: 5px
|
49
|
-
&--column > div > .promethee-
|
49
|
+
&--column > div > .promethee-edit__toolbar
|
50
50
|
margin-bottom: 5px
|
51
51
|
&--slider
|
52
52
|
.fontawesome-carousel-control .fa
|
@@ -1,126 +1,44 @@
|
|
1
1
|
<%
|
2
|
-
master_data ||= nil
|
3
2
|
promethee_data = Promethee::Data.new master_data
|
4
3
|
%>
|
5
|
-
|
6
|
-
<script>
|
7
|
-
|
8
|
-
var promethee = angular
|
9
|
-
.module('Promethee', ['summernote', 'ngAnimate'])
|
10
|
-
.value('data', <%= promethee_data.to_json.html_safe %>)
|
11
|
-
.value('definitions', [])
|
12
|
-
.config(function($rootScopeProvider) {
|
13
|
-
$rootScopeProvider.digestTtl(20);
|
14
|
-
})
|
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
|
-
.filter('textContentFromHTML', function() {
|
32
|
-
return function(val, distinctParagraphs) {
|
33
|
-
var element = document.createElement('div');
|
34
|
-
element.innerHTML = val;
|
35
|
-
|
36
|
-
if(distinctParagraphs === 'distinctParagraphs') {
|
37
|
-
var paragraphs = element.querySelectorAll('p');
|
38
|
-
for(var i = 0; i < paragraphs.length; i++) paragraphs[i].textContent += ' ';
|
39
|
-
}
|
40
|
-
|
41
|
-
return element.textContent;
|
42
|
-
}
|
43
|
-
})
|
44
|
-
.filter('numberOfCharacters', function() {
|
45
|
-
return function(val) {
|
46
|
-
return val.length;
|
47
|
-
};
|
48
|
-
})
|
49
|
-
.filter('numberOfWords', function() {
|
50
|
-
return function(val) {
|
51
|
-
var words = val
|
52
|
-
.replace(/\bhttps?:\/\/[a-z0-9\-\._]+(?:\/[^\s\n\r]+)?/gi, 'a') // A URL is one word
|
53
|
-
.replace(/\b[a-z0-9\-\._]+@[a-z0-9\-\._]+\.[a-z0-9\-\._]+\b/gi, 'a') // An email is one word
|
54
|
-
.replace(/[^a-z0-9\s\n\r]/gi, ' ')
|
55
|
-
.replace(/[\s\n\r]+/g, ' ')
|
56
|
-
.trim()
|
57
|
-
.split(' ');
|
58
|
-
|
59
|
-
return words[0] === '' ? 0 : words.length;
|
60
|
-
};
|
61
|
-
});
|
62
|
-
|
63
|
-
promethee.controller('PrometheeController', ['data', '$scope', 'definitions', '$http',
|
64
|
-
function(data, $scope, definitions, $http) {
|
65
|
-
|
66
|
-
// Data (TODO use Adder and probably page definition to init)
|
67
|
-
if(data === null || data === '') {
|
68
|
-
data = {
|
69
|
-
id: '',
|
70
|
-
type: 'page',
|
71
|
-
version: 1,
|
72
|
-
children: []
|
73
|
-
};
|
74
|
-
}
|
75
|
-
|
76
|
-
$scope.promethee = { inspected: null };
|
77
|
-
$scope.data = $scope.component = data;
|
78
|
-
$scope.mode = 'write';
|
79
|
-
$scope.preview = 'desktop';
|
80
|
-
$scope.fullscreen = false;
|
81
|
-
|
82
|
-
$scope.inspect = function(component, event) {
|
83
|
-
$scope.promethee.inspected = component;
|
84
|
-
event.stopPropagation();
|
85
|
-
}
|
86
|
-
|
87
|
-
$scope.enablePreview = function() {
|
88
|
-
if (this.mode === 'preview') return;
|
89
|
-
this.mode = 'preview';
|
90
|
-
|
91
|
-
var form = document.createElement('form');
|
92
|
-
document.body.appendChild(form);
|
93
|
-
form.method = 'POST';
|
94
|
-
form.action = <%= promethee_preview_path.to_json.html_safe %>;
|
95
|
-
form.target = 'preview';
|
96
|
-
|
97
|
-
var input = document.createElement('input');
|
98
|
-
input.type = 'text';
|
99
|
-
input.value = JSON.stringify(data);
|
100
|
-
input.name = 'data';
|
101
|
-
form.appendChild(input);
|
102
|
-
form.submit();
|
103
|
-
document.body.removeChild(form);
|
104
|
-
}
|
105
|
-
|
106
|
-
$scope.remove = function(component, components) {
|
107
|
-
var index = components.indexOf(component);
|
108
|
-
components.splice(index, 1);
|
109
|
-
}
|
110
|
-
|
111
|
-
}]);
|
112
|
-
|
113
|
-
</script>
|
114
|
-
|
115
4
|
<div
|
116
5
|
id="promethee"
|
117
|
-
class="promethee-
|
118
|
-
ng-class="{ 'promethee-editor--fullscreen': fullscreen }"
|
6
|
+
class="promethee-edit"
|
119
7
|
ng-app="Promethee"
|
8
|
+
ng-class="{ 'promethee-edit--fullscreen': promethee.fullscreen }"
|
120
9
|
ng-controller="PrometheeController as prometheeController"
|
10
|
+
ng-init="promethee.data=<%= promethee_data.to_json %>"
|
121
11
|
>
|
122
|
-
|
123
|
-
|
12
|
+
<input type="hidden" name="page[data]" id="page_data" value="{{promethee.data}}" />
|
13
|
+
<nav class="navbar navbar-default promethee-edit__navbar" ng-class="{'navbar-fixed-top': promethee.fullscreen }">
|
14
|
+
<div class="container-fluid">
|
15
|
+
<div class="navbar-header promethee-edit__icon">
|
16
|
+
<div class="navbar-brand"><%= File.read(__dir__ + '/../../assets/images/icon-promethee.svg').html_safe %></div>
|
17
|
+
</div>
|
18
|
+
<div id="navbar">
|
19
|
+
<ul class="nav navbar-nav navbar-right">
|
20
|
+
<li ng-click="promethee.mode = 'write'" ng-class="{active: promethee.mode == 'write'}"><a><%= fa_icon :pencil %></a></li>
|
21
|
+
<li ng-click="promethee.mode = 'move'" ng-class="{active: promethee.mode == 'move'}"><a><%= fa_icon :arrows %></a></li>
|
22
|
+
<li ng-click="enablePreview()" ng-class="{active: promethee.mode == 'preview'}">
|
23
|
+
<a data-toggle="dropdown"><%= fa_icon :eye %></a>
|
24
|
+
<ul class="dropdown-menu" ng-show="promethee.mode == 'preview'">
|
25
|
+
<li ng-click="promethee.preview = 'desktop'" ng-class="{active: promethee.preview == 'desktop'}"><a><i class="fa fa-desktop"></i></a></li>
|
26
|
+
<li ng-click="promethee.preview = 'tablet'" ng-class="{active: promethee.preview == 'tablet'}"><a><i class="fa fa-tablet"></i></a></li>
|
27
|
+
<li ng-click="promethee.preview = 'mobile'" ng-class="{active: promethee.preview == 'mobile'}"><a><i class="fa fa-mobile"></i></a></li>
|
28
|
+
</ul>
|
29
|
+
</li>
|
30
|
+
<li ng-click="promethee.fullscreen = !promethee.fullscreen">
|
31
|
+
<a ng-show="promethee.fullscreen"><%= fa_icon :expand %></a>
|
32
|
+
<a ng-hide="promethee.fullscreen"><%= fa_icon :compress %></a>
|
33
|
+
</li>
|
34
|
+
</ul>
|
35
|
+
</div>
|
36
|
+
</div>
|
37
|
+
</nav>
|
38
|
+
<% Dir["#{__dir__}/components/*/_edit.*.html.erb"].map do |file| %>
|
39
|
+
<% partial = file.split('app/views/').last.gsub('.html.erb', '').gsub('/_', '/') %>
|
40
|
+
<%= render partial %>
|
41
|
+
<% end %>
|
124
42
|
<%= render 'promethee/edit/write' %>
|
125
43
|
<%= render 'promethee/edit/move' %>
|
126
44
|
<%= render 'promethee/edit/preview' %>
|