promethee 1.11.29 → 2.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 87015a529d4f152f57fd5da02b5bf817e8cfb8420efabaf1714489b3d822f01d
4
- data.tar.gz: 3c947c382a7ebd8b3a66668708a4503197f1178a58414af19e608708db594b1e
3
+ metadata.gz: b24d3197b6a9f29120ec8849dffae52cb78cf47b309200bd6b1d228dbd930170
4
+ data.tar.gz: 4c47e50f8ea5ec4c239d9adeba78c17e41fa02801631e1896032f64016e57104
5
5
  SHA512:
6
- metadata.gz: 48fafc37b97d5dd355f11dbac04cdc00a2e526786390b7969980b915060196efbda9a75ffcf2a4d2efc56275f0d834323a5defadfc4dc0285c29ead194c0a633
7
- data.tar.gz: 8c5728fdab8c70aa73a5ebcc46aabb2ae81e3df8b1f7bf8bab350e38e5da8ab66a5ad439456e17cf494942ba4f4fd290758b098ec38a3b979124d60337885563
6
+ metadata.gz: 60837d5bb49e78e27cd9816bc78794ec2ebc74a8a25d2ed3074926ba884e80fa140e463daad482eabeb9fc9cab278e80dd569bbc21cdef16b116ccddd09086de
7
+ data.tar.gz: a36840b631435a45a53e26c40148a2e4baf2cab78d28d3938fef818391072988540dfac3cddb2523f1d7f79a0b8f1a98e02288025ce96ca791531d1e898e01cf
data/UPGRADING ADDED
@@ -0,0 +1,10 @@
1
+ ##########################################
2
+ # NOTE FOR UPGRADING TO 2.0.0 OR LATER #
3
+ ##########################################
4
+
5
+ Prométhée 2.0 brings:
6
+ - [BREAKING CHANGE] New structure for table component. A rake task is available to update them in your master models. Localization has to be manual.
7
+ - [TOOL TO FIX ISSUE] A rake task to clean your localization models.
8
+
9
+ For more details, check the documentation:
10
+ https://github.com/lespoupeesrusses/promethee/tree/dev-2.0/doc
@@ -1,127 +1,135 @@
1
1
  @import "@fancyapps/fancybox/dist/jquery.fancybox.min"
2
2
 
3
+ // aside
4
+ // blockquote
5
+ // collection
6
+ // cover
7
+ // faq
8
+ // image
9
+ // slider
10
+
3
11
  .promethee
