ideyabox 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
data/app/assets/.DS_Store CHANGED
Binary file
@@ -7,8 +7,8 @@
7
7
  //= require swfobject.js
8
8
  //= require jquery.uploadify.min
9
9
  //= require jquery-ui.min.js
10
- //= require jquery.ui.nestedSortable
11
10
  //= require chosen.jquery.js
11
+ //= require jquery.mjs.nestedSortable.js
12
12
 
13
13
  //
14
14
  $(document).ready(function(){
@@ -80,5 +80,5 @@ $(document).ready(function(){
80
80
  $(".cropable").removeAttr('id');
81
81
  $('.crop_params input').val('');
82
82
  });
83
-
83
+
84
84
  });
@@ -1,29 +1,39 @@
1
1
  /*
2
2
  * jQuery UI Nested Sortable
3
- * v 1.3.4 / 28 apr 2011f
4
- * http://mjsarfatti.com/sandbox/nestedSortable
3
+ * v 1.3.5 / 21 jun 2012
4
+ * http://mjsarfatti.com/code/nestedSortable
5
5
  *
6
- * Depends:
6
+ * Depends on:
7
7
  * jquery.ui.sortable.js 1.8+
8
8
  *
9
- * License CC BY-SA 3.0
10
- * Copyright 2010-2011, Manuele J Sarfatti
9
+ * Copyright (c) 2010-2012 Manuele J Sarfatti
10
+ * Licensed under the MIT License
11
+ * http://www.opensource.org/licenses/mit-license.php
11
12
  */
12
13
 
