kuhsaft 1.7.1 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 76dbe731782470b70b5f4e800df56a90940025dd
4
+ data.tar.gz: 863e59213b956cb04fbb9c289e0e2a9cda6f04c3
5
+ SHA512:
6
+ metadata.gz: 3225ea8917bd257a8bad15171de011d8cd6a4a400d2297eb5c1136418323fba0ef25e1eb8bb0172436ac513f0f2a7aa1cbadde5a527589b51e09c525a9fae8c9
7
+ data.tar.gz: 2babddfa702eb7b132703f846d44b37d25af7b7564d1256b5a740b7660dcd8df1b56a34ba2e25d6d738c272aac45d4d39b3567a15a9f7fefe0e76c6e68679679
data/README.md CHANGED
@@ -61,6 +61,18 @@ Load the Kuhsaft assets into your app, so you have working grids, widgets etc:
61
61
  # application.js.coffee
62
62
  //= require 'kuhsaft/application'
63
63
 
64
+ Finally, you need to define the image sizes for the image brick or use
65
+ the defaults:
66
+
67
+ # your_app/config/initializers/kuhsaft.rb
68
+ Rails.application.config.to_prepare do
69
+ Kuhsaft::Engine.configure do
70
+ config.image_sizes.build_defaults! # creates 960x540 and 320x180 sizes
71
+ end
72
+ end
73
+
74
+ See "Customizing The Image Brick" for more details.
75
+
64
76
  ## Authentication
65
77
 
66
78
  Kuhsaft itself does not ship with any form of authentication. However, it is fairly easy to add by plugging into the Kuhsaft::Cms::AdminController. An example with devise:
@@ -9,6 +9,7 @@
9
9
  #= require jquery_ujs
10
10
  #= require bootstrap
11
11
  #= require ckeditor/init
12
+ #= require jquery.nestable
12
13
  #= require_tree .
13
14
 
14
15
  CKEDITOR.config.customConfig = '/assets/kuhsaft/cms/ck-config.js'
@@ -79,3 +80,14 @@ $(document).ready ->
79
80
 
80
81
  $('#page_page_type').change ->
81
82
  checkPageType()
83
+
84
+ $('.dd').nestable(
85
+ collapseBtnHTML: '<button data-action="collapse"><i class="icon-minus-sign"></i></button>'
86
+ expandBtnHTML: '<button data-action="expand"><i class="icon-plus-sign"></i></button>'
87
+ )
88
+
89
+ $('.dd').on('change', ->
90
+ pageTree = $('.dd').nestable('serialize')
91
+ url = '/cms/pages/sort'
92
+ $.post(url, { page_tree: pageTree }, "json")
93
+ )
@@ -11,6 +11,7 @@ $borderRadiusSmall: 0px
11
11
 
12
12
  @import bootstrap
13
13
  @import compass/css3
14
+ @import nestable
14
15
 
15
16
  // base styles
16
17
 
@@ -118,8 +119,6 @@ form
118
119
  padding: 0.35em 0
119
120
 
120
121
  .unpublished
121
- background-color: #f1f1f1
122
-
123
122
  a
124
123
  color: #666
125
124
 
@@ -1,3 +1,5 @@
1
+ require 'kuhsaft/page_tree'
2
+
1
3
  module Kuhsaft
2
4
  module Cms
3
5
  class PagesController < AdminController
@@ -49,6 +51,10 @@ module Kuhsaft
49
51
  @page.destroy
50
52
  redirect_to kuhsaft.cms_pages_path
51
53
  end
54
+
55
+ def sort
56
+ Kuhsaft::PageTree.update(params[:page_tree])
57
+ end
52
58
  end
53
59
  end
54
60
  end
@@ -24,7 +24,8 @@ class Kuhsaft::Page < ActiveRecord::Base
24
24
  :parent_id,
25
25
  :keywords,
26
26
  :description,
27
- :published
27
+ :published,
28
+ :position
28
29
 
29
30
  default_scope order('position ASC')
30
31
 
@@ -1,12 +1,13 @@
1
1
  - unless pages.blank?
2
- - pages.each do |page|
3
- .branch-group{ :'data-id' => page.id, :'data-put-url' => kuhsaft.cms_page_path(page) }
4
- .row-fluid.branch{ :class => page.state_class }
5
- .span9
6
- .branch-title
7
- = link_to page.title.presence, kuhsaft.edit_cms_page_path(page), :class => 'btn btn-link'
8
- .span3
9
- .pull-right
2
+ %ol.dd-list
3
+ - pages.each do |page|
4
+ %li.dd-item.dd3-item{ 'data-id' => page.id }
5
+ .dd-handle.dd3-handle
6
+ handle
7
+ .dd3-content{ class: page.state_class }
8
+ = link_to page.title.presence, kuhsaft.edit_cms_page_path(page)
9
+
10
+ .button-group
10
11
  - if page.children.empty?
11
12
  = link_to kuhsaft.cms_page_path(page), :confirm => t('kuhsaft.cms.admin.confirm_delete', :name => page.title), :method => :delete, :class => 'btn btn-small btn-danger' do
12
13
  %i.icon-trash.icon-white
@@ -15,5 +16,5 @@
15
16
  %i.icon-plus-sign
16
17
  = t('kuhsaft.cms.pages.index.add_page')
17
18
 
18
- - unless page.children.empty?
19
- = render :partial => 'branch', :locals => { :pages => page.children }
19
+ - unless page.children.empty?
20
+ = render partial: 'branch', locals: { pages: page.children }
@@ -2,12 +2,13 @@
2
2
  .actions.row
3
3
  .span5
4
4
  .span3
5
- = link_to kuhsaft.new_cms_page_path, :class => 'btn btn-primary' do
5
+ = link_to kuhsaft.new_cms_page_path, class: 'btn btn-primary' do
6
6
  %i.icon-plus-sign.icon-white
7
7
  = t('.add_page')
8
8
  .span4
9
9
 
10
10
  .row
11
11
  .span8.pages-list
12
- = render :partial => 'branch', :locals => { :pages => @pages }
12
+ .dd
13
+ = render partial: 'branch', locals: { pages: @pages }
13
14
  .span4
@@ -1,6 +1,8 @@
1
1
  Kuhsaft::Engine.routes.draw do
2
2
  namespace :cms do
