effective_ckeditor 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 46022b1ae3481ec3be596a93d32458777be3ad34
4
- data.tar.gz: 6c956c4d07044bc4f3d6626cce09d2a586c8143d
3
+ metadata.gz: 6abe1be063968942b886583f1efd66fa0922f8ad
4
+ data.tar.gz: f212652bc21b13501653bec315ba1f86fdf832f6
5
5
  SHA512:
6
- metadata.gz: ae12510c6e4da3293a0a7744ac1e9a2599dd4aa327819fc3dd4a64eda6fe221620622193637952a0acaa57ee7b2432dd9b7d020ad99ca5b014da1570785b5e47
7
- data.tar.gz: a97ab6455c7fa248c58a75471f502a6144db5dfe4c15f80d3a974d7b9043409cf73ab0080f9eb7601f6076ada000b7ad0eba161e22f79d0f97ff8e1993dfa242
6
+ metadata.gz: 7cff60407f65c4b8423ef6ac68fd22df8dfd9c34e9156d90e52a027c3d547c2b01f471e2df3b4baef32dc6abbcd793549eabb4eec0a780062e9eb27f3ac91081
7
+ data.tar.gz: e4dfd0bb28ece84c558e37f782943569676447e5c9eede0bd74f271bbd78e2a29c8d6f0fc4b2f693cf30384be9861e304769628c197f456aae7b20a2145ad5b2
@@ -0,0 +1,543 @@
1
+ # OKAY THE TOP OF THIS IS A JQUERY PLUGIN
2
+ # When the CKEditor plugin below is initialized via an /edit/ route
3
+ # it initialized this jquery on any $(.effective-menu) objects present on the page
4
+
5
+ (($, window) ->
6
+ class EffectiveMenuEditor
7
+ defaults:
8
+ menuClass: 'effective-menu'
9
+ expandThreshold: 250 # Seconds before a leaf li item will be auto-expanded into a dropdown
10
+ maxDepth: 9999
11
+
12
+ menu: null
13
+ draggable: null
14
+ droppable: null
15
+
16
+ constructor: (el, options) ->
17
+ @menu = $(el)
18
+
19
+ @options = $.extend({}, @defaults, options)
20
+ @options.maxDepth = @menu.data('effective-menu-maxdepth') if @menu.data('effective-menu-maxdepth')
21
+
22
+ @initCkEditorEvents()
23
+ @initAddButtonEvents()
24
+ @initDestroyButtonEvents()
25
+ @initDragDropEvents()
26
+ @initAdditionalEvents()
27
+ true
28
+
29
+ # All 3 of these events are basically the same:
30
+ # Remove the open class and
31
+
32
+ initCkEditorEvents: ->
33
+ # Oh yea, you like that selector. The comma means or, so there are actually 3 selectors being created here
34
+ # They need to be in this order for the stopPropagation to work properly.
35
+ @menu.on 'click', 'li.dropdown.open,.dropdown-menu > li.dropdown,li:not(.dropdown)', (event) =>
36
+ event.stopPropagation()
37
+ @menu.find('.open').removeClass('open')
38
+ # Open the CKEDITOR dialog and pass the source effective_menu_item $('li') to the dialog
39
+ CKEDITOR.instances[Object.keys(CKEDITOR.instances)[0]].openDialog 'effectiveMenusDialog', (dialog) ->
40
+ dialog.effective_menu_item = $(event.currentTarget)
41
+
42
+ initAddButtonEvents: ->
43
+ @menu.on 'mouseenter', (event) => @menu.children('.actions').children('.add-item').show()
44
+ @menu.on 'mouseleave', (event) => @menu.children('.actions').children('.add-item').hide()
45
+ @menu.on 'mouseenter', '.add-item', (event) -> $(event.currentTarget).addClass('large') ; event.stopPropagation()
46
+ @menu.on 'mouseleave', '.add-item', (event) -> $(event.currentTarget).removeClass('large'); event.stopPropagation()
47
+
48
+ @menu.on 'click', '.add-item', (event) =>
49
+ event.preventDefault()
50
+ unique_id = new Date().getTime()
51
+ item = $(@menu.data('effective-menu-new-html').replace(':new', "#{unique_id}", 'g'))
52
+
53
+ @menu.children('.actions').before(item)
54
+
55
+ CKEDITOR.instances[Object.keys(CKEDITOR.instances)[0]].openDialog 'effectiveMenusDialog', (dialog) ->
56
+ dialog.effective_menu_item = item
57
+
58
+ initDestroyButtonEvents: ->
59
+ @menu.on 'dragenter', '.remove-item', (event) => $(event.currentTarget).addClass('large')
60
+ @menu.on 'dragleave', '.remove-item', (event) => $(event.currentTarget).removeClass('large')
61
+
62
+ @menu.on 'dragover', '.remove-item', (event) =>
63
+ return false unless @draggable
64
+ glyphicon = $(event.currentTarget).addClass('large') # Garbage can
65
+
66
+ event.preventDefault() # Enable drag and drop
67
+ event.stopPropagation()
68
+
69
+ @menu.on 'drop', '.remove-item', (event) =>
70
+ return false unless @draggable
71
+ glyphicon = $(event.currentTarget).removeClass('large')
72
+
73
+ @markDestroyed(@draggable)
74
+
75
+ @cleanupMenuAfterDrop()
76
+ event.stopPropagation()
77
+ event.preventDefault()
78
+
79
+ initAdditionalEvents: ->
80
+ @menu.on 'click', 'a', (event) -> event.preventDefault()
81
+
82
+ initDragDropEvents: ->
83
+ @menu.on 'dragenter', 'li', (event) =>
84
+ @droppable = null
85
+ @droppable = {item: $(event.currentTarget), time: new Date().getTime()}
86
+ event.preventDefault() if @draggable # enable drag and drop
87
+
88
+ @menu.on 'dragleave', 'li', (event) =>
89
+ event.preventDefault() if @draggable # enable drag and drop
90
+
91
+ @menu.on 'dragstart', 'li', (event) =>
92
+ @draggable = item = $(event.currentTarget)
93
+ @menu.children('.actions').children('.add-item').hide()
94
+ item.removeClass('open').find('.open').removeClass('open')
95
+
96
+ event.originalEvent.dataTransfer.setData('text/html', item[0].outerHTML)
97
+
98
+ item.css('opacity', '0.4') # Show it slightly removed from the DOM
99
+ @menu.addClass('dragging')
100
+ event.stopPropagation()
101
+
102
+ @menu.on 'dragover', 'li', (event) =>
103
+ return false unless @draggable
104
+
105
+ item = $(event.currentTarget)
106
+
107
+ if item.hasClass('dropdown') && !item.hasClass('open') # This is a menu, expand it
108
+ @menu.find('.open').removeClass('open')
109
+ item.parentsUntil(@menu, 'li').andSelf().addClass('open')
110
+ else
111
+ event.preventDefault() # Enable drag and drop
112
+ @expandToDropdown(item) if (new Date().getTime()) > @options.expandThreshold + (@droppable.time || 0)
113
+
114
+ # If I don't have the placeholder class already
115
+ if item.hasClass('placeholder') == false
116
+ @menu.find('.placeholder').removeClass('placeholder')
117
+ item.addClass('placeholder')
118
+
119
+ event.stopPropagation()
120
+
121
+ @menu.on 'dragend', 'li', (event) =>
122
+ return false unless @draggable
123
+ item = $(event.currentTarget)
124
+
125
+ @cleanupMenuAfterDrop()
126
+ item.css('opacity', '1.0')
127
+
128
+ @menu.on 'drop', 'li', (event) =>
129
+ item = $(event.currentTarget)
130
+
131
+ # Don't allow to drop into myself or my own children
132
+ return false if !@draggable? || @draggable.is(item) || @draggable.find(item).length > 0
133
+
134
+ new_item = $(event.originalEvent.dataTransfer.getData('text/html'))
135
+
136
+ item.before(new_item)
137
+ @draggable.remove()
138
+
139
+ @cleanupMenuAfterDrop()
140
+ @cleanupItemAfterDrop(new_item)
141
+
142
+ event.stopPropagation()
143
+ event.preventDefault()
144
+
145
+ # If it hasn't already been expanded...
146
+ # Append some html to make it into a faux dropdown
147
+ # which is just a ul.dropdown-menu > li
148
+ expandToDropdown: (item) ->
149
+ return false if item.hasClass('dropdown') || item.hasClass('effective-menu-expand')
150
+ return false if @depthOf(item) >= @options.maxDepth
151
+
152
+ item.append(@menu.data('effective-menu-expand-html'))
153
+ item.addClass('dropdown')
154
+ item.children('a').attr('data-toggle', 'dropdown')
155
+
156
+ # If I'm a top level dropdown
157
+ if item.parent().hasClass('effective-menu')
158
+ item.children('a').append("<span class='caret'></span>")
159
+
160
+ @menu.find('.open').removeClass('open')
161
+ item.parentsUntil(@menu, 'li.dropdown').addClass('open')
162
+
163
+ cleanupMenuAfterDrop: ->
164
+ # chrome puts in a weird meta tag that firefox doesnt
165
+ # so we delete it here
166
+ @menu.find('meta,li.effective-menu-expand').remove()
167
+
168
+ # Collapse any empty dropdowns we may have expanded back to leafs
169
+ @menu.find('.dropdown-menu:empty').each (index, item) ->
170
+ item = $(item).closest('.dropdown')
171
+ item.removeClass('dropdown').removeClass('open')
172
+ item.children('a').removeAttr('data-toggle').find('span.caret').remove()
173
+ item.children('.dropdown-menu').remove()
174
+
175
+ @menu.removeClass('dragging')
176
+ @menu.children('.actions').children('.add-item').show()
177
+ @menu.find('.placeholder,.open').removeClass('placeholder').removeClass('open')
178
+
179
+ @draggable = null
180
+ @droppable = null
181
+
182
+ cleanupItemAfterDrop: (item) ->
183
+ item.children('a').find('span.caret').remove() # Just always remove the caret if present
184
+
185
+ # And add it back if we're a top level node
186
+ if item.parent().hasClass('effective-menu') && item.children('.dropdown-menu').length
187
+ item.children('a').append("<span class='caret'></span>")
188
+
189
+ item.parentsUntil(@menu, 'li.dropdown').addClass('open')
190
+
191
+ # Very top level items are assigned Depth of 0
192
+ # The first dropdowns all have Depth of 1
193
+ depthOf: (item) -> item.parentsUntil(@menu, 'li').length
194
+
195
+ # Just pass _destroyed = 1 back to rails to delete this item
196
+ # Rails seems to disregard new items set to the new Date.now() values anyhow
197
+ # Put all deleted items after the .actions div just to be tidy
198
+ markDestroyed: (item) ->
199
+ item.hide().addClass('destroyed').find("input[name$='[_destroy]']").val(1)
200
+ @menu.children('.actions').after(item.remove())
201
+
202
+ # This method is called with a Hash value
203
+ # that is called by reference from the parent function
204
+ #
205
+ # This serialize method is called from the effective_ckeditor gem plugins/effective_regions plugin
206
+ # by the SaveAll method to actually persist the menus when it also saves the regions
207
+ # This way the saves happen all at once
208
+
209
+ serialize: (retval) ->
210
+ # console.log "============ BEFORE =============="
211
+ # @menu.find('li').each (index, item) =>
212
+ # item = $(item)
213
+ # label = item.children('a').first().text()
214
+ # left = item.children('.menu-item').children("input[name$='[lft]']").val()
215
+ # right = item.children('.menu-item').children("input[name$='[rgt]']").val()
216
+ # console.log "[#{label}] #{left}, #{right}"
217
+ # console.log "=================================="
218
+
219
+ @assignLftRgt(@menu, 1)
220
+
221
+ # console.log "============ AFTER =============="
222
+ # @menu.find('li').each (index, item) =>
223
+ # item = $(item)
224
+ # label = item.children('a').first().text()
225
+ # left = item.children('.menu-item').children("input[name$='[lft]']").val()
226
+ # right = item.children('.menu-item').children("input[name$='[rgt]']").val()
227
+ # console.log "[#{label}] #{left}, #{right}"
228
+ # console.log "=================================="
229
+
230
+ items = {}
231
+
232
+ # This next bit just massages some of the form serialization
233
+ # and translates the jquery serializeArray into the formnat needed by Rails accepts_nested_attributes
234
+
235
+ $.each @menu.find('input').serializeArray(), ->
236
+ @name = @name.replace("effective_menu[menu_items_attributes]", "menu_items_attributes")
237
+
238
+ if items[@name]?
239
+ items[@name] = [items[@name]] unless items[@name].push
240
+ items[@name].push (@value || '')
241
+ else
242
+ items[@name] = (@value || '')
243
+
244
+ # This retVal has to account for multiple effective-menus on one page
245
+ retval[@menu.data('effective-menu-id')] = items
246
+
247
+ assignLftRgt: (parent, lft) ->
248
+ rgt = lft + 1
249
+
250
+ parent.children('.dropdown-menu').children('li:not(.destroyed)').each (_, child) =>
251
+ rgt = @assignLftRgt($(child), rgt)
252
+
253
+ parent.children('li:not(.destroyed)').each (_, child) =>
254
+ rgt = @assignLftRgt($(child), rgt)
255
+
256
+ parent.children('.menu-item').children("input[name$='[lft]']").val(lft)
257
+ parent.children('.menu-item').children("input[name$='[rgt]']").val(rgt)
258
+
259
+ rgt + 1
260
+
261
+
262
+ $.fn.extend effectiveMenuEditor: (option, args...) ->
263
+ @each ->
264
+ $this = $(this)
265
+ data = $this.data('effectiveMenuEditor')
266
+
267
+ $this.data('effectiveMenuEditor', (data = new EffectiveMenuEditor(this, option))) if !data
268
+ data[option].apply(data, args) if typeof option == 'string'
269
+ $this
270
+
271
+ ) window.jQuery, window
272
+
273
+
274
+ # AND THE REST IS A CKEDITOR PLUGIN
275
+
276
+ # This plugin is registered with CkEditor and a dialog to edit menu item is created
277
+ # See the initCkEditorEvents() function in the jquery plugin that calls this dialog
278
+ # When the dialog is called, it sets dialog.effective_menu_item to
279
+ # to the event.currentTarget, i.e. the jquery element $(li)
280
+
281
+ CKEDITOR.plugins.add 'effective_menus',
282
+ init: (editor) ->
283
+ $('.effective-menu').effectiveMenuEditor() # Initialize the EffectiveMenus
284
+
285
+ CKEDITOR.dialog.add 'effectiveMenusDialog', (editor) ->
286
+ {
287
+ title: 'Effective Menu Item'
288
+ minWidth: 350,
289
+ minHeight: 200,
290
+ contents: [
291
+ {
292
+ id: 'item',
293
+ label: 'Menu Item'
294
+ elements: [
295
+ {
296
+ id: 'add_or_edit',
297
+ type: 'html',
298
+ html: '',
299
+ setup: (element) ->
300
+ # This just doesnt work and Im not sure why
301
+ if this.getDialog().effective_menu_item.hasClass('new-item')
302
+ this.setValue('<p>Create a new menu item</p>')
303
+ else
304
+ this.setValue('<p>Editing an existing menu item</p>')
305
+ },
306
+ {
307
+ id: 'title',
308
+ type: 'text',
309
+ label: 'Title',
310
+ validate: CKEDITOR.dialog.validate.notEmpty('please enter a title')
311
+ setup: (element) ->
312
+ this.setValue(element.children('.menu-item').children("input[name$='[title]']").val())
313
+ commit: (element) ->
314
+ element.children('.menu-item').children("input[name$='[title]']").val(this.getValue())
315
+
316
+ if element.children('a').find('span.caret').length > 0
317
+ element.children('a').text(this.getValue())
318
+ element.children('a').append("<span class='caret'></span>")
319
+ else
320
+ element.children('a').text(this.getValue())
321
+ validate: ->
322
+ if this.getDialog().getValueOf('item', 'source') != 'Divider' && (this.getValue() || '').length == 0
323
+ CKEDITOR.dialog.validate.notEmpty('please enter a title').apply(this)
324
+ },
325
+ {type: 'html', html: '<br>'},
326
+ {
327
+ id: 'source',
328
+ type: 'radio',
329
+ label: 'Link Type',
330
+ items: [['Page', 'Page'], ['URL', 'URL'], ['Route', 'Route'], ['Divider', 'Divider']]
331
+ setup: (element) ->
332
+ menuable_id = element.children('.menu-item').children("input[name$='[menuable_id]']").val() || ''
333
+ special = element.children('.menu-item').children("input[name$='[special]']").val() || ''
334
+ url = element.children('.menu-item').children("input[name$='[url]']").val() || ''
335
+
336
+ if menuable_id.length > 0
337
+ this.setValue('Page')
338
+ else if special == 'divider'
339
+ this.setValue('Divider')
340
+ else if special.length > 0
341
+ this.setValue('Route')
342
+ else if url.length > 0 && url != '#'
343
+ this.setValue('URL')
344
+ else
345
+ this.setValue('Page')
346
+
347
+ onChange: (event) ->
348
+ if this.getValue() == 'Page'
349
+ this.getDialog().getContentElement('item', 'title').getElement().show()
350
+ this.getDialog().getContentElement('item', 'menuable_id').getElement().show()
351
+
352
+ this.getDialog().getContentElement('item', 'url').getElement().hide()
353
+ this.getDialog().getContentElement('item', 'special').getElement().hide()
354
+
355
+ if this.getValue() == 'URL'
356
+ this.getDialog().getContentElement('item', 'title').getElement().show()
357
+ this.getDialog().getContentElement('item', 'url').getElement().show()
358
+
359
+ this.getDialog().getContentElement('item', 'menuable_id').getElement().hide()
360
+ this.getDialog().getContentElement('item', 'special').getElement().hide()
361
+
362
+ if this.getValue() == 'Divider'
363
+ this.getDialog().getContentElement('item', 'url').getElement().hide()
364
+ this.getDialog().getContentElement('item', 'title').getElement().hide()
365
+ this.getDialog().getContentElement('item', 'menuable_id').getElement().hide()
366
+ this.getDialog().getContentElement('item', 'special').getElement().hide()
367
+
368
+ if this.getValue() == 'Route'
369
+ this.getDialog().getContentElement('item', 'title').getElement().show()
370
+ this.getDialog().getContentElement('item', 'special').getElement().show()
371
+
372
+ this.getDialog().getContentElement('item', 'menuable_id').getElement().hide()
373
+ this.getDialog().getContentElement('item', 'url').getElement().hide()
374
+ },
375
+ {
376
+ id: 'menuable_id',
377
+ type: 'select',
378
+ label: 'Page',
379
+ items: (
380
+ pages = []
381
+ $.ajax
382
+ url: '/admin/pages'
383
+ dataType: 'json'
384
+ async: false
385
+ complete: (data) -> pages = data.responseJSON
386
+ pages
387
+ ),
388
+ setup: (element) ->
389
+ this.setValue(element.children('.menu-item').children("input[name$='[menuable_id]']").val())
390
+ commit: (element) ->
391
+ if this.getElement().isVisible()
392
+ element.children('.menu-item').children("input[name$='[menuable_id]']").val(this.getValue())
393
+ element.children('.menu-item').children("input[name$='[menuable_type]']").val('Effective::Page')
394
+ else
395
+ element.children('.menu-item').children("input[name$='[menuable_id]']").val('')
396
+ element.children('.menu-item').children("input[name$='[menuable_type]']").val('')
397
+ validate: ->
398
+ if this.getElement().isVisible() && (this.getValue() || '').length == 0
399
+ CKEDITOR.dialog.validate.notEmpty('please select a page').apply(this)
400
+ },
401
+ {
402
+ id: 'url',
403
+ type: 'text',
404
+ label: 'URL',
405
+ setup: (element) ->
406
+ this.setValue(element.children('.menu-item').children("input[name$='[url]']").val())
407
+ commit: (element) ->
408
+ if this.getElement().isVisible() then value = this.getValue() else value = ''
409
+
410
+ element.children('.menu-item').children("input[name$='[url]']").val(value)
411
+ element.children('a').attr('href', value || '#')
412
+ validate: ->
413
+ if this.getElement().isVisible() && (this.getValue() || '').length == 0
414
+ CKEDITOR.dialog.validate.notEmpty('please enter a URL').apply(this)
415
+ },
416
+ {
417
+ id: 'special',
418
+ type: 'text',
419
+ label: 'Route',
420
+ setup: (element) ->
421
+ this.setValue(element.children('.menu-item').children("input[name$='[special]']").val())
422
+ commit: (element) ->
423
+ if this.getDialog().getValueOf('item', 'source') == 'Divider'
424
+ element.children('.menu-item').children("input[name$='[special]']").val('divider')
425
+ else if this.getElement().isVisible()
426
+ element.children('.menu-item').children("input[name$='[special]']").val(this.getValue())
427
+ else
428
+ element.children('.menu-item').children("input[name$='[special]']").val('')
429
+ # There is more stuff in the classes commit
430
+ validate: ->
431
+ if this.getDialog().getValueOf('item', 'source') == 'Divider'
432
+ if this.getDialog().effective_menu_item.hasClass('dropdown')
433
+ CKEDITOR.dialog.validate.notEmpty('cannot convert existing dropdown menu to a Divider').apply(this)
434
+ else if this.getElement().isVisible()
435
+ if (this.getValue() || '').length == 0
436
+ CKEDITOR.dialog.validate.notEmpty('please enter a route').apply(this)
437
+ }
438
+ ] # /tab1 elements
439
+ },
440
+ {
441
+ id: 'permissions',
442
+ label: 'Permissions',
443
+ elements: [
444
+ {
445
+ id: 'signed_out',
446
+ type: 'checkbox',
447
+ label: 'Only visible when signed out',
448
+ setup: (element) ->
449
+ value = element.children('.menu-item').children("input[name$='[roles_mask]']").val()
450
+ this.setValue(value == '-1')
451
+ onChange: (event) ->
452
+ if this.getValue() == true
453
+ this.getDialog().setValueOf('permissions', 'signed_in', false)
454
+ this.getDialog().setValueOf('permissions', 'roles_mask', '')
455
+ },
456
+ {
457
+ id: 'signed_in',
458
+ type: 'checkbox',
459
+ label: 'Only visible when signed in',
460
+ setup: (element) ->
461
+ value = element.children('.menu-item').children("input[name$='[roles_mask]']").val()
462
+ this.setValue(value.length > 0 && parseInt(value, 10) >= 0)
463
+ onChange: (event) ->
464
+ if this.getValue() == true
465
+ this.getDialog().setValueOf('permissions', 'signed_out', false)
466
+ },
467
+ {
468
+ id: 'roles_mask',
469
+ type: 'text',
470
+ label: 'Roles Mask',
471
+ setup: (element) ->
472
+ value = parseInt(element.children('.menu-item').children("input[name$='[roles_mask]']").val(), 10)
473
+ if value > 0 then this.setValue(value) else this.setValue('')
474
+ commit: (element) ->
475
+ if ('' + this.getValue()).length > 0
476
+ element.children('.menu-item').children("input[name$='[roles_mask]']").val(this.getValue())
477
+ else if this.getDialog().getValueOf('permissions', 'signed_in') == true
478
+ element.children('.menu-item').children("input[name$='[roles_mask]']").val(0)
479
+ else if this.getDialog().getValueOf('permissions', 'signed_out') == true
480
+ element.children('.menu-item').children("input[name$='[roles_mask]']").val(-1)
481
+ else
482
+ element.children('.menu-item').children("input[name$='[roles_mask]']").val('')
483
+ onKeyup: (event) ->
484
+ if ('' + this.getValue()).length > 0
485
+ this.getDialog().setValueOf('permissions', 'signed_in', true)
486
+ this.getDialog().setValueOf('permissions', 'signed_out', false)
487
+ validate: ->
488
+ if ('' + this.getValue()).length > 0
489
+ CKEDITOR.dialog.validate.integer('roles_mask must be an integer').apply(this)
490
+ }
491
+ ]
492
+ },
493
+ {
494
+ id: 'advanced',
495
+ label: 'Advanced'
496
+ elements: [
497
+ {
498
+ id: 'new_window',
499
+ type: 'checkbox',
500
+ label: 'Open in new window',
501
+ setup: (element) ->
502
+ value = element.children('.menu-item').children("input[name$='[new_window]']").val()
503
+ if value == 'true' then this.setValue(true) else this.setValue(false)
504
+ commit: (element) ->
505
+ element.children('.menu-item').children("input[name$='[new_window]']").val(this.getValue())
506
+ },
507
+ {
508
+ id: 'classes',
509
+ type: 'text',
510
+ label: 'HTML Classes',
511
+ setup: (element) ->
512
+ this.setValue(element.children('.menu-item').children("input[name$='[classes]']").val())
513
+ commit: (element) ->
514
+ value = this.getValue()
515
+ element.children('.menu-item').children("input[name$='[classes]']").val(value)
516
+
517
+ dropdown = element.hasClass('dropdown')
518
+
519
+ element.prop('class', value)
520
+
521
+ # Put back classes we need
522
+ element.addClass('dropdown') if dropdown
523
+
524
+ if this.getDialog().getValueOf('item', 'source') == 'Divider'
525
+ element.addClass('divider')
526
+ else
527
+ element.removeClass('divider')
528
+ }
529
+ ]
530
+ }
531
+ ], # /contents
532
+
533
+ onShow: -> this.setupContent(this.effective_menu_item) if this.effective_menu_item
534
+
535
+ onOk: ->
536
+ this.commitContent(this.effective_menu_item)
537
+ this.effective_menu_item.removeClass('new-item') if this.effective_menu_item.hasClass('new-item')
538
+ this.effective_menu_item = undefined
539
+
540
+ onCancel: ->
541
+ this.effective_menu_item.remove() if this.effective_menu_item.hasClass('new-item')
542
+ this.effective_menu_item = undefined
543
+ }
@@ -36,18 +36,24 @@ SaveAll = {
36
36
  button.css('background-image', 'url(/assets/ckeditor/plugins/effective_regions/icons/saving.png)')
37
37
  setTimeout(
38
38
  -> button.css('background-image', 'url(/assets/ckeditor/plugins/effective_regions/icons/save.png)')
39
- 2000)
40
-
41
- data = {}
42
- data[name] = @instanceData(instance) for name, instance of CKEDITOR.instances
39
+ 2000
40
+ )
43
41
 