13
14
  (function($) {
14
15
 
15
- $.widget("ui.nestedSortable", $.extend({}, $.ui.sortable.prototype, {
16
+ $.widget("mjs.nestedSortable", $.extend({}, $.ui.sortable.prototype, {
16
17
 
17
18
  options: {
18
19
  tabSize: 20,
19
- disableNesting: 'ui-nestedSortable-no-nesting',
20
- errorClass: 'ui-nestedSortable-error',
20
+ disableNesting: 'mjs-nestedSortable-no-nesting',
21
+ errorClass: 'mjs-nestedSortable-error',
22
+ doNotClear: false,
21
23
  listType: 'ol',
22
- maxLevels: 0
24
+ maxLevels: 0,
25
+ protectRoot: false,
26
+ rootID: null,
27
+ rtl: false,
28
+ isAllowed: function(item, parent) { return true; }
23
29
  },
24
30
 
25
31
  _create: function() {
26
32
  this.element.data('sortable', this.element.data('nestedSortable'));
33
+
34
+ if (!this.element.is(this.options.listType))
35
+ throw new Error('nestedSortable: Please check the listType option is set to your actual list type');
36
+
27
37
  return $.ui.sortable.prototype._create.apply(this, arguments);
28
38
  },
29
39
 
@@ -44,9 +54,11 @@
44
54
  this.lastPositionAbs = this.positionAbs;
45
55
  }
46
56
 
57
+ var o = this.options;
58
+
47
59
  //Do scrolling
48
60
  if(this.options.scroll) {
49
- var o = this.options, scrolled = false;
61
+ var scrolled = false;
50
62
  if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {
51
63
 
52
64
  if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
@@ -80,6 +92,9 @@
80
92
  //Regenerate the absolute position used for position checks
81
93
  this.positionAbs = this._convertPositionTo("absolute");
82
94
 
95
+ // Find the top offset before rearrangement,
96
+ var previousTopOffset = this.placeholder.offset().top;
97
+
83
98
  //Set the helper position
84
99
  if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
85
100
  if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
@@ -117,16 +132,17 @@
117
132
  }
118
133
  }
119
134
 
120
- var parentItem = (this.placeholder[0].parentNode.parentNode
121
- && $(this.placeholder[0].parentNode.parentNode).closest('.ui-sortable').length)
122
- ? $(this.placeholder[0].parentNode.parentNode)
123
- : null,
135
+ var parentItem = (this.placeholder[0].parentNode.parentNode &&
136
+ $(this.placeholder[0].parentNode.parentNode).closest('.ui-sortable').length)
137
+ ? $(this.placeholder[0].parentNode.parentNode)
138
+ : null,
124
139
  level = this._getLevel(this.placeholder),
125
- childLevels = this._getChildLevels(this.helper),
126
- previousItem = this.placeholder[0].previousSibling ? $(this.placeholder[0].previousSibling) : null;
140
+ childLevels = this._getChildLevels(this.helper);
127
141
 
142
+ // To find the previous sibling in the list, keep backtracking until we hit a valid list item.
143
+ var previousItem = this.placeholder[0].previousSibling ? $(this.placeholder[0].previousSibling) : null;
128
144
  if (previousItem != null) {
129
- while (previousItem[0].nodeName.toLowerCase() != 'li' || previousItem[0] == this.currentItem[0]) {
145
+ while (previousItem[0].nodeName.toLowerCase() != 'li' || previousItem[0] == this.currentItem[0] || previousItem[0] == this.helper[0]) {
130
146
  if (previousItem[0].previousSibling) {
131
147
  previousItem = $(previousItem[0].previousSibling);
132
148
  } else {
@@ -136,27 +152,51 @@
136
152
  }
137
153
  }
138
154
 
139
- newList = document.createElement(o.listType);
155
+ // To find the next sibling in the list, keep stepping forward until we hit a valid list item.
156
+ var nextItem = this.placeholder[0].nextSibling ? $(this.placeholder[0].nextSibling) : null;
157
+ if (nextItem != null) {
158
+ while (nextItem[0].nodeName.toLowerCase() != 'li' || nextItem[0] == this.currentItem[0] || nextItem[0] == this.helper[0]) {
159
+ if (nextItem[0].nextSibling) {
160
+ nextItem = $(nextItem[0].nextSibling);
161
+ } else {
162
+ nextItem = null;
163
+ break;
164
+ }
165
+ }
166
+ }
167
+
168
+ var newList = document.createElement(o.listType);
140
169
 
141
170
  this.beyondMaxLevels = 0;
142
-
143
- // If the item is moved to the left, send it to its parent level
144
- if (parentItem != null && this.positionAbs.left < parentItem.offset().left) {
171
+
172
+ // If the item is moved to the left, send it to its parent's level unless there are siblings below it.
173
+ if (parentItem != null && nextItem == null &&
174
+ (o.rtl && (this.positionAbs.left + this.helper.outerWidth() > parentItem.offset().left + parentItem.outerWidth()) ||
175
+ !o.rtl && (this.positionAbs.left < parentItem.offset().left))) {
145
176
  parentItem.after(this.placeholder[0]);
146
177
  this._clearEmpty(parentItem[0]);
147
178
  this._trigger("change", event, this._uiHash());
148
179
  }
149
- // If the item is below another one and is moved to the right, make it a children of it
150
- else if (previousItem != null && this.positionAbs.left > previousItem.offset().left + o.tabSize) {
151
- this._isAllowed(previousItem, level+childLevels+1);
180
+ // If the item is below a sibling and is moved to the right, make it a child of that sibling.
181
+ else if (previousItem != null &&
182
+ (o.rtl && (this.positionAbs.left + this.helper.outerWidth() < previousItem.offset().left + previousItem.outerWidth() - o.tabSize) ||
183
+ !o.rtl && (this.positionAbs.left > previousItem.offset().left + o.tabSize))) {
184
+ this._isAllowed(previousItem, level, level+childLevels+1);
152
185
  if (!previousItem.children(o.listType).length) {
153
186
  previousItem[0].appendChild(newList);
154
187
  }
155
- previousItem.children(o.listType)[0].appendChild(this.placeholder[0]);
188
+ // If this item is being moved from the top, add it to the top of the list.
189
+ if (previousTopOffset && (previousTopOffset <= previousItem.offset().top)) {
190
+ previousItem.children(o.listType).prepend(this.placeholder);
191
+ }
192
+ // Otherwise, add it to the bottom of the list.
193
+ else {
194
+ previousItem.children(o.listType)[0].appendChild(this.placeholder[0]);
195
+ }
156
196
  this._trigger("change", event, this._uiHash());
157
197
  }
158
198
  else {
159
- this._isAllowed(parentItem, level+childLevels);
199
+ this._isAllowed(parentItem, level, level+childLevels);
160
200
  }
161
201
 
162
202
  //Post events to containers
@@ -180,24 +220,14 @@
180
220
 
181
221
  this.placeholder.removeClass(this.options.errorClass);
182
222
 
183
- if (this.options.revertOnError) {
184
- if (this.domPosition.prev) {
185
- $(this.domPosition.prev).after(this.placeholder);
186
- } else {
187
- $(this.domPosition.parent).prepend(this.placeholder);
188
- }
189
- this._trigger("revert", event, this._uiHash());
223
+ if (this.domPosition.prev) {
224
+ $(this.domPosition.prev).after(this.placeholder);
190
225
  } else {
191
- var parent = this.placeholder.parent().closest(this.options.items);
192
-
193
- for (var i = this.beyondMaxLevels - 1; i > 0; i--) {
194
- parent = parent.parent().closest(this.options.items);
195
- }
196
-
197
- parent.after(this.placeholder);
198
- this._trigger("change", event, this._uiHash());
226
+ $(this.domPosition.parent).prepend(this.placeholder);
199
227
  }
200
228
 
229
+ this._trigger("revert", event, this._uiHash());
230
+
201
231
  }
202
232
 
203
233
  // Clean last empty ul/ol
@@ -210,23 +240,24 @@
210
240
 
211
241
  },
212
242
 
213
- serialize: function(o) {
243
+ serialize: function(options) {
214
244
 
215
- var items = this._getItemsAsjQuery(o && o.connected),
216
- str = []; o = o || {};
245
+ var o = $.extend({}, this.options, options),
246
+ items = this._getItemsAsjQuery(o && o.connected),
247
+ str = [];
217
248
 
218
249
  $(items).each(function() {
219
250
  var res = ($(o.item || this).attr(o.attribute || 'id') || '')
220
251
  .match(o.expression || (/(.+)[-=_](.+)/)),
221
252
  pid = ($(o.item || this).parent(o.listType)
222
- .parent('li')
253
+ .parent(o.items)
223
254
  .attr(o.attribute || 'id') || '')
224
255
  .match(o.expression || (/(.+)[-=_](.+)/));
225
256
 
226
257
  if (res) {
227
- str.push((o.key || res[1] + '[' + (o.key && o.expression ? res[1] : res[2]) + ']')
258
+ str.push(((o.key || res[1]) + '[' + (o.key && o.expression ? res[1] : res[2]) + ']')
228
259
  + '='
229
- + (pid ? (o.key && o.expression ? pid[1] : pid[2]) : 'root'));
260
+ + (pid ? (o.key && o.expression ? pid[1] : pid[2]) : o.rootID));
230
261
  }
231
262
  });
232
263
 
@@ -238,51 +269,51 @@
238
269
 
239
270
  },
240
271
 
241
- toHierarchy: function(o) {
272
+ toHierarchy: function(options) {
242
273
 
243
- o = o || {};
244
- var sDepth = o.startDepthCount || 0,
274
+ var o = $.extend({}, this.options, options),
275
+ sDepth = o.startDepthCount || 0,
245
276
  ret = [];
246
277
 
247
- $(this.element).children('li').each(function () {
248
- var level = _recursiveItems($(this));
278
+ $(this.element).children(o.items).each(function () {
279
+ var level = _recursiveItems(this);
249
280
  ret.push(level);
250
281
  });
251
282
 
252
283
  return ret;
253
284
 
254
- function _recursiveItems(li) {
255
- var id = ($(li).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
285
+ function _recursiveItems(item) {
286
+ var id = ($(item).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
256
287
  if (id) {
257
- var item = {"id" : id[2]};
258
- if ($(li).children(o.listType).children('li').length > 0) {
259
- item.children = [];
260
- $(li).children(o.listType).children('li').each(function() {
261
- var level = _recursiveItems($(this));
262
- item.children.push(level);
288
+ var currentItem = {"id" : id[2]};
289
+ if ($(item).children(o.listType).children(o.items).length > 0) {
290
+ currentItem.children = [];
291
+ $(item).children(o.listType).children(o.items).each(function() {
292
+ var level = _recursiveItems(this);
293
+ currentItem.children.push(level);
263
294
  });
264
295
  }
265
- return item;
296
+ return currentItem;
266
297
  }
267
298
  }
268
299
  },
269
300
 
270
- toArray: function(o) {
301
+ toArray: function(options) {
271
302
 
272
- o = o || {};
273
- var sDepth = o.startDepthCount || 0,
303
+ var o = $.extend({}, this.options, options),
304
+ sDepth = o.startDepthCount || 0,
274
305
  ret = [],
275
306
  left = 2;
276
307
 
277
308
  ret.push({
278
- "item_id": 'root',
309
+ "item_id": o.rootID,
279
310
  "parent_id": 'none',
280
311
  "depth": sDepth,
281
312
  "left": '1',
282
- "right": ($('li', this.element).length + 1) * 2
313
+ "right": ($(o.items, this.element).length + 1) * 2
283
314
  });
284
315
 
285
- $(this.element).children('li').each(function () {
316
+ $(this.element).children(o.items).each(function () {
286
317
  left = _recursiveArray(this, sDepth + 1, left);
287
318
  });
288
319
 
@@ -296,9 +327,9 @@
296
327
  id,
297
328
  pid;
298
329
 
299
- if ($(item).children(o.listType).children('li').length > 0) {
330
+ if ($(item).children(o.listType).children(o.items).length > 0) {
300
331
  depth ++;
301
- $(item).children(o.listType).children('li').each(function () {
332
+ $(item).children(o.listType).children(o.items).each(function () {
302
333
  right = _recursiveArray($(this), depth, right);
303
334
  });
304
335
  depth --;
@@ -307,12 +338,12 @@
307
338
  id = ($(item).attr(o.attribute || 'id')).match(o.expression || (/(.+)[-=_](.+)/));
308
339
 
309
340
  if (depth === sDepth + 1) {
310
- pid = 'root';
341
+ pid = o.rootID;
311
342
  } else {
312
343
  var parentItem = ($(item).parent(o.listType)
313
- .parent('li')
314
- .attr(o.attribute || 'id'))
315
- .match(o.expression || (/(.+)[-=_](.+)/));
344
+ .parent(o.items)
345
+ .attr(o.attribute || 'id'))
346
+ .match(o.expression || (/(.+)[-=_](.+)/));
316
347
  pid = parentItem[2];
317
348
  }
318
349
 
@@ -329,7 +360,7 @@
329
360
  _clearEmpty: function(item) {
330
361
 
331
362
  var emptyList = $(item).children(this.options.listType);
332
- if (emptyList.length && !emptyList.children().length) {
363
+ if (emptyList.length && !emptyList.children().length && !this.options.doNotClear) {
333
364
  emptyList.remove();
334
365
  }
335
366
 
@@ -341,7 +372,8 @@
341
372
 
342
373
  if (this.options.listType) {
343
374
  var list = item.closest(this.options.listType);
344
- while (!list.is('.ui-sortable')) {
375
+ while (list && list.length > 0 &&
376
+ !list.is('.ui-sortable')) {
345
377
  level++;
346
378
  list = list.parent().closest(this.options.listType);
347
379
  }
@@ -363,28 +395,35 @@
363
395
  return depth ? result + 1 : result;
364
396
  },
365
397
 
366
- _isAllowed: function(parentItem, levels) {
367
- var o = this.options;
368
- // Are we trying to nest under a no-nest or are we nesting too deep?
369
- if (parentItem == null || !(parentItem.hasClass(o.disableNesting))) {
370
- if (o.maxLevels < levels && o.maxLevels != 0) {
398
+ _isAllowed: function(parentItem, level, levels) {
399
+ var o = this.options,
400
+ isRoot = $(this.domPosition.parent).hasClass('ui-sortable') ? true : false,
401
+ maxLevels = this.placeholder.closest('.ui-sortable').nestedSortable('option', 'maxLevels'); // this takes into account the maxLevels set to the recipient list
402
+
403
+ // Is the root protected?
404
+ // Are we trying to nest under a no-nest?
405
+ // Are we nesting too deep?
406
+ if (!o.isAllowed(this.currentItem, parentItem) ||
407
+ parentItem && parentItem.hasClass(o.disableNesting) ||
408
+ o.protectRoot && (parentItem == null && !isRoot || isRoot && level > 1)) {
371
409
  this.placeholder.addClass(o.errorClass);
372
- this.beyondMaxLevels = levels - o.maxLevels;
410
+ if (maxLevels < levels && maxLevels != 0) {
411
+ this.beyondMaxLevels = levels - maxLevels;
412
+ } else {
413
+ this.beyondMaxLevels = 1;
414
+ }
415
+ } else {
416
+ if (maxLevels < levels && maxLevels != 0) {
417
+ this.placeholder.addClass(o.errorClass);
418
+ this.beyondMaxLevels = levels - maxLevels;
373
419
  } else {
374
420
  this.placeholder.removeClass(o.errorClass);
375
421
  this.beyondMaxLevels = 0;
376
422
  }
377
- } else {
378
- this.placeholder.addClass(o.errorClass);
379
- if (o.maxLevels < levels && o.maxLevels != 0) {
380
- this.beyondMaxLevels = levels - o.maxLevels;
381
- } else {
382
- this.beyondMaxLevels = 1;
383
- }
384
423
  }
385
424
  }
386
425
 
387
426
  }));
388
427
 
389
- $.ui.nestedSortable.prototype.options = $.extend({}, $.ui.sortable.prototype.options, $.ui.nestedSortable.prototype.options);
390
- })(jQuery);
428
+ $.mjs.nestedSortable.prototype.options = $.extend({}, $.ui.sortable.prototype.options, $.mjs.nestedSortable.prototype.options);
429
+ })(jQuery);
@@ -172,6 +172,32 @@ img {
172
172
  .clear {
173
173
  clear:both;
174
174
  }
175
+
176
+
177
+ html.login {
178
+ #content input{font-size:1em;}
179
+ #content input[type=submit]{padding: 0.3em 0.5em;}
180
+ &, body { width:100%; height:100%;}
181
+ #main {min-height:0; width:370px; margin:0 auto;
182
+ margin-bottom:100px;
183
+ background:white;
184
+ padding:0 2em;
185
+ -webkit-box-shadow: 0 0 5px #CCC;
186
+ -moz-box-shadow: 0 0 5px #CCC;
187
+ box-shadow: 0 0 5px #CCC;
188
+ -webkit-border-radius: 3px;
189
+ -moz-border-radius: 3px;
190
+ border-radius: 3px;
191
+ border: 1px solid #CCC;
192
+ }
193
+
194
+ table.login {border-collapse:collapse; width:100%; height:100%;}
195
+ td.login {vertical-align:middle;}
196
+ .fields {
197
+ margin:0 0 5px 0;
198
+ input {width:100%}
199
+ }
200
+ }
175
201
  #launchbar {
176
202
  background: $deepgreen;overflow: hidden;position: relative;text-align: left;z-index: 9999;padding: 0 3%;
177
203
  -webkit-box-shadow: 0 0 5px $shadows;
@@ -278,17 +304,25 @@ td #imp_redactor_box_slider_item_body {width:100% !important;}
278
304
  .date_params {display:none;&.show {display:table-row;}}
279
305
 
280
306
  body .redactor_toolbar li a.redactor_btn_hiconix_cut{background: url(<%= asset_path 'admin/hiconix_cut.png' %>) no-repeat;}
281
- ul.photos {
282
- list-style: none;
283
- li {
284
- display:inline-block;
285
- position:relative;
286
- a.del {text-indent:-9999px;position:absolute;right:0;bottom:0;}
287
- }
288
- }
307
+
289
308
  #index_wr {
290
309
  margin-top:10px;
291
310
  }
311
+
312
+ @mixin gradient($top, $bottom) {
313
+ background: $top;
314
+ background: -moz-linear-gradient(top, $top 0%, $bottom 100%);
315
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,$top), color-stop(100%,$bottom));
316
+ background: -webkit-linear-gradient(top, $top 0%,$bottom 100%);
317
+ background: -o-linear-gradient(top, $top 0%,$bottom 100%);
318
+ background: -ms-linear-gradient(top, $top 0%,$bottom 100%);
319
+ background: linear-gradient(to bottom, $top 0%,$bottom 100%);
320
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#5eb6ff', endColorstr='#006ed6',GradientType=0 );
321
+ }
322
+
323
+
324
+ // buttons
325
+
292
326
  @mixin black_button {
293
327
  font:1em Helvetica, Arial, sans-serif;
294
328
  margin-bottom:10px;
@@ -364,6 +398,10 @@ input[type=submit] {
364
398
  }
365
399
  }
366
400
 
401
+
402
+
403
+ // flash messages
404
+
367
405
  .notice, .alert {
368
406
  padding:7px 15px;
369
407
  margin:10px 30px;
@@ -395,40 +433,20 @@ input[type=submit] {
395
433
 
396
434
  #error_explanation {background:#fbe3e4;padding:1em;border-radius:4px; border:1px dashed red;ul{list-style-type:none;}}
397
435
 
398
- html.login {
399
- #content input{font-size:1em;}
400
- #content input[type=submit]{padding: 0.3em 0.5em;}
401
- &, body { width:100%; height:100%;}
402
- #main {min-height:0; width:370px; margin:0 auto;
403
- margin-bottom:100px;
404
- background:white;
405
- padding:0 2em;
406
- -webkit-box-shadow: 0 0 5px #CCC;
407
- -moz-box-shadow: 0 0 5px #CCC;
408
- box-shadow: 0 0 5px #CCC;
409
- -webkit-border-radius: 3px;
410
- -moz-border-radius: 3px;
411
- border-radius: 3px;
412
- border: 1px solid #CCC;
413
- }
414
436
 
415
- table.login {border-collapse:collapse; width:100%; height:100%;}
416
- td.login {vertical-align:middle;}
417
- .fields {
418
- margin:0 0 5px 0;
419
- input {width:100%}
437
+
438
+
439
+ // images uploading
440
+
441
+ ul.photos {
442
+ list-style: none;
443
+ li {
444
+ display:inline-block;
445
+ position:relative;
446
+ a.del {text-indent:-9999px;position:absolute;right:0;bottom:0;}
420
447
  }
421
448
  }
422
- @mixin gradient($top, $bottom) {
423
- background: $top;
424
- background: -moz-linear-gradient(top, $top 0%, $bottom 100%);
425
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,$top), color-stop(100%,$bottom));
426
- background: -webkit-linear-gradient(top, $top 0%,$bottom 100%);
427
- background: -o-linear-gradient(top, $top 0%,$bottom 100%);
428
- background: -ms-linear-gradient(top, $top 0%,$bottom 100%);
429
- background: linear-gradient(to bottom, $top 0%,$bottom 100%);
430
- filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#5eb6ff', endColorstr='#006ed6',GradientType=0 );
431
- }
449
+
432
450
  .image-list li{
433
451
  display:inline-block;
434
452
  width:47%;
@@ -481,8 +499,38 @@ html.login {
481
499
  @include gradient(#53B75F, #1B7726);
482
500
  height: 10px;
483
501
  }
502
+
503
+ // crop
484
504
  .preview_crop {display:none;overflow:hidden;img{max-width:none;}}
485
505
  .crop_panel {
486
506
  margin:1em 0;
487
507
  #unhook {display:none;}
488
- }
508
+ }
509
+
510
+ // trees
511
+ ol.sortable {
512
+ margin: 0;
513
+ padding: 0;
514
+ width: 100%;
515
+ li {
516
+ width:100%;
517
+ margin: 12px 0;
518
+ vertical-align: middle;
519
+ padding: 0;
520
+ }
521
+ ol {margin: 0 0 0 30px;padding: 0;}
522
+ div {
523
+ cursor: move;
524
+ background-color: #F8F8F8;
525
+ width:100%;
526
+ vertical-align: middle;
527
+ padding: 10px 0;
528
+ a {margin-left: 10px;}
529
+ .del {float: right;min-width:30px;}
530
+ &:hover {background-color:#C4FFCB;outline:1px dashed green;}
531
+ }
532
+ }
533
+ .ui-nestedSortable-error {background:#fbe3e4; outline:1px dashed red;}
534
+ .placeholder {background-color: #C4FFCB; outline:1px dashed green;}
535
+ .ui-sortable-placeholder {background-color: #C4FFCB !important;height:2.6em;visibility:visible !important;}
536
+
@@ -5,6 +5,8 @@ module AdminHelper
5
5
  <script type="text/javascript">
6
6
  $(document).ready(function() {
7
7
  $('#sort-list tbody').sortable( {
8
+ placeholder: 'ui-sortable-placeholder',
9
+ forcePlaceholderSize: true,
8
10
  dropOnEmpty: false,
9
11
  cursor: 'crosshair',
10
12
  opacity: 0.75,
@@ -25,7 +27,45 @@ module AdminHelper
25
27
  }.gsub(/[\n ]+/, ' ').strip.html_safe
26
28
  end
27
29
 
30
+ def cropable(image_name, x,y,w,h)
31
+ %Q{
32
+ <script type="text/javascript">
33
+ function jcropInit() {
34
+
35
+ $('.preview_crop').width(#{w}).height(#{h});
36
+
37
+ $("#cropbox").Jcrop({
38
+ aspectRatio: #{w}/#{h},
39
+ onSelect: showCoords,
40
+ onChange: showCoords,
41
+ minSize: [30,30],
42
+ bgColor: '#fff',
43
+ bgOpacity: .4,
44
+ });
28
45
 
46
+ function showCoords(c) {
47
+ $("##{image_name}_crop_x").val(c.x);
48
+ $("##{image_name}_crop_y").val(c.y);
49
+ $("##{image_name}_crop_w").val(c.w);
50
+ $("##{image_name}_crop_h").val(c.h);
51
+ updatePreview(c);
52
+ };
53
+
54
+ function updatePreview(c) {
55
+ $("#preview").css(
56
+ {'width': Math.round(#{w}/c.w * $("#cropbox").width()) + 'px',
57
+ 'height': Math.round(#{h}/c.wh * $("#cropbox").height()) + 'px',
58
+ "margin-left": "-" + Math.round(#{w}/c.w * c.x) + 'px',
59
+ "margin-top": "-" + Math.round(#{h}/c.h * c.y) + 'px'}
60
+ );
61
+ };
62
+
63
+ $("#cropbox").parents("body").css("min-width","600px");
64
+
65
+ };
66
+ </script>
67
+ }.gsub(/[\n ]+/, ' ').strip.html_safe
68
+ end
29
69
 
30
70
  def sortable_columns(column, title = nil)
31
71
  title ||= column.titleize
@@ -90,6 +130,74 @@ module AdminHelper
90
130
  return raw html
91
131
  end
92
132
 
133
+ def show_tree(items)
134
+ html = ""
135
+ html << "<ol#{" class='sortable'"}>"
136
+
137
+ items.where(:ancestry => nil).order(:position).each do |i|
138
+ html << children(i)
139
+ end
140
+
141
+ html << "</ol>"
142
+
143
+ return raw(html)
144
+ end
145
+
93
146
 
147
+ def children(i)
148
+ html = ""
149
+ html << "
150
+ <li id=\"list_#{i.id}\">
151
+ <div>#{link_to i.title, [:edit, :admin, i]}
152
+ "
153
+ html << delete_button(i)
154
+ html << "</div>"
155
+
156
+
157
+ unless i.children.empty?
158
+ html << "<ol>"
159
+ i.children.order('position').each do |child|
160
+ html << children(child)
161
+ end
162
+ html << "</ol>"
163
+ end
164
+ html << "</li>"
165
+ return html
166
+ end
167
+
168
+ def delete_button(object)
169
+ link_to [:admin, object], :class => :del, :confirm => 'Точно удалить?', :method => :delete do
170
+ raw("<span> Удалить </span>")
171
+ raw("<i class='icon-trash icon-large'> </i>")
172
+ end
173
+ end
174
+
175
+ def sort_tree(url, maxlevels)
176
+ %Q{
177
+ <script type="text/javascript">
178
+ $(document).ready(function(){
179
+
180
+ $('ol.sortable').nestedSortable({
181
+ disableNesting: 'no-nest',
182
+ forcePlaceholderSize: true,
183
+ handle: 'div',
184
+ helper: 'clone',
185
+ items: 'li',
186
+ maxLevels: #{maxlevels},
187
+ opacity: .6,
188
+ placeholder: 'placeholder',
189
+ revert: 250,
190
+ tabSize: 25,
191
+ tolerance: 'pointer',
192
+ toleranceElement: '> div',
193
+ update: function(){
194
+ var serialized = $('ol.sortable').nestedSortable('serialize');
195
+ $.ajax({url: '#{url}', data: serialized});
196
+ }
197
+ });
198
+ });
199
+ </script>
200
+ }.gsub(/[\n ]+/, ' ').strip.html_safe
201
+ end
94
202
 
95
203
  end
Binary file
@@ -24,6 +24,7 @@ module Ideyabox
24
24
  gem 'russian'
25
25
  gem 'redactor-rails'
26
26
  gem 'haml'
27
+ gem 'ancestry'
27
28
  gem 'carrierwave'
28
29
  gem 'mini_magick'
29
30
  gem 'squeel'
@@ -0,0 +1,65 @@
1
+ #coding: utf-8
2
+ class Admin::<%= @model_name.demodulize.pluralize -%>Controller < Admin::ApplicationController
3
+ helper_method :sort_column, :sort_direction
4
+ <%- if column_names.include?("visible") -%>
5
+ def toggleshow
6
+ @<%= plural_resource_name %> = <%= @model_name.demodulize -%>.find(params[:id])
7
+ @<%= plural_resource_name %>.toggle(:visible)
8
+ @<%= plural_resource_name %>.save
9
+ render :nothing => true
10
+ end
11
+ <%- end -%><%- if column_names.include?("position") -%>
12
+ def sort
13
+
14
+ <%= @model_name.demodulize %>.sort(params[:list])
15
+
16
+ render :nothing => true
17
+ end
18
+ <%- end -%>
19
+ def index
20
+ @<%= plural_resource_name %> = <%= @model_name.demodulize -%>.order(sort_column + " " + sort_direction)
21
+ end
22
+
23
+ def new
24
+ @<%= resource_name %> = <%= @model_name.demodulize -%>.new
25
+ render 'edit'
26
+ end
27
+
28
+ def edit
29
+ @<%= resource_name %> = <%= @model_name.demodulize -%>.find(params[:id])
30
+ end
31
+
32
+ def create
33
+ @<%= resource_name %> = <%= @model_name.demodulize -%>.new(params[:<%= resource_name %>])
34
+ if @<%= resource_name %>.save
35
+ redirect_to admin_<%= plural_resource_name %>_path, :notice => "#{<%= @model_name.demodulize %>.model_name.human} #{t 'flash.notice.was_added'}"
36
+ else
37
+ render 'edit'
38
+ end
39
+ end
40
+
41
+ def update
42
+ @<%= resource_name %> = <%= @model_name.demodulize -%>.find(params[:id])
43
+ if @<%= resource_name %>.update_attributes(params[:<%= resource_name %>])
44
+ redirect_to admin_<%= plural_resource_name %>_path, :notice => "#{<%= @model_name.demodulize %>.model_name.human} #{t 'flash.notice.was_updated'}"
45
+ else
46
+ render 'edit'
47
+ end
48
+ end
49
+
50
+ def destroy
51
+ @<%= resource_name %> = <%= @model_name.demodulize -%>.find(params[:id])
52
+ @<%= resource_name %>.destroy
53
+ redirect_to admin_<%= plural_resource_name %>_path, :alert => "#{<%= @model_name.demodulize %>.model_name.human} #{t 'flash.notice.was_deleted'}"
54
+ end
55
+
56
+ private
57
+
58
+ def sort_column
59
+ <%= @model_name.demodulize -%>.column_names.include?(params[:sort]) ? params[:sort] : <%= column_names.include?("position") ? "\'position\'" : "\'created_at\'" %>
60
+ end
61
+
62
+ def sort_direction
63
+ %w[asc desc].include?(params[:direction]) ? params[:direction] : "asc"
64
+ end
65
+ end
@@ -0,0 +1,38 @@
1
+ - content_for :page_header do
2
+ %p= link_to t('back'), admin_<%= controller_routing_path %>_path, :class => "bright_link"
3
+ %h1
4
+ - if @<%= resource_name %>.new_record?
5
+ = "#{t 'add'} #{<%= @model_name.demodulize %>.model_name.human}"
6
+ - else
7
+ = "#{t 'edit'} #{<%= @model_name.demodulize %>.model_name.human}"
8
+
9
+ = form_for [:admin, @<%= resource_name %>] do |f|
10
+ - if @<%= resource_name %>.errors.any?
11
+ #error_explanation
12
+ %h2= "#{t 'save_errors'}: #{@<%= resource_name %>.errors.count}"
13
+ %ul
14
+ - @<%= resource_name %>.errors.full_messages.each do |msg|
15
+ %li= msg
16
+ %table
17
+ <%- columns.each do |column| -%>
18
+ <%- unless column.name == "position" || column.name == "ancestry" %>
19
+ <%- if column.field_type.to_s == "text_area" -%>
20
+ %tr
21
+ %td{colspan: 2}
22
+ = f.label :<%= column.name %>
23
+ %br
24
+ = f.<%= column.field_type -%> :<%= column.name %>
25
+ <%- elsif column.field_type.to_s == "check_box" -%>
26
+ %tr
27
+ %th{colspan: 2}
28
+ = f.<%= column.field_type -%> :<%= column.name %>
29
+ = f.label :<%= column.name %>
30
+ <%- else -%>
31
+ %tr
32
+ %th= f.label :<%= column.name %>
33
+ %td= f.<%= column.field_type -%> :<%= column.name %>
34
+ <%- end -%>
35
+ <%- end -%>
36
+ <%- end -%>
37
+ .actions
38
+ = f.submit t('save')
@@ -0,0 +1,6 @@
1
+ - content_for(:page_header) do
2
+ %p= link_to "#{t 'add'} #{<%= @model_name.demodulize %>.model_name.human}", new_admin_<%= singular_controller_routing_path %>_path, :class => "bright_link"
3
+ %h1= link_to '<%= plural_resource_name %>', admin_<%= plural_resource_name %>_path
4
+ #index_wr
5
+ = show_tree(@<%= plural_resource_name %>)
6
+ = sort_tree(sort_admin_<%= plural_resource_name %>_path, '0')
@@ -0,0 +1,207 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/generated_attribute'
3
+
4
+ module Ideyabox
5
+ module Generators
6
+ class TreeGenerator < ::Rails::Generators::Base
7
+ source_root File.expand_path('../templates', __FILE__)
8
+ argument :controller_path, :type => :string
9
+ argument :model_name, :type => :string, :required => false
10
+ argument :layout, :type => :string, :default => "application",
11
+ :banner => "Specify application layout"
12
+
13
+ def initialize(args, *options)
14
+ super(args, *options)
15
+ initialize_views_variables
16
+ end
17
+
18
+ def copy_views
19
+ generate_views
20
+ end
21
+
22
+ def add_locale_templates
23
+ add_to_locales
24
+ end
25
+
26
+ def add_resources_and_root
27
+ add_resource_route
28
+ end
29
+
30
+ def updated_admin_layout
31
+ add_to_launchbar_items
32
+ add_to_topbar_items
33
+ end
34
+
35
+ def updating_models
36
+ inject_into_file "app/models/#{resource_name}.rb", "\n
37
+ has_ancestry :orphan_strategy => :rootify
38
+
39
+
40
+ def self.sort(list)
41
+
42
+ temp = {}
43
+ list.each do |key, value|
44
+ if temp[value]
45
+ temp[value] << key
46
+ else
47
+ temp[value] = [key]
48
+ end
49
+ end
50
+
51
+ temp.each do |parent, cats|
52
+ i = 1
53
+ if parent == 'root' || parent == 'null'
54
+ p = ''
55
+ else
56
+ p = #{@model_name.demodulize}.find(parent).id
57
+ end
58
+ cats.each do |cat|
59
+ c = #{@model_name.demodulize}.find(cat)
60
+ c.parent_id = p
61
+ c.position = i
62
+ c.save
63
+ i += 1
64
+ end
65
+ end
66
+ end
67
+
68
+ ", :after => "class #{@model_name.demodulize} < ActiveRecord::Base"
69
+
70
+ end
71
+
72
+ protected
73
+
74
+ def initialize_views_variables
75
+ @base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(controller_path)
76
+ @controller_routing_path = @controller_file_path.gsub(/\//, '_')
77
+ @model_name = @controller_class_nesting + "::#{@base_name.singularize.camelize}" unless @model_name
78
+ @model_name = @model_name.camelize
79
+ end
80
+
81
+ def controller_routing_path
82
+ @controller_routing_path
83
+ end
84
+
85
+ def singular_controller_routing_path
86
+ @controller_routing_path.singularize
87
+ end
88
+
89
+ def model_name
90
+ @model_name
91
+ end
92
+
93
+ def plural_model_name
94
+ @model_name.pluralize
95
+ end
96
+
97
+ def resource_name
98
+ @model_name.demodulize.underscore
99
+ end
100
+
101
+ def plural_resource_name
102
+ resource_name.pluralize
103
+ end
104
+
105
+ def sort_priority(column_name)
106
+ case column_name
107
+ when "position" then 1
108
+ when "visible" then 2
109
+ when "name" then 3
110
+ when "title" then 3
111
+ else 5
112
+ end
113
+ end
114
+
115
+ def columns
116
+ begin
117
+ excluded_column_names = %w[id created_at updated_at]
118
+ @model_name.constantize.columns.reject{|c| excluded_column_names.include?(c.name) || c.name.index("_id") }.sort{|a, b| sort_priority(a.name) <=> sort_priority(b.name)}.collect{|c| ::Rails::Generators::GeneratedAttribute.new(c.name, c.type)}
119
+ rescue NoMethodError
120
+ @model_name.constantize.fields.collect{|c| c[1]}.reject{|c| excluded_column_names.include?(c.name) || c.name.index("_id") }.collect{|c| ::Rails::Generators::GeneratedAttribute.new(c.name, c.type.to_s)}
121
+ end
122
+ end
123
+
124
+ def column_names
125
+ @model_name.constantize.column_names
126
+ end
127
+
128
+ def extract_modules(name)
129
+ modules = name.include?('/') ? name.split('/') : name.split('::')
130
+ name = modules.pop
131
+ path = modules.map { |m| m.underscore }
132
+ file_path = (path + [name.underscore]).join('/')
133
+ nesting = modules.map { |m| m.camelize }.join('::')
134
+ [name, path, file_path, nesting, modules.size]
135
+ end
136
+
137
+ def generate_views
138
+ views = {
139
+ "index.html.#{ext}" => "app/views/admin/#{@controller_file_path}/index.html.#{ext}",
140
+ "edit.html.#{ext}" => "app/views/admin/#{@controller_file_path}/edit.html.#{ext}"
141
+ }
142
+
143
+ selected_views = views
144
+ options.engine == generate_erb(selected_views)
145
+ end
146
+
147
+ def generate_erb(views)
148
+ views.each do |template_name, output_path|
149
+ template template_name, output_path
150
+ end
151
+ generate_controller
152
+ end
153
+
154
+ def ext
155
+ :haml
156
+ end
157
+
158
+ def generate_controller
159
+ template "controllers/controller.rb", "app/controllers/admin/#{plural_resource_name}_controller.rb"
160
+ end
161
+
162
+ def add_resource_route
163
+ resources_string = "\n resources :#{plural_resource_name} do\n"
164
+ sort_string = " get \"sort\", :on => :collection\n"
165
+ toggleshow_string = " get \"toggleshow\", :on => :member\n"
166
+
167
+ if column_names.include?("visible") && column_names.include?("position")
168
+ final_string = "#{resources_string}#{sort_string}#{toggleshow_string} end\n"
169
+ elsif column_names.include?("visible")
170
+ final_string = "#{resources_string}#{toggleshow_string} end\n"
171
+ elsif column_names.include?("position")
172
+ final_string = "#{resources_string}#{sort_string} end\n"
173
+ else
174
+ final_string = "\n resources :#{plural_resource_name}\n"
175
+ end
176
+
177
+ inject_into_file "config/routes.rb", final_string, :after => "\n namespace :admin do\n"
178
+ end
179
+
180
+ def add_to_launchbar_items
181
+ final_string = "#{plural_resource_name} "
182
+
183
+ inject_into_file "app/views/admin/shared/_launchbar.html.haml", final_string, :after => "- @active = :section if %w{"
184
+ end
185
+
186
+ def add_to_topbar_items
187
+ final_string = "\n %li{:class => \"\#\{\'active\' if c == \'#{plural_resource_name}\'}\"\}= link_to \'#{plural_resource_name}\', admin_#{plural_resource_name}_path"
188
+
189
+ inject_into_file "app/views/admin/shared/_topbar.html.haml", final_string, :after => "-when :section"
190
+ end
191
+
192
+ def add_to_locales
193
+ locales = [:ru, :en]
194
+
195
+ attributes = column_names.collect {|column| " #{column}: \"#{column}\"\n"}
196
+
197
+ attributes_string = " #{resource_name}:\n#{attributes.join}"
198
+
199
+ locales.each do |locale|
200
+ inject_into_file "config/locales/#{locale}.yml", " #{resource_name}: \"#{resource_name}\"\n", :after => "models:\n"
201
+ inject_into_file "config/locales/#{locale}.yml", attributes_string, :after => "attributes:\n"
202
+ end
203
+ end
204
+
205
+ end
206
+ end
207
+ end
@@ -1,3 +1,3 @@
1
1
  module Ideyabox
2
- VERSION = "0.1.3"
2
+ VERSION = "0.1.4"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ideyabox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -45,7 +45,7 @@ files:
45
45
  - app/assets/javascripts/default.js
46
46
  - app/assets/javascripts/jquery.Jcrop.min.js
47
47
  - app/assets/javascripts/jquery.color.js
48
- - app/assets/javascripts/jquery.ui.nestedSortable.js
48
+ - app/assets/javascripts/jquery.mjs.nestedSortable.js
49
49
  - app/assets/javascripts/jquery.uploadify.min.js
50
50
  - app/assets/javascripts/modernizr.js
51
51
  - app/assets/javascripts/swfobject.js
@@ -109,6 +109,10 @@ files:
109
109
  - lib/generators/ideyabox/scaffold/templates/edit.html.haml
110
110
  - lib/generators/ideyabox/scaffold/templates/index.html.haml
111
111
  - lib/generators/ideyabox/scaffold/templates/index.js.haml
112
+ - lib/generators/ideyabox/tree/templates/controllers/controller.rb
113
+ - lib/generators/ideyabox/tree/templates/edit.html.haml
114
+ - lib/generators/ideyabox/tree/templates/index.html.haml
115
+ - lib/generators/ideyabox/tree/tree_generator.rb
112
116
  - lib/ideyabox.rb
113
117
  - lib/ideyabox/engine.rb
114
118
  - lib/ideyabox/version.rb