ideyabox 0.1.3 → 0.1.4

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.
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