44
42
  url = window.location.protocol + '//' + window.location.host + '/edit' + window.location.pathname
45
43
 
44
+ # Collect all Effective::Region Data
45
+ regionData = {}
46
+ regionData[name] = @instanceData(instance) for name, instance of CKEDITOR.instances
47
+
48
+ # Collect all the Effective::Menu Data
49
+ menuData = {}
50
+ $('.effective-menu').effectiveMenuEditor('serialize', menuData)
51
+
46
52
  $.ajax
47
53
  url: url
48
54
  type: 'PUT'
49
55
  dataType: 'json'
50
- data: { effective_regions: data }
56
+ data: { effective_regions: regionData, effective_menus: menuData }
51
57
  async: false
52
58
  complete: (data) ->
53
59
  if data.responseText == 'refresh'
@@ -1,7 +1,7 @@
1
1
  CKEDITOR.editorConfig = (config) ->
2
2
  config.startupShowBorders = true
3
3
 
4
- config.extraPlugins = 'effective_regions,effective_assets'
4
+ config.extraPlugins = 'effective_regions,effective_assets,effective_menus'
5
5
  config.format_tags = 'p;h1;h2;h3;h4;h5;h6;pre;div'
6
6
 
7
7
  config.templates = 'effective_regions'
@@ -0,0 +1,64 @@
1
+ .effective-menu.dragging, {
2
+ cursor: move !important; // I'm having trouble getting the cursor working
3
+ li, a, * { cursor: move !important; }
4
+
5
+ > .actions {
6
+ .remove-item { display: inline-block; }
7
+ }
8
+ }
9
+
10
+ .effective-menu {
11
+ position: relative;
12
+ border: 1px dotted #4195fc; // Match the effective_regions editable border color
13
+
14
+ min-width: 30px; // What to do with an empty menu...
15
+ min-height: 30px;
16
+
17
+ li.divider { height: 3px; }
18
+ .menu-item { display: none; } // under each li, Contains the form controls. Nothing to view here
19
+
20
+ // Sub-level placeholder
21
+ li.placeholder {
22
+ position: relative;
23
+
24
+ &:before {
25
+ position: absolute;
26
+ content: "";
27
+ height: 0px;
28
+ width: 0px;
29
+ left: 2px; // Was -5px;
30
+ top: -4px;
31
+ margin-top: -5px;
32
+ border-left: 5px solid red;
33
+ border-top: 5px solid transparent;
34
+ border-bottom: 5px solid transparent;
35
+ border-right: none;
36
+ }
37
+ }
38
+
39
+ // Top level placeholder
40
+ > li.placeholder {
41
+ &:before {
42
+ top: 7px;
43
+
44
+ margin-top: -6px;
45
+ border-left: 5px solid transparent;
46
+ border-top: 5px solid red;
47
+ border-bottom: none;
48
+ border-right: 5px solid transparent;
49
+ }
50
+ }
51
+
52
+ > .actions {
53
+ cursor: pointer;
54
+ position: absolute;
55
+ right: 0;
56
+ top: 0;
57
+ font-size: 14px;
58
+
59
+ .add-item { display: none; } // Bootstrap3 glyphicon
60
+ .remove-item { display: none; } // Bootstrap3 glyphicon
61
+
62
+ .large { font-size: 20px; }
63
+ }
64
+ }
@@ -1,2 +1,3 @@
1
1
  @import 'effective_ckeditor/layout';