4
- &__component
5
- &__cover
6
- min-height: 300px
7
- padding: 150px 30px
8
- text-align: center
9
- display: flex
10
- justify-content: center
11
- flex-direction: column
12
- background-repeat: no-repeat
13
- background-position: center center
14
- background-size: cover
15
- margin-bottom: 50px
16
-
17
- &__page > &__aside,
18
- &__page > &__blockquote,
19
- &__page > &__faq,
20
- &__page > &__table,
21
- &__page > &__text,
22
- &__page > &__video
23
- @extend .container
24
- margin-bottom: 50px
25
- padding-left: $grid-gutter-width/2
26
- padding-right: $grid-gutter-width/2
27
-
28
- &__page > &__collection,
29
- &__page > &__row
30
- @extend .container
31
- padding-right: 0
32
- padding-left: 0
33
- margin-bottom: 50px
34
-
35
- &__slider
36
- .promethee__component
37
- margin-bottom: 0
38
- .fontawesome-carousel-control .fa
39
- top: 50%
40
- position: absolute
41
- transform: translateY(-50%)
42
- font-size: 30px
43
-
44
- &__collection
45
- margin-top: 20px
46
- margin-bottom: 20px
47
- .clearfix
48
- margin: 40px 0
49
-
50
- &__faq
51
- h4
52
- cursor: pointer
53
- position: relative
54
- &::after
55
- content: ""
56
- display: block
57
- width: 8px
58
- height: 8px
59
- border-right: 2px solid #000
60
- border-top: 2px solid #000
61
- transform: rotate(135deg)
62
- position: absolute
63
- right: 10px
64
- top: 5px
65
- transition: transform .4s ease
66
- &[aria-expanded="true"]
67
- &::after
68
- transform: rotate(315deg)
69
- img
70
- margin-bottom: 30px
71
-
72
- &__aside
73
- .aside__button
74
- padding-top: 30px
75
- a
76
- display: inline-block
77
- &--center
78
- text-align: center
79
- &--left
80
- text-align: left
81
- &--right
82
- text-align: right
83
-
84
- &__blockquote
85
- .blockquote
86
- font-size: 30px
87
- border: none
88
-
89
- p
90
- display: inline
91
-
92
- &::before, &::after
93
- display: inline-block
94
-
95
- &::before
96
- content: '« '
97
-
98
- &::after
99
- content: ' »'
100
-
101
- .author
102
- font-size: 14px
103
- font-style: italic
104
-
105
- &__collection
106
- .collection-item__content
107
- margin-bottom: $grid-gutter-width
108
-
109
- &__slider
110
- .carousel-item__content
111
- text-align: center
12
+ &__component
13
+ &__page > div:not(&__cover):not(&__slider),
14
+ &__page > aside
15
+ @extend .container
16
+ margin-bottom: 50px
17
+ padding-left: $grid-gutter-width/2
18
+ padding-right: $grid-gutter-width/2
19
+
20
+ &__page > &__collection,
21
+ &__page > &__row
22
+ padding-left: 0
23
+ padding-right: 0
24
+
25
+ &__aside
26
+ .aside__button
27
+ padding-top: $grid-gutter-width
28
+ a
29
+ display: inline-block
30
+ &--center
31
+ text-align: center
32
+ &--left
33
+ text-align: left
34
+ &--right
35
+ text-align: right
36
+
37
+ &__blockquote
38
+ .blockquote
39
+ border: none
40
+ font-size: 30px
41
+
42
+ p
43
+ display: inline
44
+
45
+ &::before, &::after
46
+ display: inline-block
47
+
48
+ &::before
49
+ content: '« '
50
+
51
+ &::after
52
+ content: ' »'
53
+
54
+ .author
55
+ font-size: 14px
56
+ font-style: italic
57
+
58
+ &__collection
59
+ margin-bottom: 20px
60
+ margin-top: 20px
61
+ .clearfix
62
+ margin: 40px 0
63
+ .collection-item__content
64
+ margin-bottom: $grid-gutter-width
65
+ a + p
66
+ margin-top: 10px
67
+
68
+ &__cover
69
+ background-position: center center
70
+ background-repeat: no-repeat
71
+ background-size: cover
72
+ display: flex
73
+ flex-direction: column
74
+ justify-content: center
75
+ margin-bottom: 50px
76
+ min-height: 300px
77
+ padding: 150px 30px
78
+ text-align: center
79
+
80
+ p:last-of-type
81
+ margin-bottom: 0
82
+
83
+ &__image
84
+ margin-bottom: $grid-gutter-width
85
+ figcaption
86
+ margin-top: 10px
87
+
88
+ &__faq
89
+ &_item:not(:last-of-type)
90
+ padding-bottom: 10px
91
+ h4
92
+ cursor: pointer
93
+ position: relative
94
+ &::after
95
+ border-right: 2px solid #000
96
+ border-top: 2px solid #000
97
+ content: ''
98
+ display: block
99
+ height: 8px
100
+ position: absolute
101
+ right: 10px
102
+ top: 5px
103
+ transform: rotate(135deg)
104
+ transition: transform .4s ease
105
+ width: 8px
106
+ &[aria-expanded="true"]
107
+ &::after
108
+ transform: rotate(315deg)
109
+ img
110
+ margin-bottom: $grid-gutter-width
111
+
112
+ &__slider
113
+ .promethee__component
114
+ margin-bottom: 0
115
+ .fontawesome-carousel-control .fa
116
+ font-size: 30px
117
+ position: absolute
118
+ top: 50%
119
+ transform: translateY(-50%)
120
+ .carousel-item
121
+ &__content
122
+ text-align: center
123
+ p:last-of-type
124
+ margin-bottom: 0
125
+ margin-top: 10px
112
126
 
113
127
  @media print
114
- body
115
- font-size: 125%
116
- .promethee
117
- &__component
118
- &__page > &__aside,
119
- &__page > &__text,
120
- &__page > &__faq,
121
- &__page > &__table,
122
- &__page > &__video,
123
- &__page > &__collection,
124
- &__page > &__row
125
- max-width: 90% !important
126
- .container
127
- max-width: 90% !important
128
+ body
129
+ font-size: 125%
130
+ .promethee
131
+ &__component
132
+ &__page > div:not(&__cover):not(&__slider)
133
+ max-width: 90%
134
+ .container
135
+ max-width: 90%
@@ -72,6 +72,8 @@ module PrometheeData
72
72
  if key.starts_with? 'searchable_'
73
73
  clean_value = strip_tags value
74
74
  searchable += "#{clean_value} "
75
+ elsif value.class == Hash
76
+ searchable += promethee_extract_searchable_attributes(value)
75
77
  end
76
78
  end
77
79
  searchable
