scrivito_editors 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +48 -0
- data/LICENSE +4 -0
- data/README.md +55 -0
- data/Rakefile +9 -0
- data/app/assets/fonts/editing_icons-webfont.eot +0 -0
- data/app/assets/fonts/editing_icons-webfont.ttf +0 -0
- data/app/assets/fonts/editing_icons-webfont.woff +0 -0
- data/app/assets/javascripts/jquery_additions/jquery_center.js.coffee +6 -0
- data/app/assets/javascripts/mediabrowser/inspector.js.coffee +65 -0
- data/app/assets/javascripts/mediabrowser/mediabrowser.js.coffee +420 -0
- data/app/assets/javascripts/mediabrowser/uploader.js.coffee +132 -0
- data/app/assets/javascripts/scrivito_editors.js +18 -0
- data/app/assets/javascripts/scrivito_editors/date_editor.js.coffee +50 -0
- data/app/assets/javascripts/scrivito_editors/enum_editor.js.coffee +36 -0
- data/app/assets/javascripts/scrivito_editors/html_editor.js.coffee +140 -0
- data/app/assets/javascripts/scrivito_editors/linklist_editor.js.coffee +176 -0
- data/app/assets/javascripts/scrivito_editors/multienum_editor.js.coffee +37 -0
- data/app/assets/javascripts/scrivito_editors/placeholder.js.coffee +22 -0
- data/app/assets/javascripts/scrivito_editors/reference_editor.js.coffee +28 -0
- data/app/assets/javascripts/scrivito_editors/referencelist_editor.js.coffee +111 -0
- data/app/assets/javascripts/scrivito_editors/slider_editor.js.coffee +39 -0
- data/app/assets/javascripts/scrivito_editors/string_editor.js.coffee +83 -0
- data/app/assets/javascripts/scrivito_editors/text_editor.js.coffee +85 -0
- data/app/assets/stylesheets/scrivito_editors.css +16 -0
- data/app/assets/stylesheets/scrivito_editors/buttons.css +161 -0
- data/app/assets/stylesheets/scrivito_editors/editors/linklist_editor.css +105 -0
- data/app/assets/stylesheets/scrivito_editors/editors/referencelist_editor.css +67 -0
- data/app/assets/stylesheets/scrivito_editors/editors/text_editor.css +7 -0
- data/app/assets/stylesheets/scrivito_editors/icons.css.erb +229 -0
- data/app/assets/stylesheets/scrivito_editors/mediabrowser.css +1010 -0
- data/app/assets/stylesheets/scrivito_editors/placeholder.css +17 -0
- data/app/assets/stylesheets/scrivito_editors/widget_preview.css +38 -0
- data/app/controllers/scrivito_editors/mediabrowser_controller.rb +36 -0
- data/app/views/layouts/scrivito_editors/mediabrowser/inspector.html.erb +11 -0
- data/app/views/scrivito_editors/mediabrowser/_buttons.html.erb +16 -0
- data/app/views/scrivito_editors/mediabrowser/_header.html.erb +25 -0
- data/app/views/scrivito_editors/mediabrowser/modal.html.erb +12 -0
- data/app/views/scrivito_editors/obj/details.html +5 -0
- data/config/initializers/mediabrowser.rb +13 -0
- data/config/routes.rb +5 -0
- data/lib/scrivito_editors.rb +4 -0
- data/lib/scrivito_editors/engine.rb +7 -0
- data/lib/scrivito_editors/version.rb +3 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +23 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +4 -0
- data/spec/dummy/public/404.html +58 -0
- data/spec/dummy/public/422.html +58 -0
- data/spec/dummy/public/500.html +57 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/spec_helper.rb +13 -0
- data/vendor/assets/fonts/redactor-font.eot +0 -0
- data/vendor/assets/javascripts/jquery-ui-timepicker-addon.min.js +5 -0
- data/vendor/assets/javascripts/redactor.js +7869 -0
- data/vendor/assets/stylesheets/jquery-ui-timepicker-addon.min.css +5 -0
- data/vendor/assets/stylesheets/redactor.css.erb +968 -0
- metadata +240 -0
@@ -0,0 +1,132 @@
|
|
1
|
+
@MediabrowserUploader = do ->
|
2
|
+
dropZoneSelector: '.editing-mediabrowser-items'
|
3
|
+
dropOverCssClass: 'uploader-drag-over'
|
4
|
+
mimeTypeMapping:
|
5
|
+
'image/*': 'Image'
|
6
|
+
'video/*': 'Video'
|
7
|
+
|
8
|
+
_initializeBindings: ->
|
9
|
+
dropZone = @modal.find(@dropZoneSelector)
|
10
|
+
|
11
|
+
dropZone.on 'dragover', (event) =>
|
12
|
+
$(event.currentTarget).addClass(@dropOverCssClass)
|
13
|
+
event.preventDefault()
|
14
|
+
|
15
|
+
dropZone.on 'dragleave', (event) =>
|
16
|
+
$(event.currentTarget).removeClass(@dropOverCssClass)
|
17
|
+
event.preventDefault()
|
18
|
+
|
19
|
+
dropZone.on 'drop', (event) =>
|
20
|
+
$(event.currentTarget).removeClass(@dropOverCssClass)
|
21
|
+
@_onDrop(event)
|
22
|
+
event.preventDefault()
|
23
|
+
|
24
|
+
_objClassForMimeType: (mimeType) ->
|
25
|
+
for mime, objClass of @mimeTypeMapping
|
26
|
+
return objClass if mimeType.match(mime)
|
27
|
+
|
28
|
+
undefined
|
29
|
+
|
30
|
+
_processQueue: (queue, createdObjs, promise) ->
|
31
|
+
promise.then (data) =>
|
32
|
+
@onUploadSuccess(data)
|
33
|
+
|
34
|
+
file = queue.pop()
|
35
|
+
|
36
|
+
if file?
|
37
|
+
@_createResource(file).then (obj) =>
|
38
|
+
@_updateProgress(file, '100%')
|
39
|
+
createdObjs.push(obj)
|
40
|
+
.always =>
|
41
|
+
@_processQueue(queue, createdObjs, promise)
|
42
|
+
|
43
|
+
return promise
|
44
|
+
else
|
45
|
+
return promise.resolve(createdObjs)
|
46
|
+
|
47
|
+
_addProgressWrapper: () ->
|
48
|
+
itemsElement = $('.editing-mediabrowser-items').empty()
|
49
|
+
|
50
|
+
$('<div></div>')
|
51
|
+
.addClass('editing-mediabrowser-loading')
|
52
|
+
.appendTo itemsElement
|
53
|
+
|
54
|
+
$('<div></div>')
|
55
|
+
.addClass('editing-mediabrowser-progress-wrapper')
|
56
|
+
.appendTo itemsElement
|
57
|
+
|
58
|
+
_addProgress: (file) ->
|
59
|
+
progressBar = $('<div></div>')
|
60
|
+
.addClass('editing-mediabrowser-progress-bar')
|
61
|
+
.css('width', '10%')
|
62
|
+
|
63
|
+
progress = $('<div></div>')
|
64
|
+
.addClass('editing-mediabrowser-progress')
|
65
|
+
.html(progressBar)
|
66
|
+
|
67
|
+
fileName = $('<p></p>')
|
68
|
+
.html(file.name)
|
69
|
+
|
70
|
+
$('<div></div>')
|
71
|
+
.addClass('editing-mediabrowser-progress-file')
|
72
|
+
.append(fileName)
|
73
|
+
.append(progress)
|
74
|
+
.prependTo $('.editing-mediabrowser-progress-wrapper')
|
75
|
+
|
76
|
+
file['progressBar'] = progressBar
|
77
|
+
|
78
|
+
_updateProgress: (file, percent) ->
|
79
|
+
file.progressBar.css('width', percent)
|
80
|
+
|
81
|
+
_onDrop: (event) ->
|
82
|
+
dataTransfer = event.originalEvent.dataTransfer
|
83
|
+
|
84
|
+
unless dataTransfer?
|
85
|
+
return
|
86
|
+
|
87
|
+
files = dataTransfer.files
|
88
|
+
|
89
|
+
if files.length == 0
|
90
|
+
return
|
91
|
+
|
92
|
+
@onUploadStart(queue)
|
93
|
+
@_addProgressWrapper()
|
94
|
+
|
95
|
+
promise = $.Deferred()
|
96
|
+
|
97
|
+
queue = for file in files
|
98
|
+
@_addProgress(file)
|
99
|
+
file
|
100
|
+
|
101
|
+
@_processQueue(queue, [], promise)
|
102
|
+
|
103
|
+
promise
|
104
|
+
|
105
|
+
_randomResourceId: ->
|
106
|
+
hex = Math.floor(Math.random() * Math.pow(16, 8)).toString(16)
|
107
|
+
|
108
|
+
while (hex.length < 8)
|
109
|
+
hex = '0' + hex
|
110
|
+
|
111
|
+
hex
|
112
|
+
|
113
|
+
_createResource: (file) ->
|
114
|
+
objName = file.name.replace(/[^a-z0-9_.$\-]/ig, '-')
|
115
|
+
path = "_resources/#{@_randomResourceId()}/#{objName}"
|
116
|
+
|
117
|
+
scrivito.create_obj
|
118
|
+
blob: file
|
119
|
+
_path: path
|
120
|
+
_obj_class: @_objClassForMimeType(file.type)
|
121
|
+
|
122
|
+
init: (@modal) ->
|
123
|
+
@_initializeBindings()
|
124
|
+
|
125
|
+
# Hook for 3rd parties when the upload starts.
|
126
|
+
onUploadStart: (files) ->
|
127
|
+
|
128
|
+
# Hook for 3rd parties when the upload fails.
|
129
|
+
onUploadFailure: (error) ->
|
130
|
+
|
131
|
+
# Hook for 3rd parties when the upload was successful.
|
132
|
+
onUploadSuccess: (objs) ->
|
@@ -0,0 +1,18 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// compiled file.
|
9
|
+
//
|
10
|
+
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
|
11
|
+
// about supported directives.
|
12
|
+
//
|
13
|
+
//= require jquery.ui.sortable
|
14
|
+
//= require jquery.ui.datepicker
|
15
|
+
//= require jquery.ui.slider
|
16
|
+
//= require jquery-ui-timepicker-addon.min
|
17
|
+
//= require redactor
|
18
|
+
//= require_tree .
|
@@ -0,0 +1,50 @@
|
|
1
|
+
$ ->
|
2
|
+
# Define editor behavior for date attributes.
|
3
|
+
|
4
|
+
scrivito.on 'editing', ->
|
5
|
+
template = ->
|
6
|
+
$('<input />')
|
7
|
+
.attr('type', 'text')
|
8
|
+
|
9
|
+
onKeyup = (event) ->
|
10
|
+
key = event.keyCode || event.which
|
11
|
+
|
12
|
+
switch key
|
13
|
+
when 27 # Esc
|
14
|
+
# Prevent the property view to close when the ESC key is pressed.
|
15
|
+
event.stopPropagation()
|
16
|
+
|
17
|
+
save = (dateTimeText) ->
|
18
|
+
element = $(this)
|
19
|
+
cmsField = element.data('cmsField')
|
20
|
+
|
21
|
+
if dateTimeText? && dateTimeText.length > 0
|
22
|
+
dateTimeText = new Date(dateTimeText)
|
23
|
+
|
24
|
+
cmsField.scrivito('save', dateTimeText)
|
25
|
+
.done ->
|
26
|
+
cmsField.trigger('scrivito_reload')
|
27
|
+
|
28
|
+
$('body').on 'click', '[data-scrivito-field-type="date"]:not(.hasDatepicker):not([data-editor]), [data-editor="date"]', (event) ->
|
29
|
+
event.preventDefault()
|
30
|
+
|
31
|
+
cmsField = $(this)
|
32
|
+
content = cmsField.html().trim()
|
33
|
+
dateFormat = cmsField.attr('data-date-format') || 'yy-mm-dd'
|
34
|
+
timeFormat = cmsField.attr('data-time-format') || 'HH:mm:ss'
|
35
|
+
|
36
|
+
$('body').keyup(onKeyup)
|
37
|
+
|
38
|
+
template()
|
39
|
+
.data('cmsField', cmsField)
|
40
|
+
.insertAfter(cmsField)
|
41
|
+
.val(content)
|
42
|
+
.keyup(onKeyup)
|
43
|
+
.datetimepicker(
|
44
|
+
dateFormat: dateFormat
|
45
|
+
timeFormat: timeFormat
|
46
|
+
onClose: save
|
47
|
+
)
|
48
|
+
.focus()
|
49
|
+
|
50
|
+
cmsField.hide()
|
@@ -0,0 +1,36 @@
|
|
1
|
+
$ ->
|
2
|
+
# Define editor behavior for enum attributes.
|
3
|
+
|
4
|
+
scrivito.on 'editing', ->
|
5
|
+
template = (values) ->
|
6
|
+
element = $('<select></select>')
|
7
|
+
.addClass('form-control')
|
8
|
+
|
9
|
+
$.each values, (index, value) ->
|
10
|
+
$('<option></option>')
|
11
|
+
.attr('value', value)
|
12
|
+
.text(value)
|
13
|
+
.appendTo(element)
|
14
|
+
|
15
|
+
element
|
16
|
+
|
17
|
+
save = (event) ->
|
18
|
+
element = $(event.currentTarget)
|
19
|
+
cmsField = element.data('cmsField')
|
20
|
+
content = element.val()
|
21
|
+
cmsField.scrivito('save', content).done ->
|
22
|
+
cmsField.trigger('scrivito_reload')
|
23
|
+
|
24
|
+
$(document).on 'click', '[data-scrivito-field-type="enum"]:not([data-editor]), [data-editor="enum"]', (event) ->
|
25
|
+
cmsField = $(event.currentTarget)
|
26
|
+
selected = cmsField.scrivito('content')
|
27
|
+
values = cmsField.data('values')
|
28
|
+
|
29
|
+
template(values)
|
30
|
+
.data('cmsField', cmsField)
|
31
|
+
.val(selected)
|
32
|
+
.insertAfter(cmsField)
|
33
|
+
.focusout(save)
|
34
|
+
.focus()
|
35
|
+
|
36
|
+
cmsField.hide()
|
@@ -0,0 +1,140 @@
|
|
1
|
+
$ ->
|
2
|
+
# Configuration and behavior of Redactor html editor. The editor is used for all html CMS
|
3
|
+
# attributes and provides autosave, undo and redo functionality on top of the default Redactor
|
4
|
+
# settings.
|
5
|
+
|
6
|
+
# Stores the id of the last triggered timeout for later reference.
|
7
|
+
timeoutID = undefined
|
8
|
+
|
9
|
+
# Milliseconds after which to save the content automatically.
|
10
|
+
autosaveInterval = 3000
|
11
|
+
|
12
|
+
# Stores the last saved content written to the CMS to allow comparison with editor content.
|
13
|
+
savedContent = undefined
|
14
|
+
|
15
|
+
# Stores the content before the editor is opened and changes occur.
|
16
|
+
originalContent = undefined
|
17
|
+
|
18
|
+
# Stores redactor options, custom settings and configures callbacks.
|
19
|
+
redactorOptions = ->
|
20
|
+
return {} =
|
21
|
+
# This option allows you to add your own buttons with callback to the toolbar.
|
22
|
+
# http://imperavi.com/redactor/docs/settings/#set-buttonsCustom
|
23
|
+
buttonsCustom:
|
24
|
+
undoButton:
|
25
|
+
title: 'Undo'
|
26
|
+
callback: undoAction
|
27
|
+
redoButton:
|
28
|
+
title: 'Redo'
|
29
|
+
callback: redoAction
|
30
|
+
|
31
|
+
# This setting defines the array of toolbar buttons.
|
32
|
+
# http://imperavi.com/redactor/docs/settings/#set-buttons
|
33
|
+
buttons: ['undoButton', 'redoButton',
|
34
|
+
'|', 'formatting',
|
35
|
+
'|', 'bold', 'italic', 'deleted', 'underline',
|
36
|
+
'|', 'unorderedlist', 'orderedlist',
|
37
|
+
'|', 'table', 'link',
|
38
|
+
'|', 'html'
|
39
|
+
]
|
40
|
+
|
41
|
+
# This option allows you to set whether Redactor gets cursor focus on load or not.
|
42
|
+
# http://imperavi.com/redactor/docs/settings/#set-focus
|
43
|
+
focus: true
|
44
|
+
|
45
|
+
# With this option turned on, Redactor will automatically replace divs to paragraphs.
|
46
|
+
# http://imperavi.com/redactor/docs/settings/#set-convertDivs
|
47
|
+
convertDivs: false
|
48
|
+
|
49
|
+
# This callback is triggered after Redactor is launched.
|
50
|
+
# http://imperavi.com/redactor/docs/callbacks/#callback-initCallback
|
51
|
+
initCallback: ->
|
52
|
+
originalContent = @get()
|
53
|
+
|
54
|
+
# This callback fires every time when content changes in Redactor.
|
55
|
+
# http://imperavi.com/redactor/docs/callbacks/#callback-changeCallback
|
56
|
+
changeCallback: ->
|
57
|
+
autosaveAction(@)
|
58
|
+
|
59
|
+
# This callback is triggered when Redactor loses focus.
|
60
|
+
# http://imperavi.com/redactor/docs/callbacks/#callback-blurCallback
|
61
|
+
blurCallback: ->
|
62
|
+
saveContents(@).done =>
|
63
|
+
@.destroy()
|
64
|
+
reload(@)
|
65
|
+
|
66
|
+
# This callback is triggered when a key is released.
|
67
|
+
# http://imperavi.com/redactor/docs/callbacks/#callback-keyupCallback
|
68
|
+
keyupCallback: (event) ->
|
69
|
+
event.stopPropagation()
|
70
|
+
key = event.keyCode || event.which
|
71
|
+
|
72
|
+
if key == 27
|
73
|
+
cancelEditing(@)
|
74
|
+
else
|
75
|
+
autosaveAction(@)
|
76
|
+
|
77
|
+
# This callback allows to get pasted code after clean on paste.
|
78
|
+
# http://imperavi.com/redactor/docs/callbacks/#callback-pasteAfterCallback
|
79
|
+
pasteAfterCallback: (html) ->
|
80
|
+
autosaveAction(@)
|
81
|
+
html
|
82
|
+
|
83
|
+
# Registers a timeout to save the editor content after a certain interval. The timeout gets reset
|
84
|
+
# on every change.
|
85
|
+
autosaveAction = (editor) ->
|
86
|
+
if timeoutID
|
87
|
+
clearTimeout(timeoutID)
|
88
|
+
|
89
|
+
timeoutID = setTimeout ( ->
|
90
|
+
saveContents(editor)
|
91
|
+
), autosaveInterval
|
92
|
+
|
93
|
+
undoAction = ->
|
94
|
+
@execCommand('undo')
|
95
|
+
|
96
|
+
redoAction = ->
|
97
|
+
@execCommand('redo')
|
98
|
+
|
99
|
+
# Saves the current editor content to the CMS if it has changed.
|
100
|
+
saveContents = (editor) ->
|
101
|
+
content = editor.get()
|
102
|
+
|
103
|
+
if savedContent != content
|
104
|
+
cmsField = editor.$element
|
105
|
+
cmsField.scrivito('save', content).done ->
|
106
|
+
savedContent = content
|
107
|
+
|
108
|
+
else
|
109
|
+
$.Deferred().resolve()
|
110
|
+
|
111
|
+
reload = (editor) ->
|
112
|
+
cmsField = editor.$element
|
113
|
+
cmsField.trigger('scrivito_reload')
|
114
|
+
|
115
|
+
# Restores the original content before the editor was opened, also saves it back to the CMS
|
116
|
+
# because autosave could have overwritten the content and closes the editor.
|
117
|
+
cancelEditing = (editor) ->
|
118
|
+
editor.set(originalContent)
|
119
|
+
saveContents(editor).done ->
|
120
|
+
reload(editor)
|
121
|
+
editor.destroy()
|
122
|
+
|
123
|
+
# Registers Redactor for all CMS html attributes found in the given scope of the DOM element.
|
124
|
+
addOnclickRedactorHandlers = (domElement) ->
|
125
|
+
domElement.on 'click', '[data-scrivito-field-type="html"]:not([data-editor]), [data-editor="html"]', (event) ->
|
126
|
+
event.preventDefault()
|
127
|
+
cmsField = $(@)
|
128
|
+
|
129
|
+
unless cmsField.hasClass('redactor_editor')
|
130
|
+
cmsField.html(cmsField.scrivito('content') || '')
|
131
|
+
cmsField.redactor(redactorOptions())
|
132
|
+
cmsField.redactor('focus')
|
133
|
+
|
134
|
+
# Registers all handlers when inplace editing is activated.
|
135
|
+
scrivito.on 'editing', ->
|
136
|
+
addOnclickRedactorHandlers($('body'))
|
137
|
+
|
138
|
+
# Registers all handlers when content has changed.
|
139
|
+
scrivito.on 'new_content', (domElement) ->
|
140
|
+
addOnclickRedactorHandlers($(domElement))
|
@@ -0,0 +1,176 @@
|
|
1
|
+
$ ->
|
2
|
+
# An editor for CMS linklist attributes.
|
3
|
+
|
4
|
+
# Creates the DOM for one link element of the linklist and substitutes the
|
5
|
+
# title and url attribute.
|
6
|
+
template = (attributes) ->
|
7
|
+
attributes ||= {}
|
8
|
+
|
9
|
+
title = attributes['title'] || ''
|
10
|
+
url = attributes['url'] || ''
|
11
|
+
|
12
|
+
$("<input type=\"text\" name=\"title\" value=\"#{title}\" placeholder=\"Title\" />
|
13
|
+
<input type=\"text\" name=\"url\" value=\"#{url}\" placeholder=\"Url\" class=\"editing-url\" />
|
14
|
+
<div class=\"actions\">
|
15
|
+
<a href=\"#\" class=\"editing-button mediabrowser-open editing-green\">
|
16
|
+
<i class=\"editing-icon editing-icon-search\" />
|
17
|
+
</a>
|
18
|
+
<a href=\"#\" class=\"editing-button editing-red delete\">
|
19
|
+
<i class=\"editing-icon editing-icon-trash\" />
|
20
|
+
</a>
|
21
|
+
</div>")
|
22
|
+
|
23
|
+
mediabrowserButtonTemplate = ->
|
24
|
+
icon = $('<i></i>')
|
25
|
+
.addClass('editing-icon')
|
26
|
+
.addClass('editing-icon-plus')
|
27
|
+
|
28
|
+
button = $('<button></button>')
|
29
|
+
.addClass('editing-button')
|
30
|
+
.addClass('editing-green')
|
31
|
+
.addClass('add-link')
|
32
|
+
.html(icon)
|
33
|
+
|
34
|
+
button
|
35
|
+
|
36
|
+
# Returns the closest linklist DOM element.
|
37
|
+
getCmsField = (element) ->
|
38
|
+
element.closest('[data-scrivito-field-type=linklist]')
|
39
|
+
|
40
|
+
# Saves the entire linklist to the CMS and stores the last successfully saved value.
|
41
|
+
save = (cmsField) ->
|
42
|
+
value = getAttributes(cmsField)
|
43
|
+
lastSaved = getLastSaved(cmsField)
|
44
|
+
|
45
|
+
unless JSON.stringify(value) == JSON.stringify(lastSaved)
|
46
|
+
cmsField.scrivito('save', value).done ->
|
47
|
+
storeLastSaved(cmsField, value)
|
48
|
+
|
49
|
+
# Run when clicking the '...' button inside a li.
|
50
|
+
onOpenMediabrowser = (event) ->
|
51
|
+
event.preventDefault()
|
52
|
+
|
53
|
+
linkItem = $(event.currentTarget).closest('li')
|
54
|
+
cmsField = getCmsField(linkItem)
|
55
|
+
filters = cmsField.data('filters') || cmsField.data('filter')
|
56
|
+
|
57
|
+
Mediabrowser.open
|
58
|
+
selection: []
|
59
|
+
filters: filters
|
60
|
+
onSave: (selection) =>
|
61
|
+
onMediabrowserSaveLinkItem(selection, linkItem)
|
62
|
+
|
63
|
+
# Media browser callback for saving a single link.
|
64
|
+
onMediabrowserSaveLinkItem = (selection, linkItem) ->
|
65
|
+
url = buildUrl(selection[0])
|
66
|
+
linkItem.find('[name=url]').val(url)
|
67
|
+
|
68
|
+
# trigger save after inserting the value
|
69
|
+
cmsField = getCmsField(linkItem)
|
70
|
+
save(cmsField)
|
71
|
+
|
72
|
+
true
|
73
|
+
|
74
|
+
# Transforms an obj id into an url that can be parsed by Scrivito
|
75
|
+
# to establish an internal link.
|
76
|
+
buildUrl = (id) ->
|
77
|
+
"/#{id}"
|
78
|
+
|
79
|
+
# Collects all link attributes for a given linklist.
|
80
|
+
getAttributes = (cmsField) ->
|
81
|
+
items = $(cmsField).find('li')
|
82
|
+
|
83
|
+
attributes =
|
84
|
+
for item in items
|
85
|
+
item = $(item)
|
86
|
+
title = item.find('[name=title]').val()
|
87
|
+
url = item.find('[name=url]').val()
|
88
|
+
|
89
|
+
# Make sure the url is not empty.
|
90
|
+
if !isEmpty(url)
|
91
|
+
'title': title
|
92
|
+
'url': url
|
93
|
+
|
94
|
+
# Remove empty array elements.
|
95
|
+
removeEmptyElements(attributes)
|
96
|
+
|
97
|
+
isEmpty = (value) ->
|
98
|
+
!value
|
99
|
+
|
100
|
+
removeEmptyElements = (array) ->
|
101
|
+
$.grep(array, (n) -> n)
|
102
|
+
|
103
|
+
# Adds a new link to the linklist.
|
104
|
+
addLink = (event) ->
|
105
|
+
event.preventDefault()
|
106
|
+
|
107
|
+
cmsField = getCmsField($(event.currentTarget))
|
108
|
+
content = $('<li>').html(template())
|
109
|
+
|
110
|
+
cmsField.find('ul').append(content)
|
111
|
+
|
112
|
+
# Removes a link from the linklist.
|
113
|
+
removeLink = (event) ->
|
114
|
+
event.preventDefault()
|
115
|
+
|
116
|
+
target = $(event.currentTarget)
|
117
|
+
cmsField = getCmsField(target)
|
118
|
+
|
119
|
+
target.closest('li').remove()
|
120
|
+
save(cmsField)
|
121
|
+
|
122
|
+
# Turns the server side generated linklist data into the linklist editor using a template.
|
123
|
+
transformLinks = (cmsFields) ->
|
124
|
+
cmsFields.append(mediabrowserButtonTemplate)
|
125
|
+
|
126
|
+
items = cmsFields.find('li')
|
127
|
+
|
128
|
+
for item in items
|
129
|
+
item = $(item)
|
130
|
+
|
131
|
+
content = template
|
132
|
+
title: item.data('title')
|
133
|
+
url: item.data('url')
|
134
|
+
|
135
|
+
item.html(content)
|
136
|
+
|
137
|
+
# Returns the last saved value.
|
138
|
+
getLastSaved = (cmsField) ->
|
139
|
+
cmsField.data('last-saved')
|
140
|
+
|
141
|
+
# Stores a given value as last saved.
|
142
|
+
storeLastSaved = (cmsField, value) ->
|
143
|
+
$(cmsField).data('last-saved', value)
|
144
|
+
|
145
|
+
# Automatically save when focus is lost.
|
146
|
+
onBlur = (event) ->
|
147
|
+
cmsField = getCmsField($(event.currentTarget))
|
148
|
+
|
149
|
+
save(cmsField)
|
150
|
+
|
151
|
+
initialize = (root) ->
|
152
|
+
linklistElements = $(root).find('[data-scrivito-field-type="linklist"]:not([data-editor]), [data-editor="linklist"]')
|
153
|
+
|
154
|
+
if linklistElements.length
|
155
|
+
transformLinks(linklistElements)
|
156
|
+
|
157
|
+
for linklistElement in linklistElements
|
158
|
+
storeLastSaved(linklistElement, getAttributes(linklistElement))
|
159
|
+
|
160
|
+
linklistElements.on 'blur', 'li input', onBlur
|
161
|
+
linklistElements.on 'click', 'li a.delete', removeLink
|
162
|
+
linklistElements.on 'click', 'button.add-link', addLink
|
163
|
+
linklistElements.on 'click', 'a.mediabrowser-open', onOpenMediabrowser
|
164
|
+
|
165
|
+
linklistElements.find('ul').sortable
|
166
|
+
update: (event) ->
|
167
|
+
cmsField = getCmsField($(event.target))
|
168
|
+
|
169
|
+
save(cmsField)
|
170
|
+
|
171
|
+
# Initialize linklist editor and setup event callbacks.
|
172
|
+
scrivito.on 'new_content', (root) ->
|
173
|
+
initialize(root)
|
174
|
+
|
175
|
+
scrivito.on 'editing', ->
|
176
|
+
initialize(document)
|