2
2
  @import 'effective_ckeditor/overrides';
3
+ @import 'effective_ckeditor/menu_editor';
@@ -1,3 +1,3 @@
1
1
  module EffectiveCkeditor
2
- VERSION = '1.0.1'.freeze
2
+ VERSION = '1.1.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: effective_ckeditor
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code and Effect
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-31 00:00:00.000000000 Z
11
+ date: 2015-01-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -51,6 +51,7 @@ files:
51
51
  - app/assets/javascripts/ckeditor/plugins/effective_assets/icons/effectiveassets.png
52
52
  - app/assets/javascripts/ckeditor/plugins/effective_assets/icons/hidpi/effectiveassets.png
53
53
  - app/assets/javascripts/ckeditor/plugins/effective_assets/plugin.js.coffee
54
+ - app/assets/javascripts/ckeditor/plugins/effective_menus/plugin.js.coffee
54
55
  - app/assets/javascripts/ckeditor/plugins/effective_regions/icons/exit.png
55
56
  - app/assets/javascripts/ckeditor/plugins/effective_regions/icons/hidpi/exit.png
56
57
  - app/assets/javascripts/ckeditor/plugins/effective_regions/icons/hidpi/save.png
@@ -176,6 +177,7 @@ files:
176
177
  - app/assets/javascripts/vendor/jquery.cookie.js
177
178
  - app/assets/stylesheets/effective_ckeditor.css.scss
178
179
  - app/assets/stylesheets/effective_ckeditor/layout.css.scss
180
+ - app/assets/stylesheets/effective_ckeditor/menu_editor.css.scss
179
181
  - app/assets/stylesheets/effective_ckeditor/overrides.css.scss
180
182
  - lib/effective_ckeditor.rb
181
183
  - lib/effective_ckeditor/engine.rb