@@ -0,0 +1,77 @@
1
+ module Promethee
2
+ class LocalizeCleanService
3
+ DEFAULT_WHITELIST = {
4
+ "aside" => ["searchable_visible_content", "searchable_collapsed_content", "searchable_open_label"],
5
+ "blockquote" => ["searchable_body", "searchable_author"],
6
+ "collection" => [],
7
+ "collection_item" => ["searchable_caption", "video"],
8
+ "column" => [],
9
+ "cover" => ["searchable_surtitle", "searchable_title", "searchable_subtitle"],
10
+ "faq" => [],
11
+ "faq_item" => ["searchable_title", "searchable_body"],
12
+ "image" => ["searchable_alt", "searchable_caption"],
13
+ "page" => ["searchable_title", "searchable_description"],
14
+ "row" => [],
15
+ "slider" => [],
16
+ "slider_item" => ["searchable_caption", "video"],
17
+ "table" => ["cols", "cols_data", "rows", "rows_data"],
18
+ "text" => ["searchable_body"],
19
+ "video" => ["url"]
20
+ }
21
+
22
+ attr_accessor :objects
23
+
24
+ def initialize(model_name, whitelist = {})
25
+ begin
26
+ model_class = model_name.constantize
27
+ objects = model_class.all
28
+ rescue
29
+ puts 'Please provide a valid model name (e.g. `rake promethee:clean_localizations[Page]`)'
30
+ exit
31
+ end
32
+ @objects = objects
33
+ @whitelist = DEFAULT_WHITELIST.merge(whitelist)
34
+ end
35
+
36
+ def add_rule(type, attributes = [])
37
+ @whitelist[type] = attributes
38
+ end
39
+
40
+ def start
41
+ puts '= START LOCALIZE CLEAN ='
42
+ puts "Number of objects: #{objects.count}"
43
+ i = 0
44
+ objects.each do |object|
45
+ next unless can_process?(object.data)
46
+
47
+ i += 1
48
+ puts "Processing object ##{object.id}"
49
+
50
+ object.data = clean(object.data)
51
+ object.save
52
+ puts "End processing object ##{object.id}"
53
+ end
54
+ puts "Number of processed objects: #{i}"
55
+ puts '====== END CLEANER ========'
56
+ end
57
+
58
+ private
59
+
60
+ def clean(data)
61
+ i = 0
62
+ data["components"].each do |component|
63
+ component_whitelist = @whitelist[component["type"]]
64
+ next if component_whitelist.nil? # Process only types in whitelist
65
+
66
+ i += 1
67
+ component["attributes"]&.slice!(*component_whitelist)
68
+ end
69
+ puts "- #{i} components were processed"
70
+ data
71
+ end
72
+
73
+ def can_process?(data)
74
+ data.is_a?(Hash) && data.has_key?("components")
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,69 @@
1
+ module Promethee
2
+ class TableUpgradeService
3
+ attr_accessor :objects
4
+
5
+ def initialize(model_name)
6
+ begin
7
+ model_class = model_name.constantize
8
+ objects = model_class.all.select { |page| page.data&.to_json&.include? '"type":"table"' }
9
+ rescue
10
+ puts 'Please provide a valid model name (e.g. `rake promethee:clean_localizations[Page]`)'
11
+ exit
12
+ end
13
+ @objects = objects
14
+ end
15
+
16
+ def start
17
+ puts '= START TABLE UPGRADE ='
18
+ puts "Number of objects: #{objects.count}"
19
+ objects.each do |object|
20
+ puts "Processing object ##{object.id}"
21
+
22
+ object.data = process_component(object.data)
23
+ object.save
24
+ puts "End processing object ##{object.id}"
25
+ end
26
+ puts '====== END CLEANER ========'
27
+ end
28
+
29
+ private
30
+
31
+ def process_component(component)
32
+ component = upgrade(component) if component["type"] == "table"
33
+ component["children"].map do |child|
34
+ process_component(child)
35
+ end if component["children"]&.any?
36
+ component
37
+ end
38
+
39
+ def upgrade(component)
40
+ return component unless component.has_key? "attributes"
41
+
42
+ head = component["attributes"]["head"]
43
+ body = component["attributes"]["body"]
44
+ return component if head.nil? || body.nil?
45
+
46
+ cols = create_uids(head)
47
+ rows = create_uids(body)
48
+
49
+ cols_data = head.map.with_index { |col_data, i| [cols[i], col_data] }.to_h
50
+ rows_data = body.map.with_index { |row_data, i|
51
+ new_row_data = row_data.map.with_index { |cell_data, j| [cols[j], cell_data] }.to_h
52
+ [rows[i], new_row_data]
53
+ }.to_h
54
+
55
+ component["attributes"].except!("head", "body")
56
+
57
+ component["attributes"]["cols"] = cols
58
+ component["attributes"]["cols_data"] = cols_data
59
+ component["attributes"]["rows"] = rows
60
+ component["attributes"]["rows_data"] = rows_data
61
+
62
+ component
63
+ end
64
+
65
+ def create_uids(array)
66
+ (0...array.size).map { |_| SecureRandom.hex(5) }
67
+ end
68
+ end
69
+ end
@@ -8,9 +8,31 @@ back_url ||= nil
8
8
  logo = File.read "#{__dir__}/../../assets/images/icon-promethee.svg"