3
- resources :pages, :except => :show
3
+ resources :pages, :except => :show do
4
+ post :sort, :on => :collection
5
+ end
4
6
  resources :bricks, :except => [:new, :edit, :index] do
5
7
  post :sort, :on => :collection
6
8
  end
@@ -0,0 +1,15 @@
1
+ module Kuhsaft
2
+ module PageTree
3
+ extend self
4
+
5
+ def update(params, parent_id = nil)
6
+ params.each do |page_position, page_content|
7
+ page = Page.find(page_content['id'])
8
+ page.update_attributes(parent_id: parent_id, position: page_position)
9
+ unless page_content['children'].nil?
10
+ update(page_content['children'], page.id)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,3 +1,3 @@
1
1
  module Kuhsaft
2
- VERSION = "1.7.1"
2
+ VERSION = "1.8.0"
3
3
  end
@@ -2,6 +2,7 @@ FactoryGirl.define do
2
2
  sequence(:title) { |n| n }
3
3
 
4
4
  factory :page, :class => 'Kuhsaft::Page' do |p|
5
+ p.parent nil
5
6
  p.position 1
6
7
  p.title { "English Title #{FactoryGirl.generate(:title)}" }
7
8
  p.published 1
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+ require_relative '../../lib/kuhsaft/page_tree'
3
+ require_relative '../../app/models/kuhsaft/page'
4
+
5
+ # TODO: THESE SPECS ONLY WORK WHEN THE FULL SUITE IS RUN. FIX THAT!
6
+
7
+ module Kuhsaft
8
+ describe PageTree do
9
+ let(:page_tree) { {"0"=>{"id"=>"1", "children"=>{"0"=>{"id"=>"2"}}},
10
+ "1"=>{"id"=>"3"}}}
11
+
12
+ before :each do
13
+ @page1 = FactoryGirl.create(:page, id: 1, position: 10)
14
+ @page2 = FactoryGirl.create(:page, id: 2, position: 10)
15
+ @page3 = FactoryGirl.create(:page, id: 3, position: 10)
16
+ end
17
+
18
+ describe 'update' do
19
+ it 'sets the correct position of the root nodes' do
20
+ PageTree.update(page_tree)
21
+ @page1.reload.position.should == 0
22
+ @page2.reload.position.should == 0
23
+ @page3.reload.position.should == 1
24
+ end
25
+
26
+ it 'sets the correct parent attribute for the nodes' do
27
+ PageTree.update(page_tree)
28
+ @page1.reload.parent_id.should be_nil
29
+ @page2.reload.parent_id.should == 1
30
+ @page3.reload.parent_id.should be nil
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,485 @@
1
+ /*!
2
+ * Nestable jQuery Plugin - Copyright (c) 2012 David Bushell - http://dbushell.com/
3
+ * Dual-licensed under the BSD or MIT licenses
4
+ */
5
+ ;(function($, window, document, undefined)
6
+ {
7
+ var hasTouch = 'ontouchstart' in window;
8
+
9
+ /**
10
+ * Detect CSS pointer-events property
11
+ * events are normally disabled on the dragging element to avoid conflicts
12
+ * https://github.com/ausi/Feature-detection-technique-for-pointer-events/blob/master/modernizr-pointerevents.js
13
+ */
14
+ var hasPointerEvents = (function()
15
+ {
16
+ var el = document.createElement('div'),
17
+ docEl = document.documentElement;
18
+ if (!('pointerEvents' in el.style)) {
19
+ return false;
20
+ }
21
+ el.style.pointerEvents = 'auto';
22
+ el.style.pointerEvents = 'x';
23
+ docEl.appendChild(el);
24
+ var supports = window.getComputedStyle && window.getComputedStyle(el, '').pointerEvents === 'auto';
25
+ docEl.removeChild(el);
26
+ return !!supports;
27
+ })();
28
+
29
+ var eStart = hasTouch ? 'touchstart' : 'mousedown',
30
+ eMove = hasTouch ? 'touchmove' : 'mousemove',
31
+ eEnd = hasTouch ? 'touchend' : 'mouseup';
32
+ eCancel = hasTouch ? 'touchcancel' : 'mouseup';
33
+
34
+ var defaults = {
35
+ listNodeName : 'ol',
36
+ itemNodeName : 'li',
37
+ rootClass : 'dd',
38
+ listClass : 'dd-list',
39
+ itemClass : 'dd-item',
40
+ dragClass : 'dd-dragel',
41
+ handleClass : 'dd-handle',
42
+ collapsedClass : 'dd-collapsed',
43
+ placeClass : 'dd-placeholder',
44
+ noDragClass : 'dd-nodrag',
45
+ emptyClass : 'dd-empty',
46
+ expandBtnHTML : '<button data-action="expand" type="button">Expand</button>',
47
+ collapseBtnHTML : '<button data-action="collapse" type="button">Collapse</button>',
48
+ group : 0,
49
+ maxDepth : 5,
50
+ threshold : 20
51
+ };
52
+
53
+ function Plugin(element, options)
54
+ {
55
+ this.w = $(window);
56
+ this.el = $(element);
57
+ this.options = $.extend({}, defaults, options);
58
+ this.init();
59
+ }
60
+
61
+ Plugin.prototype = {
62
+
63
+ init: function()
64
+ {
65
+ var list = this;
66
+
67
+ list.reset();
68
+
69
+ list.el.data('nestable-group', this.options.group);
70
+
71
+ list.placeEl = $('<div class="' + list.options.placeClass + '"/>');
72
+
73
+ $.each(this.el.find(list.options.itemNodeName), function(k, el) {
74
+ list.setParent($(el));
75
+ });
76
+
77
+ list.el.on('click', 'button', function(e) {
78
+ if (list.dragEl || (!hasTouch && e.button !== 0)) {
79
+ return;
80
+ }
81
+ var target = $(e.currentTarget),
82
+ action = target.data('action'),
83
+ item = target.parent(list.options.itemNodeName);
84
+ if (action === 'collapse') {
85
+ list.collapseItem(item);
86
+ }
87
+ if (action === 'expand') {
88
+ list.expandItem(item);
89
+ }
90
+ });
91
+
92
+ var onStartEvent = function(e)
93
+ {
94
+ var handle = $(e.target);
95
+ if (!handle.hasClass(list.options.handleClass)) {
96
+ if (handle.closest('.' + list.options.noDragClass).length) {
97
+ return;
98
+ }
99
+ handle = handle.closest('.' + list.options.handleClass);
100
+ }
101
+ if (!handle.length || list.dragEl || (!hasTouch && e.button !== 0) || (hasTouch && e.touches.length !== 1)) {
102
+ return;
103
+ }
104
+ e.preventDefault();
105
+ list.dragStart(hasTouch ? e.touches[0] : e);
106
+ };
107
+
108
+ var onMoveEvent = function(e)
109
+ {
110
+ if (list.dragEl) {
111
+ e.preventDefault();
112
+ list.dragMove(hasTouch ? e.touches[0] : e);
113
+ }
114
+ };
115
+
116
+ var onEndEvent = function(e)
117
+ {
118
+ if (list.dragEl) {
119
+ e.preventDefault();
120
+ list.dragStop(hasTouch ? e.touches[0] : e);
121
+ }
122
+ };
123
+
124
+ if (hasTouch) {
125
+ list.el[0].addEventListener(eStart, onStartEvent, false);
126
+ window.addEventListener(eMove, onMoveEvent, false);
127
+ window.addEventListener(eEnd, onEndEvent, false);
128
+ window.addEventListener(eCancel, onEndEvent, false);
129
+ } else {
130
+ list.el.on(eStart, onStartEvent);
131
+ list.w.on(eMove, onMoveEvent);
132
+ list.w.on(eEnd, onEndEvent);
133
+ }
134
+
135
+ },
136
+
137
+ serialize: function()
138
+ {
139
+ var data,
140
+ depth = 0,
141
+ list = this;
142
+ step = function(level, depth)
143
+ {
144
+ var array = [ ],
145
+ items = level.children(list.options.itemNodeName);
146
+ items.each(function()
147
+ {
148
+ var li = $(this),
149
+ item = $.extend({}, li.data()),
150
+ sub = li.children(list.options.listNodeName);
151
+ if (sub.length) {
152
+ item.children = step(sub, depth + 1);
153
+ }
154
+ array.push(item);
155
+ });
156
+ return array;
157
+ };
158
+ data = step(list.el.find(list.options.listNodeName).first(), depth);
159
+ return data;
160
+ },
161
+
162
+ serialise: function()
163
+ {
164
+ return this.serialize();
165
+ },
166
+
167
+ reset: function()
168
+ {
169
+ this.mouse = {
170
+ offsetX : 0,
171
+ offsetY : 0,
172
+ startX : 0,
173
+ startY : 0,
174
+ lastX : 0,
175
+ lastY : 0,
176
+ nowX : 0,
177
+ nowY : 0,
178
+ distX : 0,
179
+ distY : 0,
180
+ dirAx : 0,
181
+ dirX : 0,
182
+ dirY : 0,
183
+ lastDirX : 0,
184
+ lastDirY : 0,
185
+ distAxX : 0,
186
+ distAxY : 0
187
+ };
188
+ this.moving = false;
189
+ this.dragEl = null;
190
+ this.dragRootEl = null;
191
+ this.dragDepth = 0;
192
+ this.hasNewRoot = false;
193
+ this.pointEl = null;
194
+ },
195
+
196
+ expandItem: function(li)
197
+ {
198
+ li.removeClass(this.options.collapsedClass);
199
+ li.children('[data-action="expand"]').hide();
200
+ li.children('[data-action="collapse"]').show();
201
+ li.children(this.options.listNodeName).show();
202
+ },
203
+
204
+ collapseItem: function(li)
205
+ {
206
+ var lists = li.children(this.options.listNodeName);
207
+ if (lists.length) {
208
+ li.addClass(this.options.collapsedClass);
209
+ li.children('[data-action="collapse"]').hide();
210
+ li.children('[data-action="expand"]').show();
211
+ li.children(this.options.listNodeName).hide();
212
+ }
213
+ },
214
+
215
+ expandAll: function()
216
+ {
217
+ var list = this;
218
+ list.el.find(list.options.itemNodeName).each(function() {
219
+ list.expandItem($(this));
220
+ });
221
+ },
222
+
223
+ collapseAll: function()
224
+ {
225
+ var list = this;
226
+ list.el.find(list.options.itemNodeName).each(function() {
227
+ list.collapseItem($(this));
228
+ });
229
+ },
230
+
231
+ setParent: function(li)
232
+ {
233
+ if (li.children(this.options.listNodeName).length) {
234
+ li.prepend($(this.options.expandBtnHTML));
235
+ li.prepend($(this.options.collapseBtnHTML));
236
+ }
237
+ li.children('[data-action="expand"]').hide();
238
+ },
239
+
240
+ unsetParent: function(li)
241
+ {
242
+ li.removeClass(this.options.collapsedClass);
243
+ li.children('[data-action]').remove();
244
+ li.children(this.options.listNodeName).remove();
245
+ },
246
+
247
+ dragStart: function(e)
248
+ {
249
+ var mouse = this.mouse,
250
+ target = $(e.target),
251
+ dragItem = target.closest(this.options.itemNodeName);
252
+
253
+ this.placeEl.css('height', dragItem.height());
254
+
255
+ mouse.offsetX = e.offsetX !== undefined ? e.offsetX : e.pageX - target.offset().left;
256
+ mouse.offsetY = e.offsetY !== undefined ? e.offsetY : e.pageY - target.offset().top;
257
+ mouse.startX = mouse.lastX = e.pageX;
258
+ mouse.startY = mouse.lastY = e.pageY;
259
+
260
+ this.dragRootEl = this.el;
261
+
262
+ this.dragEl = $(document.createElement(this.options.listNodeName)).addClass(this.options.listClass + ' ' + this.options.dragClass);
263
+ this.dragEl.css('width', dragItem.width());
264
+
265
+ // fix for zepto.js
266
+ //dragItem.after(this.placeEl).detach().appendTo(this.dragEl);
267
+ dragItem.after(this.placeEl);
268
+ dragItem[0].parentNode.removeChild(dragItem[0]);
269
+ dragItem.appendTo(this.dragEl);
270
+
271
+ $(document.body).append(this.dragEl);
272
+ this.dragEl.css({
273
+ 'left' : e.pageX - mouse.offsetX,
274
+ 'top' : e.pageY - mouse.offsetY
275
+ });
276
+ // total depth of dragging item
277
+ var i, depth,
278
+ items = this.dragEl.find(this.options.itemNodeName);
279
+ for (i = 0; i < items.length; i++) {
280
+ depth = $(items[i]).parents(this.options.listNodeName).length;
281
+ if (depth > this.dragDepth) {
282
+ this.dragDepth = depth;
283
+ }
284
+ }
285
+ },
286
+
287
+ dragStop: function(e)
288
+ {
289
+ // fix for zepto.js
290
+ //this.placeEl.replaceWith(this.dragEl.children(this.options.itemNodeName + ':first').detach());
291
+ var el = this.dragEl.children(this.options.itemNodeName).first();
292
+ el[0].parentNode.removeChild(el[0]);
293
+ this.placeEl.replaceWith(el);
294
+
295
+ this.dragEl.remove();
296
+ this.el.trigger('change');
297
+ if (this.hasNewRoot) {
298
+ this.dragRootEl.trigger('change');
299
+ }
300
+ this.reset();
301
+ },
302
+
303
+ dragMove: function(e)
304
+ {
305
+ var list, parent, prev, next, depth,
306
+ opt = this.options,
307
+ mouse = this.mouse;
308
+
309
+ this.dragEl.css({
310
+ 'left' : e.pageX - mouse.offsetX,
311
+ 'top' : e.pageY - mouse.offsetY
312
+ });
313
+
314
+ // mouse position last events
315
+ mouse.lastX = mouse.nowX;
316
+ mouse.lastY = mouse.nowY;
317
+ // mouse position this events
318
+ mouse.nowX = e.pageX;
319
+ mouse.nowY = e.pageY;
320
+ // distance mouse moved between events
321
+ mouse.distX = mouse.nowX - mouse.lastX;
322
+ mouse.distY = mouse.nowY - mouse.lastY;
323
+ // direction mouse was moving
324
+ mouse.lastDirX = mouse.dirX;
325
+ mouse.lastDirY = mouse.dirY;
326
+ // direction mouse is now moving (on both axis)
327
+ mouse.dirX = mouse.distX === 0 ? 0 : mouse.distX > 0 ? 1 : -1;
328
+ mouse.dirY = mouse.distY === 0 ? 0 : mouse.distY > 0 ? 1 : -1;
329
+ // axis mouse is now moving on
330
+ var newAx = Math.abs(mouse.distX) > Math.abs(mouse.distY) ? 1 : 0;
331
+
332
+ // do nothing on first move
333
+ if (!mouse.moving) {
334
+ mouse.dirAx = newAx;
335
+ mouse.moving = true;
336
+ return;
337
+ }
338
+
339
+ // calc distance moved on this axis (and direction)
340
+ if (mouse.dirAx !== newAx) {
341
+ mouse.distAxX = 0;
342
+ mouse.distAxY = 0;
343
+ } else {
344
+ mouse.distAxX += Math.abs(mouse.distX);
345
+ if (mouse.dirX !== 0 && mouse.dirX !== mouse.lastDirX) {
346
+ mouse.distAxX = 0;
347
+ }
348
+ mouse.distAxY += Math.abs(mouse.distY);
349
+ if (mouse.dirY !== 0 && mouse.dirY !== mouse.lastDirY) {
350
+ mouse.distAxY = 0;
351
+ }
352
+ }
353
+ mouse.dirAx = newAx;
354
+
355
+ /**
356
+ * move horizontal
357
+ */
358
+ if (mouse.dirAx && mouse.distAxX >= opt.threshold) {
359
+ // reset move distance on x-axis for new phase
360
+ mouse.distAxX = 0;
361
+ prev = this.placeEl.prev(opt.itemNodeName);
362
+ // increase horizontal level if previous sibling exists and is not collapsed
363
+ if (mouse.distX > 0 && prev.length && !prev.hasClass(opt.collapsedClass)) {
364
+ // cannot increase level when item above is collapsed
365
+ list = prev.find(opt.listNodeName).last();
366
+ // check if depth limit has reached
367
+ depth = this.placeEl.parents(opt.listNodeName).length;
368
+ if (depth + this.dragDepth <= opt.maxDepth) {
369
+ // create new sub-level if one doesn't exist
370
+ if (!list.length) {
371
+ list = $('<' + opt.listNodeName + '/>').addClass(opt.listClass);
372
+ list.append(this.placeEl);
373
+ prev.append(list);
374
+ this.setParent(prev);
375
+ } else {
376
+ // else append to next level up
377
+ list = prev.children(opt.listNodeName).last();
378
+ list.append(this.placeEl);
379
+ }
380
+ }
381
+ }
382
+ // decrease horizontal level
383
+ if (mouse.distX < 0) {
384
+ // we can't decrease a level if an item preceeds the current one
385
+ next = this.placeEl.next(opt.itemNodeName);
386
+ if (!next.length) {
387
+ parent = this.placeEl.parent();
388
+ this.placeEl.closest(opt.itemNodeName).after(this.placeEl);
389
+ if (!parent.children().length) {
390
+ this.unsetParent(parent.parent());
391
+ }
392
+ }
393
+ }
394
+ }
395
+
396
+ var isEmpty = false;
397
+
398
+ // find list item under cursor
399
+ if (!hasPointerEvents) {
400
+ this.dragEl[0].style.visibility = 'hidden';
401
+ }
402
+ this.pointEl = $(document.elementFromPoint(e.pageX - document.body.scrollLeft, e.pageY - (window.pageYOffset || document.documentElement.scrollTop)));
403
+ if (!hasPointerEvents) {
404
+ this.dragEl[0].style.visibility = 'visible';
405
+ }
406
+ if (this.pointEl.hasClass(opt.handleClass)) {
407
+ this.pointEl = this.pointEl.parent(opt.itemNodeName);
408
+ }
409
+ if (this.pointEl.hasClass(opt.emptyClass)) {
410
+ isEmpty = true;
411
+ }
412
+ else if (!this.pointEl.length || !this.pointEl.hasClass(opt.itemClass)) {
413
+ return;
414
+ }
415
+
416
+ // find parent list of item under cursor
417
+ var pointElRoot = this.pointEl.closest('.' + opt.rootClass),
418
+ isNewRoot = this.dragRootEl.data('nestable-id') !== pointElRoot.data('nestable-id');
419
+
420
+ /**
421
+ * move vertical
422
+ */
423
+ if (!mouse.dirAx || isNewRoot || isEmpty) {
424
+ // check if groups match if dragging over new root
425
+ if (isNewRoot && opt.group !== pointElRoot.data('nestable-group')) {
426
+ return;
427
+ }
428
+ // check depth limit
429
+ depth = this.dragDepth - 1 + this.pointEl.parents(opt.listNodeName).length;
430
+ if (depth > opt.maxDepth) {
431
+ return;
432
+ }
433
+ var before = e.pageY < (this.pointEl.offset().top + this.pointEl.height() / 2);
434
+ parent = this.placeEl.parent();
435
+ // if empty create new list to replace empty placeholder
436
+ if (isEmpty) {
437
+ list = $(document.createElement(opt.listNodeName)).addClass(opt.listClass);
438
+ list.append(this.placeEl);
439
+ this.pointEl.replaceWith(list);
440
+ }
441
+ else if (before) {
442
+ this.pointEl.before(this.placeEl);
443
+ }
444
+ else {
445
+ this.pointEl.after(this.placeEl);
446
+ }
447
+ if (!parent.children().length) {
448
+ this.unsetParent(parent.parent());
449
+ }
450
+ if (!this.dragRootEl.find(opt.itemNodeName).length) {
451
+ this.dragRootEl.append('<div class="' + opt.emptyClass + '"/>');
452
+ }
453
+ // parent root list has changed
454
+ if (isNewRoot) {
455
+ this.dragRootEl = pointElRoot;
456
+ this.hasNewRoot = this.el[0] !== this.dragRootEl[0];
457
+ }
458
+ }
459
+ }
460
+
461
+ };
462
+
463
+ $.fn.nestable = function(params)
464
+ {
465
+ var lists = this,
466
+ retval = this;
467
+
468
+ lists.each(function()
469
+ {
470
+ var plugin = $(this).data("nestable");
471
+
472
+ if (!plugin) {
473
+ $(this).data("nestable", new Plugin(this, params));
474
+ $(this).data("nestable-id", new Date().getTime());
475
+ } else {
476
+ if (typeof params === 'string' && typeof plugin[params] === 'function') {
477
+ retval = plugin[params]();
478
+ }
479
+ }
480
+ });
481
+
482
+ return retval || lists;
483
+ };
484
+
485
+ })(window.jQuery || window.Zepto, window, document);
@@ -0,0 +1,84 @@
1
+ .dd { position: relative; display: block; margin: 0; padding: 0; list-style: none; font-size: 13px; line-height: 20px; }
2
+
3
+ .dd-list { display: block; position: relative; margin: 0; padding: 0; list-style: none; }
4
+ .dd-list .dd-list { padding-left: 30px; }
5
+ .dd-collapsed .dd-list { display: none; }
6
+
7
+ .dd-item,
8
+ .dd-empty,
9
+ .dd-placeholder { display: block; position: relative; margin: 0; padding: 0; min-height: 40px; font-size: 13px; line-height: 40px; }
10
+
11
+ .dd-handle { display: block; height: 40px; margin: 5px 0; padding: 5px 10px; color: #333; text-decoration: none; font-weight: bold; border: 1px solid #ccc;
12
+ background: #fafafa;
13
+ background: -webkit-linear-gradient(top, #fafafa 0%, #eee 100%);
14
+ background: -moz-linear-gradient(top, #fafafa 0%, #eee 100%);
15
+ background: linear-gradient(top, #fafafa 0%, #eee 100%);
16
+ -webkit-border-radius: 3px;
17
+ border-radius: 3px;
18
+ box-sizing: border-box; -moz-box-sizing: border-box;
19
+ }
20
+ .dd-handle:hover { color: #2ea8e5; background: #fff; }
21
+
22
+ .dd-item > button { display: block; position: relative; cursor: pointer; float: left; width: 25px; height: 30px; margin: 5px 0; padding: 0; white-space: nowrap; overflow: hidden; border: 0; background: transparent; font-size: 12px; line-height: 1; text-align: center; font-weight: bold; }
23
+ /*.dd-item > button:before { content: ''; display: block; position: absolute; width: 100%; text-align: center; text-indent: 0; }*/
24
+ /*.dd-item > button[data-action="collapse"]:before { content: ''; }*/
25
+
26
+ .dd-placeholder,
27
+ .dd-empty { margin: 5px 0; padding: 0; min-height: 40px; background: #f2fbff; border: 1px dashed #b6bcbf; box-sizing: border-box; -moz-box-sizing: border-box; }
28
+ .dd-empty { border: 1px dashed #bbb; min-height: 100px; background-color: #e5e5e5;
29
+ background-image: -webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
30
+ -webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
31
+ background-image: -moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
32
+ -moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
33
+ background-image: linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
34
+ linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
35
+ background-size: 60px 60px;
36
+ background-position: 0 0, 30px 30px;
37
+ }
38
+
39
+ .dd-dragel { position: absolute; pointer-events: none; z-index: 9999; }
40
+ .dd-dragel > .dd-item .dd-handle { margin-top: 0; }
41
+ .dd-dragel .dd-handle {
42
+ -webkit-box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1);
43
+ box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1);
44
+ }
45
+
46
+ .dd3-content { display: block; height: 40px; margin: 5px 0; padding: 0px 10px 0px 38px; color: #333; text-decoration: none; font-weight: bold; border: 1px solid #ccc; line-height: 40px;
47
+ background: #fafafa;
48
+ background: -webkit-linear-gradient(top, #fafafa 0%, #eee 100%);
49
+ background: -moz-linear-gradient(top, #fafafa 0%, #eee 100%);
50
+ background: linear-gradient(top, #fafafa 0%, #eee 100%);
51
+ -webkit-border-radius: 3px;
52
+ border-radius: 3px;
53
+ box-sizing: border-box; -moz-box-sizing: border-box;
54
+ }
55
+ .dd3-content:hover { color: #2ea8e5; background: #fff; }
56
+ .dd3-content.unpublished { color: #2ea8e5; background: #e9e9e9; }
57
+
58
+ .dd-dragel > .dd3-item > .dd3-content { margin: 0; }
59
+
60
+ .dd3-item > button { margin-left: 30px; }
61
+
62
+ .dd3-handle { position: absolute; margin: 0; left: 0; top: 0; cursor: pointer; width: 30px; text-indent: 100%; white-space: nowrap; overflow: hidden;
63
+ border: 1px solid #aaa;
64
+ background: #ddd;
65
+ background: -webkit-linear-gradient(top, #ddd 0%, #bbb 100%);
66
+ background: -moz-linear-gradient(top, #ddd 0%, #bbb 100%);
67
+ background: linear-gradient(top, #ddd 0%, #bbb 100%);
68
+ border-top-right-radius: 0;
69
+ border-bottom-right-radius: 0;
70
+ }
71
+ .dd3-handle:before { content: '≡'; display: block; position: absolute; left: 0; top: 0px; width: 100%; text-align: center; text-indent: 0; color: #fff; font-size: 20px; font-weight: normal; }
72
+ .dd3-handle:hover { background: #ddd; }
73
+
74
+ .dd3-content .btn {
75
+ margin-bottom: 6px;
76
+ }
77
+
78
+ .button-group {
79
+ float: right;
80
+ }
81
+
82
+ button i {
83
+ opacity: 0.5;
84
+ }
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kuhsaft
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.1
5
- prerelease:
4
+ version: 1.8.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Immanuel Häussermann
@@ -13,124 +12,109 @@ authors:
13
12
  autorequire:
14
13
  bindir: bin
15
14
  cert_chain: []
16
- date: 2013-06-06 00:00:00.000000000 Z
15
+ date: 2013-07-15 00:00:00.000000000 Z
17
16
  dependencies:
18
17
  - !ruby/object:Gem::Dependency
19
18
  name: rspec
20
19
  requirement: !ruby/object:Gem::Requirement
21
- none: false
22
20
  requirements:
23
- - - ! '>='
21
+ - - '>='
24
22
  - !ruby/object:Gem::Version
25
23
  version: '0'
26
24
  type: :development
27
25
  prerelease: false
28
26
  version_requirements: !ruby/object:Gem::Requirement
29
- none: false
30
27
  requirements:
31
- - - ! '>='
28
+ - - '>='
32
29
  - !ruby/object:Gem::Version
33
30
  version: '0'
34
31
  - !ruby/object:Gem::Dependency
35
32
  name: rspec-rails
36
33
  requirement: !ruby/object:Gem::Requirement
37
- none: false
38
34
  requirements:
39
- - - ! '>='
35
+ - - ~>
40
36
  - !ruby/object:Gem::Version
41
- version: '2.6'
37
+ version: '2.13'
42
38
  type: :development
43
39
  prerelease: false
44
40
  version_requirements: !ruby/object:Gem::Requirement
45
- none: false
46
41
  requirements:
47
- - - ! '>='
42
+ - - ~>
48
43
  - !ruby/object:Gem::Version
49
- version: '2.6'
44
+ version: '2.13'
50
45
  - !ruby/object:Gem::Dependency
51
46
  name: factory_girl_rails
52
47
  requirement: !ruby/object:Gem::Requirement
53
- none: false
54
48
  requirements:
55
- - - ! '>='
49
+ - - '>='
56
50
  - !ruby/object:Gem::Version
57
51
  version: '0'
58
52
  type: :development
59
53
  prerelease: false
60
54
  version_requirements: !ruby/object:Gem::Requirement
61
- none: false
62
55
  requirements:
63
- - - ! '>='
56
+ - - '>='
64
57
  - !ruby/object:Gem::Version
65
58
  version: '0'
66
59
  - !ruby/object:Gem::Dependency
67
60
  name: capybara
68
61
  requirement: !ruby/object:Gem::Requirement
69
- none: false
70
62
  requirements:
71
- - - ! '>='
63
+ - - '>='
72
64
  - !ruby/object:Gem::Version
73
65
  version: '2.0'
74
66
  type: :development
75
67
  prerelease: false
76
68
  version_requirements: !ruby/object:Gem::Requirement
77
- none: false
78
69
  requirements:
79
- - - ! '>='
70
+ - - '>='
80
71
  - !ruby/object:Gem::Version
81
72
  version: '2.0'
82
73
  - !ruby/object:Gem::Dependency
83
74
  name: mysql2
84
75
  requirement: !ruby/object:Gem::Requirement
85
- none: false
86
76
  requirements:
87
- - - ! '>='
77
+ - - '>='
88
78
  - !ruby/object:Gem::Version
89
79
  version: '0'
90
80
  type: :development
91
81
  prerelease: false
92
82
  version_requirements: !ruby/object:Gem::Requirement
93
- none: false
94
83
  requirements:
95
- - - ! '>='
84
+ - - '>='
96
85
  - !ruby/object:Gem::Version
97
86
  version: '0'
98
87
  - !ruby/object:Gem::Dependency
99
88
  name: launchy
100
89
  requirement: !ruby/object:Gem::Requirement
101
- none: false
102
90
  requirements:
103
- - - ! '>='
91
+ - - '>='
104
92
  - !ruby/object:Gem::Version
105
93
  version: '0'
106
94
  type: :development
107
95
  prerelease: false
108
96
  version_requirements: !ruby/object:Gem::Requirement
109
- none: false
110
97
  requirements:
111
- - - ! '>='
98
+ - - '>='
112
99
  - !ruby/object:Gem::Version
113
100
  version: '0'
114
101
  - !ruby/object:Gem::Dependency
115
102
  name: rake
116
103
  requirement: !ruby/object:Gem::Requirement
117
- none: false
118
104
  requirements:
119
- - - ! '>='
105
+ - - '>='
120
106
  - !ruby/object:Gem::Version
121
107
  version: '0'
122
108
  type: :development
123
109
  prerelease: false
124
110
  version_requirements: !ruby/object:Gem::Requirement
125
- none: false
126
111
  requirements:
127
- - - ! '>='
112
+ - - '>='
128
113
  - !ruby/object:Gem::Version
129
114
  version: '0'
130
115
  - !ruby/object:Gem::Dependency
131
116
  name: rails
132
117
  requirement: !ruby/object:Gem::Requirement
133
- none: false
134
118
  requirements:
135
119
  - - ~>
136
120
  - !ruby/object:Gem::Version
@@ -138,7 +122,6 @@ dependencies:
138
122
  type: :runtime
139
123
  prerelease: false
140
124
  version_requirements: !ruby/object:Gem::Requirement
141
- none: false
142
125
  requirements:
143
126
  - - ~>
144
127
  - !ruby/object:Gem::Version
@@ -146,167 +129,146 @@ dependencies:
146
129
  - !ruby/object:Gem::Dependency
147
130
  name: haml
148
131
  requirement: !ruby/object:Gem::Requirement
149
- none: false
150
132
  requirements:
151
- - - ! '>='
133
+ - - '>='
152
134
  - !ruby/object:Gem::Version
153
135
  version: '3.1'
154
136
  type: :runtime
155
137
  prerelease: false
156
138
  version_requirements: !ruby/object:Gem::Requirement
157
- none: false
158
139
  requirements:
159
- - - ! '>='
140
+ - - '>='
160
141
  - !ruby/object:Gem::Version
161
142
  version: '3.1'
162
143
  - !ruby/object:Gem::Dependency
163
144
  name: compass
164
145
  requirement: !ruby/object:Gem::Requirement
165
- none: false
166
146
  requirements:
167
- - - ! '>='
147
+ - - '>='
168
148
  - !ruby/object:Gem::Version
169
149
  version: 0.11.1
170
150
  type: :runtime
171
151
  prerelease: false
172
152
  version_requirements: !ruby/object:Gem::Requirement
173
- none: false
174
153
  requirements:
175
- - - ! '>='
154
+ - - '>='
176
155
  - !ruby/object:Gem::Version
177
156
  version: 0.11.1
178
157
  - !ruby/object:Gem::Dependency
179
158
  name: compass-rails
180
159
  requirement: !ruby/object:Gem::Requirement
181
- none: false
182
160
  requirements:
183
- - - ! '>='
161
+ - - '>='
184
162
  - !ruby/object:Gem::Version
185
163
  version: '0'
186
164
  type: :runtime
187
165
  prerelease: false
188
166
  version_requirements: !ruby/object:Gem::Requirement
189
- none: false
190
167
  requirements:
191
- - - ! '>='
168
+ - - '>='
192
169
  - !ruby/object:Gem::Version
193
170
  version: '0'
194
171
  - !ruby/object:Gem::Dependency
195
172
  name: coffee-rails
196
173
  requirement: !ruby/object:Gem::Requirement
197
- none: false
198
174
  requirements:
199
- - - ! '>='
175
+ - - '>='
200
176
  - !ruby/object:Gem::Version
201
177
  version: '0'
202
178
  type: :runtime
203
179
  prerelease: false
204
180
  version_requirements: !ruby/object:Gem::Requirement
205
- none: false
206
181
  requirements:
207
- - - ! '>='
182
+ - - '>='
208
183
  - !ruby/object:Gem::Version
209
184
  version: '0'
210
185
  - !ruby/object:Gem::Dependency
211
186
  name: simple_form
212
187
  requirement: !ruby/object:Gem::Requirement
213
- none: false
214
188
  requirements:
215
- - - ! '>='
189
+ - - '>='
216
190
  - !ruby/object:Gem::Version
217
191
  version: '2.0'
218
192
  type: :runtime
219
193
  prerelease: false
220
194
  version_requirements: !ruby/object:Gem::Requirement
221
- none: false
222
195
  requirements:
223
- - - ! '>='
196
+ - - '>='
224
197
  - !ruby/object:Gem::Version
225
198
  version: '2.0'
226
199
  - !ruby/object:Gem::Dependency
227
200
  name: carrierwave
228
201
  requirement: !ruby/object:Gem::Requirement
229
- none: false
230
202
  requirements:
231
- - - ! '>='
203
+ - - '>='
232
204
  - !ruby/object:Gem::Version
233
205
  version: 0.7.1
234
206
  type: :runtime
235
207
  prerelease: false
236
208
  version_requirements: !ruby/object:Gem::Requirement
237
- none: false
238
209
  requirements:
239
- - - ! '>='
210
+ - - '>='
240
211
  - !ruby/object:Gem::Version
241
212
  version: 0.7.1
242
213
  - !ruby/object:Gem::Dependency
243
214
  name: mini_magick
244
215
  requirement: !ruby/object:Gem::Requirement
245
- none: false
246
216
  requirements:
247
- - - ! '>='
217
+ - - '>='
248
218
  - !ruby/object:Gem::Version
249
219
  version: '3.4'
250
220
  type: :runtime
251
221
  prerelease: false
252
222
  version_requirements: !ruby/object:Gem::Requirement
253
- none: false
254
223
  requirements:
255
- - - ! '>='
224
+ - - '>='
256
225
  - !ruby/object:Gem::Version
257
226
  version: '3.4'
258
227
  - !ruby/object:Gem::Dependency
259
228
  name: rdiscount
260
229
  requirement: !ruby/object:Gem::Requirement
261
- none: false
262
230
  requirements:
263
- - - ! '>='
231
+ - - '>='
264
232
  - !ruby/object:Gem::Version
265
233
  version: '1.6'
266
234
  type: :runtime
267
235
  prerelease: false
268
236
  version_requirements: !ruby/object:Gem::Requirement
269
- none: false
270
237
  requirements:
271
- - - ! '>='
238
+ - - '>='
272
239
  - !ruby/object:Gem::Version
273
240
  version: '1.6'
274
241
  - !ruby/object:Gem::Dependency
275
242
  name: ancestry
276
243
  requirement: !ruby/object:Gem::Requirement
277
- none: false
278
244
  requirements:
279
- - - ! '>='
245
+ - - '>='
280
246
  - !ruby/object:Gem::Version
281
247
  version: '0'
282
248
  type: :runtime
283
249
  prerelease: false
284
250
  version_requirements: !ruby/object:Gem::Requirement
285
- none: false
286
251
  requirements:
287
- - - ! '>='
252
+ - - '>='
288
253
  - !ruby/object:Gem::Version
289
254
  version: '0'
290
255
  - !ruby/object:Gem::Dependency
291
256
  name: bootstrap-sass
292
257
  requirement: !ruby/object:Gem::Requirement
293
- none: false
294
258
  requirements:
295
- - - ! '>='
259
+ - - '>='
296
260
  - !ruby/object:Gem::Version
297
261
  version: 2.2.2.0
298
262
  type: :runtime
299
263
  prerelease: false
300
264
  version_requirements: !ruby/object:Gem::Requirement
301
- none: false
302
265
  requirements:
303
- - - ! '>='
266
+ - - '>='
304
267
  - !ruby/object:Gem::Version
305
268
  version: 2.2.2.0
306
269
  - !ruby/object:Gem::Dependency
307
270
  name: ckeditor
308
271
  requirement: !ruby/object:Gem::Requirement
309
- none: false
310
272
  requirements:
311
273
  - - '='
312
274
  - !ruby/object:Gem::Version
@@ -314,7 +276,6 @@ dependencies:
314
276
  type: :runtime
315
277
  prerelease: false
316
278
  version_requirements: !ruby/object:Gem::Requirement
317
- none: false
318
279
  requirements:
319
280
  - - '='
320
281
  - !ruby/object:Gem::Version
@@ -322,33 +283,29 @@ dependencies:
322
283
  - !ruby/object:Gem::Dependency
323
284
  name: pg_search
324
285
  requirement: !ruby/object:Gem::Requirement
325
- none: false
326
286
  requirements:
327
- - - ! '>='
287
+ - - '>='
328
288
  - !ruby/object:Gem::Version
329
289
  version: '0'
330
290
  type: :runtime
331
291
  prerelease: false
332
292
  version_requirements: !ruby/object:Gem::Requirement
333
- none: false
334
293
  requirements:
335
- - - ! '>='
294
+ - - '>='
336
295
  - !ruby/object:Gem::Version
337
296
  version: '0'
338
297
  - !ruby/object:Gem::Dependency
339
298
  name: htmlentities
340
299
  requirement: !ruby/object:Gem::Requirement
341
- none: false
342
300
  requirements:
343
- - - ! '>='
301
+ - - '>='
344
302
  - !ruby/object:Gem::Version
345
303
  version: '0'
346
304
  type: :runtime
347
305
  prerelease: false
348
306
  version_requirements: !ruby/object:Gem::Requirement
349
- none: false
350
307
  requirements:
351
- - - ! '>='
308
+ - - '>='
352
309
  - !ruby/object:Gem::Version
353
310
  version: '0'
354
311
  description: Kuhsaft is a Rails engine that offers a simple CMS.
@@ -428,6 +385,7 @@ files:
428
385
  - app/views/kuhsaft/cms/pages/index.html.haml
429
386
  - app/views/kuhsaft/cms/pages/new.html.haml
430
387
  - app/views/kuhsaft/cms/pages/show.html.haml
388
+ - app/views/kuhsaft/cms/pages/sort.js.erb
431
389
  - app/views/kuhsaft/column_bricks/_column_brick.html.haml
432
390
  - app/views/kuhsaft/column_bricks/column_brick/_edit.html.haml
433
391
  - app/views/kuhsaft/image_bricks/_image_brick.html.haml
@@ -497,6 +455,7 @@ files:
497
455
  - lib/kuhsaft/brick_list.rb
498
456
  - lib/kuhsaft/engine.rb
499
457
  - lib/kuhsaft/orderable.rb
458
+ - lib/kuhsaft/page_tree.rb
500
459
  - lib/kuhsaft/partial_extractor.rb
501
460
  - lib/kuhsaft/searchable.rb
502
461
  - lib/kuhsaft/translatable.rb
@@ -507,6 +466,8 @@ files:
507
466
  - lib/templates/kuhsaft/assets/customizations.css.sass
508
467
  - lib/templates/kuhsaft/assets/customizations.js.coffee
509
468
  - lib/templates/kuhsaft/translations/add_translation.html.erb
469
+ - vendor/assets/javascripts/jquery.nestable.js
470
+ - vendor/assets/stylesheets/nestable.css
510
471
  - Rakefile
511
472
  - README.md
512
473
  - spec/controllers/kuhsaft/pages_controller_spec.rb
@@ -551,6 +512,7 @@ files:
551
512
  - spec/kuhsaft_spec.rb
552
513
  - spec/lib/brick_list_spec.rb
553
514
  - spec/lib/engine_spec.rb
515
+ - spec/lib/page_tree_spec.rb
554
516
  - spec/lib/searchable_spec.rb
555
517
  - spec/lib/translatable_spec.rb
556
518
  - spec/models/accordion_brick_spec.rb
@@ -576,33 +538,26 @@ files:
576
538
  - spec/support/kuhsaft_spec_helper.rb
577
539
  homepage: http://github.com/screenconcept/kuhsaft
578
540
  licenses: []
541
+ metadata: {}
579
542
  post_install_message:
580
543
  rdoc_options: []
581
544
  require_paths:
582
545
  - lib
583
546
  required_ruby_version: !ruby/object:Gem::Requirement
584
- none: false
585
547
  requirements:
586
- - - ! '>='
548
+ - - '>='
587
549
  - !ruby/object:Gem::Version
588
550
  version: '0'
589
- segments:
590
- - 0
591
- hash: -4607812915694865046
592
551
  required_rubygems_version: !ruby/object:Gem::Requirement
593
- none: false
594
552
  requirements:
595
- - - ! '>='
553
+ - - '>='
596
554
  - !ruby/object:Gem::Version
597
555
  version: '0'
598
- segments:
599
- - 0
600
- hash: -4607812915694865046
601
556
  requirements: []
602
557
  rubyforge_project: kuhsaft
603
- rubygems_version: 1.8.24
558
+ rubygems_version: 2.0.3
604
559
  signing_key:
605
- specification_version: 3
560
+ specification_version: 4
606
561
  summary: A tool that helps you to manage your content within your app.
607
562
  test_files:
608
563
  - spec/controllers/kuhsaft/pages_controller_spec.rb
@@ -647,6 +602,7 @@ test_files:
647
602
  - spec/kuhsaft_spec.rb
648
603
  - spec/lib/brick_list_spec.rb
649
604
  - spec/lib/engine_spec.rb
605
+ - spec/lib/page_tree_spec.rb
650
606
  - spec/lib/searchable_spec.rb
651
607
  - spec/lib/translatable_spec.rb
652
608
  - spec/models/accordion_brick_spec.rb