9
9
  %>
10
10
 
11
+ <script type="text/javascript">
12
+ angular
13
+ .module('uid', [])
14
+ .factory('uidService', function () {
15
+ // Option 3 : https://stackoverflow.com/a/27747377
16
+ return {
17
+ generate: function () {
18
+ var arr = new Uint8Array(10 / 2),
19
+ hexArr = [],
20
+ i;
21
+
22
+ (window.crypto || window.msCrypto).getRandomValues(arr);
23
+ for (i = 0; i < arr.length; i += 1) {
24
+ hexArr[i] = ('0' + arr[i].toString(16)).substr(-2);
25
+ }
26
+
27
+ return hexArr.join('');
28
+ }
29
+ };
30
+ });
31
+ </script>
32
+
11
33
  <script type="text/javascript">
12
34
  var promethee = angular
13
- .module('Promethee', ['summernote', 'ngAnimate', 'ngFileUpload', 'ui.sortable', 'colorpicker.module'], ['$rootScopeProvider', function($rootScopeProvider) {
35
+ .module('Promethee', ['summernote', 'ngAnimate', 'ngFileUpload', 'ui.sortable', 'colorpicker.module', 'uid'], ['$rootScopeProvider', function($rootScopeProvider) {
14
36
  $rootScopeProvider.digestTtl(30);
15
37
  }])
16
38
  .value('definitions', [])
@@ -92,16 +114,6 @@ promethee.controller('PrometheeController', ['$scope', 'summernoteConfig', 'pres
92
114
  $scope.inspect = function(component, event) {
93
115
  if(event.target.closest('.promethee-edit__component') === event.currentTarget) {
94
116
  $scope.promethee.inspected = component;
95
- $scope.refreshInspect(component.type);
96
- }
97
- }
98
-
99
- $scope.refreshInspect = function (componentType) {
100
- var inspectContainer = document.querySelector(".promethee-edit__inspect-content--"+componentType);
101
- var summernoteToolbars = inspectContainer.querySelectorAll('.note-toolbar-wrapper');
102
- var i;
103
- for (i = 0 ; i < summernoteToolbars.length ; i += 1) {
104
- summernoteToolbars[i].removeAttribute('style');
105
117
  }
106
118
  }
107
119
 
@@ -1,7 +1,8 @@
1
1
  <script type="text/ng-template" id="promethee/components/collection_item/localize">
2
- <div ng-show="master.attributes.searchable_caption !== ''">
2
+ <div ng-show="master.attributes.searchable_caption !== '' || master.attributes.media_type == 'video'">
3
3
  <hr>
4
- <div class="row">
4
+
5
+ <div class="row" ng-show="master.attributes.searchable_caption !== ''">
5
6
  <div class="col-md-6">
6
7
  <b>Collection Item Caption</b>
7
8
  <div class="promethee-edit__wrapper" ng-bind-html="master.attributes.searchable_caption | htmlSafe"></div>
@@ -11,5 +12,16 @@
11
12
  <summernote config="summernoteConfig" ng-model="component.attributes.searchable_caption"></summernote>
12
13
  </div>
13
14
  </div>
15
+
16
+ <div class="row" ng-show="master.attributes.media_type == 'video'">
17
+ <div class="col-md-6">
18
+ <b>Video URL</b>
19
+ <div ng-bind-html="master.attributes.video.url | htmlSafe"></div>
20
+ </div>
21
+ <div class="col-md-6">
22
+ <label class="label-control">Video URL</label>
23
+ <input class="form-control" ng-model="component.attributes.video.url" type="text">
24
+ </div>
25
+ </div>
14
26
  </div>
15
27
  </script>
@@ -4,7 +4,7 @@
4
4
 
5
5
  <div class="row">
6
6
  <div class="col-md-6">
7
- <img ng-src="/promethee/blob/{{component.attributes.image.id}}" class="img-fluid img-responsive">
7
+ <img ng-src="/promethee/blob/{{master.attributes.image.id}}" class="img-fluid img-responsive">
8
8
  </div>
9
9
  </div>
10
10
 
@@ -1,7 +1,8 @@
1
1
  <script type="text/ng-template" id="promethee/components/slider_item/localize">
2
- <div ng-show="master.attributes.text !== ''">
2
+ <div ng-show="master.attributes.searchable_caption !== '' || master.attributes.media_type == 'video'">
3
3
  <hr>
4
- <div class="row">
4
+
5
+ <div class="row" ng-show="master.attributes.searchable_caption !== ''">
5
6
  <div class="col-md-6">
6
7
  <b>Slider Item Caption</b>
7
8
  <div class="promethee-edit__wrapper" ng-bind-html="master.attributes.searchable_caption | htmlSafe"></div>
@@ -11,5 +12,16 @@
11
12
  <summernote config="summernoteConfig" ng-model="component.attributes.searchable_caption"></summernote>
12
13
  </div>
13
14
  </div>
15
+
16
+ <div class="row" ng-show="master.attributes.media_type == 'video'">
17
+ <div class="col-md-6">
18
+ <b>Video URL</b>
19
+ <div ng-bind-html="master.attributes.video.url | htmlSafe"></div>
20
+ </div>
21
+ <div class="col-md-6">
22
+ <label class="label-control">Video URL</label>
23
+ <input class="form-control" ng-model="component.attributes.video.url" type="text">
24
+ </div>
25
+ </div>
14
26
  </div>
15
27
  </script>
@@ -8,30 +8,10 @@
8
8
  data: {
9
9
  type: 'table',
10
10
  attributes: {
11
- head: [
12
- {
13
- searchable_text: 'Column 1'
14
- },
15
- {
16
- searchable_text: 'Column 2'
17
- },
18
- {
19
- searchable_text: 'Column 3'
20
- }
21
- ],
22
- body: [
23
- [
24
- {
25
- searchable_text: 'Text 1'
26
- },
27
- {
28
- searchable_text: 'Text 2'
29
- },
30
- {
31
- searchable_text: 'Text 3'
32
- }
33
- ]
34
- ]
11
+ cols: [],
12
+ cols_data: {},
13
+ rows: [],
14
+ rows_data: {}
35
15
  }
36
16
  }
37
17
  })
@@ -1,42 +1,102 @@
1
1
  <script type="text/ng-template" id="promethee/components/table/edit/inspect">
2
- <div class="form-group">
3
- <label class="label-control">Head</label><br/>
4
- <div class="btn btn-default btn-light btn-sm"
5
- ng-click="promethee.inspected.attributes.head.push({searchable_text: 'Column'})">
6
- Add column
7
- </div><br/><br/>
8
- <div ng-repeat="th in promethee.inspected.attributes.head track by $index">
9
- <div class="form-row">
10
- <div class="col-10">
11
- <input type="text" ng-model="th.searchable_text" class="form-control" />
2
+ <div ng-controller="TableInspectController" ng-init="component = promethee.inspected">
3
+ <div class="form-group">
4
+ <label class="label-control">Columns</label><br/>
5
+ <div class="btn btn-default btn-light btn-sm"
6
+ ng-click="addColumn()">
7
+ Add column
8
+ </div><br/><br/>
9
+ <div ui-sortable ng-model="component.attributes.cols">
10
+ <div ng-repeat="colUid in component.attributes.cols">
11
+ <div class="form-group row align-items-center">
12
+ <div class="col-1" style="line-height: 38px">
13
+ <i class="fas fa-bars"></i>
14
+ </div>
15
+ <div class="col-9">
16
+ <input type="text"
17
+ ng-model="component.attributes.cols_data[colUid].searchable_text"
18
+ class="form-control" />
19
+ </div>
20
+ <div class="col-2">
21
+ <a class="btn btn-default btn-light btn-sm"
22
+ ng-click="removeColumn(colUid)">
23
+ <%= icon('fa', 'close') %>
24
+ </a>
25
+ </div>
26
+ </div>
12
27
  </div>
13
- <div class="col-2">
14
- <a class="btn btn-default btn-light btn-sm"
15
- ng-click="promethee.inspected.attributes.head.splice($index, 1)">
28
+ </div>
29
+ </div>
30
+ <hr>
31
+ <div class="form-group">
32
+ <label class="label-control">Rows</label><br/>
33
+ <div class="btn btn-default btn-light btn-sm"
34
+ ng-click="addRow()">
35
+ Add row
36
+ </div><br/><br/>
37
+ <div ng-repeat="rowUid in component.attributes.rows track by $index">
38
+ <span class="small">
39
+ <b>Row {{$index+1}}</b>
40
+ <a class="btn btn-default btn-light btn-sm float-right"
41
+ ng-click="removeRow(rowUid)">
16
42
  <%= icon('fa', 'close') %>
17
43
  </a>
44
+ </span><br/>
45
+ <div ng-repeat="colUid in component.attributes.cols">
46
+ <span class="small">
47
+ {{component.attributes.cols_data[colUid].searchable_text}}
48
+ </span>
49
+ <br/>
50
+ <input type="text"
51
+ ng-model="component.attributes.rows_data[rowUid][colUid].searchable_text"
52
+ class="form-control" />
18
53
  </div>
54
+ <hr/>
19
55
  </div>
20
56
  </div>
21
- </div>
22
- <div class="form-group">
23
- <label class="label-control">Body</label><br/>
24
- <div class="btn btn-default btn-light btn-sm"
25
- ng-click="promethee.inspected.attributes.body.push([{searchable_text: 'Text'}])">
26
- Add row
27
- </div><br/><br/>
28
- <div ng-repeat="tr in promethee.inspected.attributes.body track by $index">
29
- <span class="small"><b>Row {{$index+1}}</b>
30
- <a class="btn btn-default btn-light btn-sm float-right"
31
- ng-click="promethee.inspected.attributes.body.splice($index, 1)">
32
- <%= icon('fa', 'close') %>
33
- </a>
34
- </span><br/>
35
- <div ng-repeat="th in promethee.inspected.attributes.head track by $index">
36
- <span class="small">{{th.searchable_text}}</span><br/>
37
- <input type="text" ng-model="tr[$index].searchable_text" class="form-control" />
38
- </div>
39
- <hr/>
57
+ <div class="form-group" ng-show="component.attributes.rows.length > 1">
58
+ <label class="label-control">Drag the rows below to reorder them:</label>
59
+ <ul ui-sortable
60
+ ng-model="component.attributes.rows"
61
+ class="list-unstyled">
62
+ <li ng-repeat="_ in component.attributes.rows track by $index">
63
+ <%= icon('fa', 'bars') %> Row {{$index + 1}}
64
+ </li>
65
+ </ul>
40
66
  </div>
41
67
  </div>
42
68
  </script>
69
+
70
+ <script>
71
+ promethee.controller('TableInspectController', ['$scope', 'uidService', function($scope, uidService) {
72
+ $scope.addColumn = function () {
73
+ var uid = uidService.generate();
74
+ $scope.component.attributes.cols.push(uid);
75
+ $scope.component.attributes.cols_data[uid] = { searchable_text: 'New column' };
76
+ }
77
+
78
+ $scope.addRow = function () {
79
+ var uid = uidService.generate();
80
+ $scope.component.attributes.rows.push(uid);
81
+
82
+ console.log($scope.component.attributes);
83
+ }
84
+
85
+ $scope.removeItem = function (uid, arrayKey) {
86
+ var dataKey = arrayKey + '_data';
87
+ var index = $scope.component.attributes[arrayKey].indexOf(uid);
88
+ if (index !== -1) {
89
+ $scope.component.attributes[arrayKey].splice(index, 1);
90
+ delete $scope.component.attributes[dataKey][uid];
91
+ }
92
+ }
93
+
94
+ $scope.removeColumn = function (uid) {
95
+ $scope.removeItem(uid, 'cols');
96
+ }
97
+
98
+ $scope.removeRow = function (uid) {
99
+ $scope.removeItem(uid, 'rows');
100
+ }
101
+ }]);
102
+ </script>
@@ -4,12 +4,16 @@
4
4
  <table class="table">
5
5
  <thead>
6
6
  <tr>
7
- <th ng-repeat="th in component.attributes.head track by $index">{{th.searchable_text}}</th>
7
+ <th ng-repeat="colUid in component.attributes.cols">
8
+ {{component.attributes.cols_data[colUid].searchable_text}}
9
+ </th>
8
10
  </tr>
9
11
  </thead>
10
12
  <tbody>
11
- <tr ng-repeat="tr in component.attributes.body track by $index">
12
- <td ng-repeat="td in tr track by $index">{{td.searchable_text}}</td>
13
+ <tr ng-repeat="rowUid in component.attributes.rows">
14
+ <td ng-repeat="colUid in component.attributes.cols">
15
+ {{component.attributes.rows_data[rowUid][colUid].searchable_text}}
16
+ </td>
13
17
  </tr>
14
18
  </tbody>
15
19
  </table>
@@ -6,12 +6,16 @@
6
6
  <table class="table">
7
7
  <thead>
8
8
  <tr>
9
- <th ng-repeat="th in master.attributes.head track by $index">{{th.searchable_text}}</th>
9
+ <th ng-repeat="colUid in master.attributes.cols track by $index">
10
+ {{ master.attributes.cols_data[colUid].searchable_text }}
11
+ </th>
10
12
  </tr>
11
13
  </thead>
12
14
  <tbody>
13
- <tr ng-repeat="tr in master.attributes.body track by $index">
14
- <td ng-repeat="td in tr track by $index">{{td.searchable_text}}</td>
15
+ <tr ng-repeat="rowUid in master.attributes.rows">
16
+ <td ng-repeat="colUid in master.attributes.cols">
17
+ {{ master.attributes.rows_data[rowUid][colUid].searchable_text }}
18
+ </td>
15
19
  </tr>
16
20
  </tbody>
17
21
  </table>
@@ -20,15 +24,19 @@
20
24
  <table class="table">
21
25
  <thead>
22
26
  <tr>
23
- <th ng-repeat="th in component.attributes.head track by $index">
24
- <input class="form-control" ng-model="th.searchable_text" type="text">
27
+ <th ng-repeat="colUid in master.attributes.cols track by $index">
28
+ <input type="text"
29
+ ng-model="component.attributes.cols_data[colUid].searchable_text"
30
+ class="form-control">
25
31
  </th>
26
32
  </tr>
27
33
  </thead>
28
34
  <tbody>
29
- <tr ng-repeat="tr in component.attributes.body track by $index">
30
- <td ng-repeat="td in tr track by $index">
31
- <input class="form-control" ng-model="td.searchable_text" type="text">
35
+ <tr ng-repeat="rowUid in master.attributes.rows">
36
+ <td ng-repeat="colUid in master.attributes.cols">
37
+ <input class="form-control"
38
+ ng-model="component.attributes.rows_data[rowUid][colUid].searchable_text"
39
+ type="text">
32
40
  </td>
33
41
  </tr>
34
42
  </tbody>
@@ -1,24 +1,37 @@
1
+ <%
2
+ return unless ([:cols, :cols_data, :rows, :rows_data] - component[:attributes].keys).empty?
3
+ columns = component[:attributes][:cols].map { |colUid|
4
+ colData = component[:attributes][:cols_data][colUid.to_sym] || {}
5
+ { uid: colUid, searchable_text: colData[:searchable_text] }
6
+ }
7
+
8
+ rows = component[:attributes][:rows].map { |rowUid|
9
+ rowData = component[:attributes][:rows_data][rowUid.to_sym] || {}
10
+ { uid: rowUid, data: rowData }
11
+ }
12
+ %>
13
+
1
14
  <div id="component-<%= component[:id] %>" class="<%= promethee_class_for(component) %>">
2
15
  <div class="table-responsive">
3
16
  <table class="table">
4
17
  <thead>
5
18
  <tr>
6
- <% component[:attributes][:head].each do |th| %>
7
- <th><%= th[:searchable_text] if th.has_key? :searchable_text %></th>
19
+ <% columns.each do |col| %>
20
+ <th><%= col[:searchable_text] %></th>
8
21
  <% end %>
9
22
  </tr>
10
23
  </thead>
11
24
  <tbody>
12
- <% component[:attributes][:body].each do |tr| %>
13
- <% if tr.select { |td| td[:searchable_text]&.present? }.count == 0 %>
14
- <tr></tr>
15
- <% else %>
16
- <tr>
17
- <% tr.each do |td| %>
18
- <td><%= td[:searchable_text] if td.has_key? :searchable_text %></td>
19
- <% end %>
20
- </tr>
21
- <% end %>
25
+ <% rows.each do |row| %>
26
+ <tr>
27
+ <% columns.each do |col| %>
28
+ <%
29
+ cell = row[:data][col[:uid].to_sym]
30
+ next if cell.nil?
31
+ %>
32
+ <td><%= cell[:searchable_text] %></td>
33
+ <% end %>
34
+ </tr>
22
35
  <% end %>
23
36
  </tbody>
24
37
  </table>
@@ -108,8 +108,7 @@ promethee
108
108
  // console.log('dropped', component, droppedToList, droppedToIndex);
109
109
  droppedToList.splice(droppedToIndex, 0, component);
110
110
 
111
- scope.promethee.inspected = component
112
- scope.refreshInspect(component.type);
111
+ scope.promethee.inspected = component;
113
112
 
114
113
  scope.$apply();
115
114
  }
@@ -155,7 +154,7 @@ promethee
155
154
  <div class="promethee-edit__inspect-content">
156
155
  <div ng-repeat="definition in promethee.definitions | orderBy:'position'">
157
156
  <ng-include src="'promethee/components/' + definition.data.type + '/edit/inspect'"
158
- ng-show="promethee.inspected.type == definition.data.type"
157
+ ng-if="promethee.inspected.type == definition.data.type"
159
158
  class="promethee-edit__inspect-content--{{ definition.data.type }}"></ng-include>
160
159
  </div>
161
160
  </div>
@@ -27,7 +27,7 @@
27
27
  "children": [
28
28
  {
29
29
  "type": "text",
30
- "attributes": {"body": "<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. A dicta, est quos distinctio culpa! Quasi cupiditate, totam nulla reprehenderit animi iusto qui cumque culpa repellat eum sit? Debitis, laboriosam reiciendis!</p>"}
30
+ "attributes": {"searchable_body": "<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. A dicta, est quos distinctio culpa! Quasi cupiditate, totam nulla reprehenderit animi iusto qui cumque culpa repellat eum sit? Debitis, laboriosam reiciendis!</p>"}
31
31
  }
32
32
  ]
33
33
  }
@@ -25,7 +25,8 @@ class Promethee::Data::Localization < Promethee::Data
25
25
  @master_data.flat.each do |master_component|
26
26
  localized_component = find_localized_component master_component[:id]
27
27
  # We take the localized component if it exists, the master component otherwise
28
- component = localized_component || master_component
28
+ component = localized_component || master_component.except(:attributes)
29
+ component[:attributes] ||= {}
29
30
  # We add it to the list of localized components
30
31
  @data[:components] << component
31
32
  end
@@ -18,9 +18,11 @@ class Promethee::Data::MasterLocalized < Promethee::Data
18
18
  def localize_component_attributes(component)
19
19
  localized_component = find_localized_component component[:id]
20
20
  return if (localized_component.nil? || !localized_component.include?(:attributes))
21
- component[:attributes].merge! localized_component[:attributes]
21
+ component[:attributes].deep_merge_existing_keys! localized_component[:attributes]
22
22
  end
23
23
 
24
+
25
+
24
26
  def localize_component_children(component)
25
27
  component[:children].each { |child| localize_component child }
26
28
  end
@@ -1,5 +1,5 @@
1
1
  module Promethee
2
2
  module Rails
3
- VERSION = '1.11.29'
3
+ VERSION = '2.0.0'
4
4
  end
5
5
  end
data/lib/promethee.rb CHANGED
@@ -3,6 +3,7 @@ require 'jquery-rails'
3
3
  require 'jquery-ui-rails'
4
4
  require 'angularjs-rails'
5
5
  require 'summernote-rails'
6
+ require 'deep_merge_existing_keys'
6
7
 
7
8
  module Promethee
8
9
  def self.root
@@ -1,4 +1,15 @@
1
- # desc "Explaining what the task does"
2
- # task :promethee do
3
- # # Task goes here
4
- # end
1
+ namespace :promethee do
2
+
3
+ desc "Remove useless attributes from localizations' data"
4
+ task :clean_localizations, [:model_name] => :environment do |task, args|
5
+ service = Promethee::LocalizeCleanService.new(args[:model_name])
6
+ service.start
7
+ end
8
+
9
+ desc "Upgrade your table components' to 2.x structure"
10
+ task :upgrade_table, [:model_name] => :environment do |task, args|
11
+ service = Promethee::TableUpgradeService.new(args[:model_name])
12
+ service.start
13
+ end
14
+
15
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: promethee
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.11.29
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sébastien Gaya
@@ -14,7 +14,7 @@ authors:
14
14
  autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
- date: 2019-04-26 00:00:00.000000000 Z
17
+ date: 2019-05-15 00:00:00.000000000 Z
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
20
  name: rails
@@ -128,6 +128,20 @@ dependencies:
128
128
  - - "~>"
129
129
  - !ruby/object:Gem::Version
130
130
  version: 0.8.10.0
131
+ - !ruby/object:Gem::Dependency
132
+ name: deep_merge_existing_keys
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ type: :runtime
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
131
145
  - !ruby/object:Gem::Dependency
132
146
  name: byebug
133
147
  requirement: !ruby/object:Gem::Requirement
@@ -157,6 +171,7 @@ extra_rdoc_files: []
157
171
  files:
158
172
  - README.md
159
173
  - Rakefile
174
+ - UPGRADING
160
175
  - app/assets/images/icon-promethee.png
161
176
  - app/assets/images/icon-promethee.svg
162
177
  - app/assets/images/loader.gif
@@ -176,6 +191,8 @@ files:
176
191
  - app/assets/stylesheets/promethee.sass
177
192
  - app/controllers/promethee_controller.rb
178
193
  - app/models/concerns/promethee_data.rb
194
+ - app/services/promethee/localize_clean_service.rb
195
+ - app/services/promethee/table_upgrade_service.rb
179
196
  - app/views/promethee/_edit.html.erb
180
197
  - app/views/promethee/_localize.html.erb
181
198
  - app/views/promethee/_show.html.erb
@@ -430,7 +447,17 @@ homepage: https://github.com/lespoupeesrusses/promethee
430
447
  licenses:
431
448
  - MIT
432
449
  metadata: {}
433
- post_install_message:
450
+ post_install_message: |-
451
+ ##########################################
452
+ # NOTE FOR UPGRADING TO 2.0.0 OR LATER #
453
+ ##########################################
454
+
455
+ Prométhée 2.0 brings:
456
+ - [BREAKING CHANGE] New structure for table component. A rake task is available to update them in your master models. Localization has to be manual.
457
+ - [TOOL TO FIX ISSUE] A rake task to clean your localization models.
458
+
459
+ For more details, check the documentation:
460
+ https://github.com/lespoupeesrusses/promethee/tree/dev-2.0/doc
434
461
  rdoc_options: []
435
462
  require_paths:
436
463
  - lib