formagic 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/CONTRIBUTING.md +24 -0
- data/Gemfile +3 -0
- data/LICENSE.md +21 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/app/assets/images/datedropper/done.png +0 -0
- data/app/assets/images/datedropper/done.svg +1 -0
- data/app/assets/images/datedropper/next.png +0 -0
- data/app/assets/images/datedropper/next.svg +1 -0
- data/app/assets/images/datedropper/prev.png +0 -0
- data/app/assets/images/datedropper/prev.svg +1 -0
- data/app/assets/javascripts/formagic/form.coffee +229 -0
- data/app/assets/javascripts/formagic/group.coffee +28 -0
- data/app/assets/javascripts/formagic/inputs/checkbox.coffee +83 -0
- data/app/assets/javascripts/formagic/inputs/color.coffee +55 -0
- data/app/assets/javascripts/formagic/inputs/date.coffee +69 -0
- data/app/assets/javascripts/formagic/inputs/datetime.coffee +130 -0
- data/app/assets/javascripts/formagic/inputs/document.coffee +0 -0
- data/app/assets/javascripts/formagic/inputs/documents.coffee +173 -0
- data/app/assets/javascripts/formagic/inputs/documents_reorder.coffee +67 -0
- data/app/assets/javascripts/formagic/inputs/file.coffee +114 -0
- data/app/assets/javascripts/formagic/inputs/hidden.coffee +57 -0
- data/app/assets/javascripts/formagic/inputs/html.coffee +81 -0
- data/app/assets/javascripts/formagic/inputs/image.coffee +28 -0
- data/app/assets/javascripts/formagic/inputs/list.coffee +154 -0
- data/app/assets/javascripts/formagic/inputs/list_reorder.coffee +39 -0
- data/app/assets/javascripts/formagic/inputs/list_typeahead.coffee +55 -0
- data/app/assets/javascripts/formagic/inputs/markdown.coffee +93 -0
- data/app/assets/javascripts/formagic/inputs/password.coffee +32 -0
- data/app/assets/javascripts/formagic/inputs/redactor.coffee +53 -0
- data/app/assets/javascripts/formagic/inputs/redactor_character.coffee +75 -0
- data/app/assets/javascripts/formagic/inputs/redactor_images.coffee +166 -0
- data/app/assets/javascripts/formagic/inputs/select.coffee +84 -0
- data/app/assets/javascripts/formagic/inputs/select2.coffee +33 -0
- data/app/assets/javascripts/formagic/inputs/string.coffee +160 -0
- data/app/assets/javascripts/formagic/inputs/text.coffee +43 -0
- data/app/assets/javascripts/formagic/inputs/time.coffee +0 -0
- data/app/assets/javascripts/formagic.coffee +22 -0
- data/app/assets/javascripts/vendor/ace.js +18280 -0
- data/app/assets/javascripts/vendor/datedropper.js +1005 -0
- data/app/assets/javascripts/vendor/jquery.scrollparent.js +14 -0
- data/app/assets/javascripts/vendor/jquery.textarea_autosize.js +55 -0
- data/app/assets/javascripts/vendor/jquery.typeahead.js +1782 -0
- data/app/assets/javascripts/vendor/marked.js +1272 -0
- data/app/assets/javascripts/vendor/mode-html.js +2436 -0
- data/app/assets/javascripts/vendor/mode-markdown.js +2820 -0
- data/app/assets/javascripts/vendor/moment.js +3083 -0
- data/app/assets/javascripts/vendor/redactor.fixedtoolbar.js +107 -0
- data/app/assets/javascripts/vendor/select2.js +5274 -0
- data/app/assets/stylesheets/formagic/checkbox.scss +8 -0
- data/app/assets/stylesheets/formagic/color.scss +12 -0
- data/app/assets/stylesheets/formagic/date.scss +37 -0
- data/app/assets/stylesheets/formagic/file.scss +29 -0
- data/app/assets/stylesheets/formagic/form.scss +36 -0
- data/app/assets/stylesheets/formagic/group.scss +22 -0
- data/app/assets/stylesheets/formagic/image.scss +19 -0
- data/app/assets/stylesheets/formagic/list.scss +39 -0
- data/app/assets/stylesheets/formagic/nested-form.scss +23 -0
- data/app/assets/stylesheets/formagic/redactor.scss +41 -0
- data/app/assets/stylesheets/formagic/select.scss +5 -0
- data/app/assets/stylesheets/formagic/select2.scss +95 -0
- data/app/assets/stylesheets/formagic/string.scss +14 -0
- data/app/assets/stylesheets/formagic/switch.scss +86 -0
- data/app/assets/stylesheets/formagic/text.scss +9 -0
- data/app/assets/stylesheets/formagic.scss +15 -0
- data/app/assets/stylesheets/vendor/datedropper.scss +523 -0
- data/app/assets/stylesheets/vendor/select2.scss +258 -0
- data/formagic.gemspec +30 -0
- data/lib/formagic/engine.rb +5 -0
- data/lib/formagic/version.rb +3 -0
- data/lib/formagic.rb +5 -0
- metadata +146 -0
@@ -0,0 +1,154 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
# Author: Alexander Kravets <alex@slatestudio.com>,
|
3
|
+
# Slate Studio (http://www.slatestudio.com)
|
4
|
+
#
|
5
|
+
# Coding Guide:
|
6
|
+
# https://github.com/thoughtbot/guides/tree/master/style/coffeescript
|
7
|
+
# -----------------------------------------------------------------------------
|
8
|
+
|
9
|
+
# -----------------------------------------------------------------------------
|
10
|
+
# INPUT LIST
|
11
|
+
# -----------------------------------------------------------------------------
|
12
|
+
# Allows to create/delete/reorder list items connected to dynamic or static
|
13
|
+
# collection. Value should be an array of objects.
|
14
|
+
#
|
15
|
+
# All items should be unique for now.
|
16
|
+
#
|
17
|
+
# Dependencies:
|
18
|
+
#= require ./list_reorder
|
19
|
+
#= require ./list_typeahead
|
20
|
+
#
|
21
|
+
# -----------------------------------------------------------------------------
|
22
|
+
|
23
|
+
class @InputList extends InputString
|
24
|
+
|
25
|
+
# PRIVATE ===============================================
|
26
|
+
|
27
|
+
_add_input: ->
|
28
|
+
# @TODO: check if we can use @config.name instead of @config.target
|
29
|
+
# @config.target ?= @config.klassName
|
30
|
+
|
31
|
+
# hidden input that stores ids, we use __LIST__ prefix to identify
|
32
|
+
# ARRAY input type and process it's value while form submission.
|
33
|
+
name = if @config.namePrefix then "#{ @config.namePrefix }[__LIST__#{ @config.target }]" else "[__LIST__#{ @config.target }]"
|
34
|
+
|
35
|
+
@$input =$ "<input type='hidden' name='#{ name }' value='' />"
|
36
|
+
@$el.append @$input
|
37
|
+
|
38
|
+
# list holder for items
|
39
|
+
@reorderContainerClass = @config.klassName
|
40
|
+
@$items =$ "<ul class='#{ @reorderContainerClass }'></ul>"
|
41
|
+
@$el.append @$items
|
42
|
+
|
43
|
+
# other options might be added here (static collection)
|
44
|
+
|
45
|
+
@_create_typeahead_el(@config.typeahead.placeholder)
|
46
|
+
|
47
|
+
@_render_items()
|
48
|
+
@_update_input_value()
|
49
|
+
|
50
|
+
|
51
|
+
_update_input_value: ->
|
52
|
+
ids = []
|
53
|
+
@$items.children('li').each (i, el) -> ids.push $(el).attr('data-id')
|
54
|
+
|
55
|
+
# @TODO: we need a better separator here, comma is too generic
|
56
|
+
# it's used cause most cases list of IDs concidered to be here,
|
57
|
+
# we might make this a @config setting.
|
58
|
+
value = ids.join(',')
|
59
|
+
|
60
|
+
@$input.val(value)
|
61
|
+
@$input.trigger('change')
|
62
|
+
|
63
|
+
|
64
|
+
_remove_item: ($el) ->
|
65
|
+
id = $el.attr('data-id')
|
66
|
+
delete @objects[id]
|
67
|
+
|
68
|
+
$el.parent().remove()
|
69
|
+
@_update_input_value()
|
70
|
+
|
71
|
+
|
72
|
+
_ordered_ids: ->
|
73
|
+
ids = @$input.val().split(',')
|
74
|
+
if ids[0] == '' then ids = []
|
75
|
+
return ids
|
76
|
+
|
77
|
+
|
78
|
+
_render_items: ->
|
79
|
+
@$items.html('')
|
80
|
+
@objects = {}
|
81
|
+
|
82
|
+
for o in @value
|
83
|
+
@_render_item(o)
|
84
|
+
|
85
|
+
|
86
|
+
_render_item: (o) ->
|
87
|
+
@_add_object(o)
|
88
|
+
|
89
|
+
if @config.itemTemplate
|
90
|
+
item = @config.itemTemplate(o)
|
91
|
+
else
|
92
|
+
item = o[@config.titleFieldName]
|
93
|
+
|
94
|
+
listItem =$ """<li data-id='#{ o._id }'>
|
95
|
+
<span class='icon-reorder' data-container-class='#{ @reorderContainerClass }'></span>
|
96
|
+
#{ item }
|
97
|
+
<a href='#' class='action_remove'>Remove</a>
|
98
|
+
</li>"""
|
99
|
+
@$items.append(listItem)
|
100
|
+
@_update_input_value()
|
101
|
+
|
102
|
+
|
103
|
+
_add_object: (o) ->
|
104
|
+
@_normalize_object(o)
|
105
|
+
@objects[o._id] = o
|
106
|
+
|
107
|
+
|
108
|
+
_normalize_object: (o) ->
|
109
|
+
o._id ?= o.id
|
110
|
+
if ! o._id then console.log("::: list item is missing an 'id' or '_id' :::")
|
111
|
+
|
112
|
+
|
113
|
+
# PUBLIC ================================================
|
114
|
+
|
115
|
+
initialize: ->
|
116
|
+
@config.beforeInitialize?(this)
|
117
|
+
|
118
|
+
# typeahead
|
119
|
+
@_bind_typeahead()
|
120
|
+
|
121
|
+
# remove
|
122
|
+
@$items.on 'click', '.action_remove', (e) =>
|
123
|
+
e.preventDefault()
|
124
|
+
if confirm('Are you sure?') then @_remove_item($(e.currentTarget))
|
125
|
+
|
126
|
+
@_bind_reorder()
|
127
|
+
|
128
|
+
@config.onInitialize?(this)
|
129
|
+
|
130
|
+
|
131
|
+
updateValue: (@value) ->
|
132
|
+
@_render_items()
|
133
|
+
|
134
|
+
|
135
|
+
hash: (hash={}) ->
|
136
|
+
hash[@config.target] = @$input.val()
|
137
|
+
ordered_objects = []
|
138
|
+
|
139
|
+
for id in @_ordered_ids()
|
140
|
+
ordered_objects.push(@objects[id])
|
141
|
+
|
142
|
+
hash[@config.klassName] = ordered_objects
|
143
|
+
return hash
|
144
|
+
|
145
|
+
|
146
|
+
include(InputList, inputListReorder)
|
147
|
+
include(InputList, inputListTypeahead)
|
148
|
+
|
149
|
+
|
150
|
+
chr.formInputs['list'] = InputList
|
151
|
+
|
152
|
+
|
153
|
+
|
154
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
# Author: Alexander Kravets <alex@slatestudio.com>,
|
3
|
+
# Slate Studio (http://www.slatestudio.com)
|
4
|
+
#
|
5
|
+
# Coding Guide:
|
6
|
+
# https://github.com/thoughtbot/guides/tree/master/style/coffeescript
|
7
|
+
# -----------------------------------------------------------------------------
|
8
|
+
|
9
|
+
# -----------------------------------------------------------------------------
|
10
|
+
# INPUT LIST REORDER
|
11
|
+
# -----------------------------------------------------------------------------
|
12
|
+
|
13
|
+
@inputListReorder =
|
14
|
+
|
15
|
+
# PRIVATE ===============================================
|
16
|
+
|
17
|
+
_bind_reorder: ->
|
18
|
+
list = @$items.get(0)
|
19
|
+
new Slip(list)
|
20
|
+
|
21
|
+
list.addEventListener 'slip:beforeswipe', (e) -> e.preventDefault()
|
22
|
+
|
23
|
+
list.addEventListener 'slip:beforewait', ((e) ->
|
24
|
+
if $(e.target).hasClass("icon-reorder") then e.preventDefault()
|
25
|
+
), false
|
26
|
+
|
27
|
+
list.addEventListener 'slip:beforereorder', ((e) ->
|
28
|
+
if not $(e.target).hasClass("icon-reorder") then e.preventDefault()
|
29
|
+
), false
|
30
|
+
|
31
|
+
list.addEventListener 'slip:reorder', ((e) =>
|
32
|
+
e.target.parentNode.insertBefore(e.target, e.detail.insertBefore)
|
33
|
+
@_update_input_value()
|
34
|
+
return false
|
35
|
+
), false
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
# Author: Alexander Kravets <alex@slatestudio.com>,
|
3
|
+
# Slate Studio (http://www.slatestudio.com)
|
4
|
+
#
|
5
|
+
# Coding Guide:
|
6
|
+
# https://github.com/thoughtbot/guides/tree/master/style/coffeescript
|
7
|
+
# -----------------------------------------------------------------------------
|
8
|
+
|
9
|
+
# -----------------------------------------------------------------------------
|
10
|
+
# INPUT LIST TYPEAHEAD
|
11
|
+
# -----------------------------------------------------------------------------
|
12
|
+
|
13
|
+
@inputListTypeahead =
|
14
|
+
|
15
|
+
# PRIVATE ===============================================
|
16
|
+
|
17
|
+
_create_typeahead_el: (placeholder) ->
|
18
|
+
# typeahead input for adding new items
|
19
|
+
@typeaheadInput =$ "<input type='text' placeholder='#{ placeholder }' />"
|
20
|
+
@$el.append @typeaheadInput
|
21
|
+
|
22
|
+
|
23
|
+
_bind_typeahead: ->
|
24
|
+
limit = @config.typeahead.limit || 5
|
25
|
+
dataSource = new Bloodhound
|
26
|
+
datumTokenizer: Bloodhound.tokenizers.obj.whitespace(@config.titleFieldName)
|
27
|
+
queryTokenizer: Bloodhound.tokenizers.whitespace
|
28
|
+
remote:
|
29
|
+
url: @config.typeahead.url
|
30
|
+
# exclude objects that are already in the list
|
31
|
+
filter: (parsedResponse) =>
|
32
|
+
data = []
|
33
|
+
for o in parsedResponse
|
34
|
+
@_normalize_object(o) ; if ! @objects[o._id] then data.push(o)
|
35
|
+
return data
|
36
|
+
limit: limit
|
37
|
+
|
38
|
+
dataSource.initialize()
|
39
|
+
|
40
|
+
@typeaheadInput.typeahead({
|
41
|
+
hint: false
|
42
|
+
highlight: true
|
43
|
+
}, {
|
44
|
+
name: @config.klassName
|
45
|
+
displayKey: @config.titleFieldName
|
46
|
+
source: dataSource.ttAdapter()
|
47
|
+
})
|
48
|
+
|
49
|
+
@typeaheadInput.on 'typeahead:selected', (e, object, dataset) =>
|
50
|
+
@_render_item(object)
|
51
|
+
@typeaheadInput.typeahead('val', '')
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
# Author: Alexander Kravets <alex@slatestudio.com>,
|
3
|
+
# Slate Studio (http://www.slatestudio.com)
|
4
|
+
#
|
5
|
+
# Coding Guide:
|
6
|
+
# https://github.com/thoughtbot/guides/tree/master/style/coffeescript
|
7
|
+
# -----------------------------------------------------------------------------
|
8
|
+
|
9
|
+
# -----------------------------------------------------------------------------
|
10
|
+
# INPUT MARKDOWN
|
11
|
+
# -----------------------------------------------------------------------------
|
12
|
+
# Markdown input supports syntax highlighting and optional compilation to html.
|
13
|
+
#
|
14
|
+
# Config options:
|
15
|
+
# label - Input label
|
16
|
+
# aceOptions - Custom options for overriding default ones
|
17
|
+
# htmlFieldName - Input name for generated HTML content
|
18
|
+
#
|
19
|
+
# Input config example:
|
20
|
+
# body_md: { type: 'markdown', label: 'Article', htmlFieldName: 'body_html' }
|
21
|
+
#
|
22
|
+
# Dependencies:
|
23
|
+
#= require vendor/marked
|
24
|
+
#= require vendor/ace
|
25
|
+
#= require vendor/mode-markdown
|
26
|
+
#
|
27
|
+
# -----------------------------------------------------------------------------
|
28
|
+
|
29
|
+
class @InputMarkdown extends InputString
|
30
|
+
|
31
|
+
# PRIVATE ===============================================
|
32
|
+
|
33
|
+
_add_input: ->
|
34
|
+
if @config.htmlFieldName
|
35
|
+
@$inputHtml =$ "<input type='hidden' name='[#{ @config.htmlFieldName }]' />"
|
36
|
+
@$el.append @$inputHtml
|
37
|
+
|
38
|
+
@$input =$ "<input type='hidden' name='#{ @name }' value='#{ @_safe_value() }' />"
|
39
|
+
@$el.append @$input
|
40
|
+
|
41
|
+
@$editor =$ "<div></div>"
|
42
|
+
@$el.append @$editor
|
43
|
+
|
44
|
+
|
45
|
+
_update_inputs: ->
|
46
|
+
md_source = @session.getValue()
|
47
|
+
@$input.val(md_source)
|
48
|
+
@$input.trigger('change')
|
49
|
+
|
50
|
+
if @$inputHtml
|
51
|
+
html = marked(md_source)
|
52
|
+
@$inputHtml.val(html)
|
53
|
+
@$inputHtml.trigger('change')
|
54
|
+
|
55
|
+
|
56
|
+
# PUBLIC ================================================
|
57
|
+
|
58
|
+
initialize: ->
|
59
|
+
@config.beforeInitialize?(this)
|
60
|
+
|
61
|
+
@editor = ace.edit(@$editor.get(0))
|
62
|
+
@editor.$blockScrolling = Infinity
|
63
|
+
|
64
|
+
@session = @editor.getSession()
|
65
|
+
@session.setValue(@$input.val())
|
66
|
+
@session.setUseWrapMode(true)
|
67
|
+
@session.setMode("ace/mode/markdown")
|
68
|
+
|
69
|
+
# options: https://github.com/ajaxorg/ace/wiki/Configuring-Ace
|
70
|
+
@editor.setOptions
|
71
|
+
autoScrollEditorIntoView: true
|
72
|
+
minLines: 5
|
73
|
+
maxLines: Infinity
|
74
|
+
showLineNumbers: false
|
75
|
+
showGutter: false
|
76
|
+
highlightActiveLine: false
|
77
|
+
showPrintMargin: false
|
78
|
+
|
79
|
+
@session.on 'change', (e) => @_update_inputs()
|
80
|
+
|
81
|
+
@config.onInitialize?(this)
|
82
|
+
|
83
|
+
|
84
|
+
updateValue: (@value) ->
|
85
|
+
@session.setValue(@value)
|
86
|
+
@_update_inputs()
|
87
|
+
|
88
|
+
|
89
|
+
chr.formInputs['markdown'] = InputMarkdown
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
# Author: Alexander Kravets <alex@slatestudio.com>,
|
3
|
+
# Slate Studio (http://www.slatestudio.com)
|
4
|
+
#
|
5
|
+
# Coding Guide:
|
6
|
+
# https://github.com/thoughtbot/guides/tree/master/style/coffeescript
|
7
|
+
# -----------------------------------------------------------------------------
|
8
|
+
|
9
|
+
# -----------------------------------------------------------------------------
|
10
|
+
# INPUT PASSWORD
|
11
|
+
# -----------------------------------------------------------------------------
|
12
|
+
class @InputPassword extends InputString
|
13
|
+
|
14
|
+
# PRIVATE ===============================================
|
15
|
+
|
16
|
+
_add_input: ->
|
17
|
+
@$input =$ "<input type='password' name='#{ @name }' value='#{ @value }' />"
|
18
|
+
@$input.on 'keyup', (e) => @$input.trigger('change')
|
19
|
+
@$el.append @$input
|
20
|
+
|
21
|
+
|
22
|
+
# PUBLIC ================================================
|
23
|
+
|
24
|
+
updateValue: (@value) ->
|
25
|
+
@$input.val(@value)
|
26
|
+
|
27
|
+
|
28
|
+
chr.formInputs['password'] = InputPassword
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
# Author: Alexander Kravets <alex@slatestudio.com>,
|
3
|
+
# Slate Studio (http://www.slatestudio.com)
|
4
|
+
#
|
5
|
+
# Coding Guide:
|
6
|
+
# https://github.com/thoughtbot/guides/tree/master/style/coffeescript
|
7
|
+
# -----------------------------------------------------------------------------
|
8
|
+
|
9
|
+
# -----------------------------------------------------------------------------
|
10
|
+
# INPUT REDACTOR
|
11
|
+
# -----------------------------------------------------------------------------
|
12
|
+
#
|
13
|
+
# Dependencies:
|
14
|
+
#= require redactor
|
15
|
+
#= require vendor/redactor.fixedtoolbar
|
16
|
+
#= require ./redactor_character
|
17
|
+
# -----------------------------------------------------------------------------
|
18
|
+
|
19
|
+
class @InputRedactor extends InputString
|
20
|
+
|
21
|
+
# PRIVATE ===============================================
|
22
|
+
|
23
|
+
_add_input: ->
|
24
|
+
@$el.css('opacity', 0)
|
25
|
+
@$input =$ "<textarea class='redactor' name='#{ @name }' rows=1>#{ @_safe_value() }</textarea>"
|
26
|
+
@$el.append @$input
|
27
|
+
|
28
|
+
|
29
|
+
# PUBLIC ================================================
|
30
|
+
|
31
|
+
initialize: ->
|
32
|
+
@config.beforeInitialize?(this)
|
33
|
+
|
34
|
+
@$input.redactor(@_redactor_options())
|
35
|
+
|
36
|
+
@$el.css('opacity', 1)
|
37
|
+
|
38
|
+
@config.onInitialize?(this)
|
39
|
+
|
40
|
+
|
41
|
+
updateValue: (@value) ->
|
42
|
+
@_trigger_change = false
|
43
|
+
@$input.redactor('code.set', @value)
|
44
|
+
|
45
|
+
|
46
|
+
include(InputRedactor, redactorCharacter)
|
47
|
+
|
48
|
+
|
49
|
+
chr.formInputs['redactor'] = InputRedactor
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
# Author: Alexander Kravets <alex@slatestudio.com>,
|
3
|
+
# Slate Studio (http://www.slatestudio.com)
|
4
|
+
#
|
5
|
+
# Coding Guide:
|
6
|
+
# https://github.com/thoughtbot/guides/tree/master/style/coffeescript
|
7
|
+
# -----------------------------------------------------------------------------
|
8
|
+
|
9
|
+
# -----------------------------------------------------------------------------
|
10
|
+
# REDACTOR CUSTOM VERSION
|
11
|
+
#= require ./redactor_images
|
12
|
+
# -----------------------------------------------------------------------------
|
13
|
+
|
14
|
+
# change default fast speed from 200 to 10 as it's used by redactor modals
|
15
|
+
# while closing
|
16
|
+
console.log ':: [redactor-character] change $.fx.speeds.fast from 200 to 10 ::'
|
17
|
+
$.fx.speeds.fast = 10
|
18
|
+
|
19
|
+
@redactorCharacter =
|
20
|
+
|
21
|
+
# PRIVATE ===============================================
|
22
|
+
|
23
|
+
# TODO: fixed toolbar disabled on mobile
|
24
|
+
_redactor_options: ->
|
25
|
+
@_trigger_change = true
|
26
|
+
|
27
|
+
config = @_get_default_config()
|
28
|
+
@config.redactorOptions ?= {}
|
29
|
+
|
30
|
+
$.extend(config, @config.redactorOptions)
|
31
|
+
|
32
|
+
if (! chr.isMobile()) && config.plugins.indexOf('fixedtoolbar') == -1
|
33
|
+
config.plugins.push('fixedtoolbar')
|
34
|
+
|
35
|
+
if Loft? && config.plugins.indexOf('loft') == -1
|
36
|
+
config.plugins.push('loft')
|
37
|
+
|
38
|
+
if chr.isMobile()
|
39
|
+
config.toolbarFixed = false
|
40
|
+
# config.toolbarFixedTopOffset = 40
|
41
|
+
|
42
|
+
return config
|
43
|
+
|
44
|
+
|
45
|
+
_get_default_config: () ->
|
46
|
+
focus: false
|
47
|
+
imageFloatMargin: '20px'
|
48
|
+
buttonSource: true
|
49
|
+
pastePlainText: true
|
50
|
+
scrollTarget: chr.module.view.$content
|
51
|
+
plugins: []
|
52
|
+
buttons: [ 'html',
|
53
|
+
'formatting',
|
54
|
+
'bold',
|
55
|
+
'italic',
|
56
|
+
'deleted',
|
57
|
+
'unorderedlist',
|
58
|
+
'orderedlist',
|
59
|
+
'link' ]
|
60
|
+
|
61
|
+
# to have caching working we need to trigger 'change' event for textarea
|
62
|
+
# when content got changed in redactor, but skip this when updating value
|
63
|
+
# via `updateValue` method
|
64
|
+
changeCallback: =>
|
65
|
+
if @_trigger_change
|
66
|
+
@$input.trigger('change')
|
67
|
+
@_trigger_change = true
|
68
|
+
|
69
|
+
initCallback: ->
|
70
|
+
new RedactorImages(this)
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
|
@@ -0,0 +1,166 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
# Author: Alexander Kravets <alex@slatestudio.com>,
|
3
|
+
# Slate Studio (http://www.slatestudio.com)
|
4
|
+
#
|
5
|
+
# Coding Guide:
|
6
|
+
# https://github.com/thoughtbot/guides/tree/master/style/coffeescript
|
7
|
+
# -----------------------------------------------------------------------------
|
8
|
+
|
9
|
+
# -----------------------------------------------------------------------------
|
10
|
+
# REDACTOR IMAGES
|
11
|
+
# -----------------------------------------------------------------------------
|
12
|
+
|
13
|
+
class @RedactorImages
|
14
|
+
constructor: (@redactor) ->
|
15
|
+
|
16
|
+
@redactor.opts.modal.imageEdit = @_modal_edit_image()
|
17
|
+
@redactor.image.update = ($image) => @update($image)
|
18
|
+
@redactor.image.showEdit = ($image) => @_show_edit($image)
|
19
|
+
@redactor.image.loadEditableControls = ($image) => @_load_editable_controls($image)
|
20
|
+
|
21
|
+
|
22
|
+
_modal_edit_image: ->
|
23
|
+
"""<section id="redactor-modal-image-edit">
|
24
|
+
<label>Image Alternative Text</label>
|
25
|
+
<input type="text" id="redactor-image-title" />
|
26
|
+
|
27
|
+
<label class="redactor-image-position-option">Position</label>
|
28
|
+
<select class="redactor-image-position-option" id="redactor-image-align">
|
29
|
+
<option value="none">None</option>
|
30
|
+
<option value="left">Left</option>
|
31
|
+
<option value="center">Center</option>
|
32
|
+
<option value="right">Right</option>
|
33
|
+
</select>
|
34
|
+
|
35
|
+
<label class="redactor-image-link-option">Link URL</label>
|
36
|
+
<input type="text" id="redactor-image-link-url" class="redactor-image-link-option" />
|
37
|
+
|
38
|
+
<label class="redactor-image-link-option">Link Title</label>
|
39
|
+
<input type="text" id="redactor-image-link-title" class="redactor-image-link-option" />
|
40
|
+
|
41
|
+
<label class="redactor-image-link-option"><input type="checkbox" id="redactor-image-link-blank"> Open link in new tab</label>
|
42
|
+
</section>"""
|
43
|
+
|
44
|
+
|
45
|
+
update: ($image) ->
|
46
|
+
@redactor.image.hideResize()
|
47
|
+
@redactor.buffer.set()
|
48
|
+
|
49
|
+
$link = $image.closest('a')
|
50
|
+
|
51
|
+
$image.attr('alt', $('#redactor-image-title').val())
|
52
|
+
|
53
|
+
@redactor.image.setFloating($image)
|
54
|
+
|
55
|
+
# as link
|
56
|
+
link = $.trim($('#redactor-image-link-url').val())
|
57
|
+
title = $.trim($('#redactor-image-link-title').val())
|
58
|
+
|
59
|
+
if link != ''
|
60
|
+
|
61
|
+
target = if ( $('#redactor-image-link-blank').prop('checked') ) then true else false
|
62
|
+
|
63
|
+
if $link.size() == 0
|
64
|
+
a =$ "<a href='#{ link }' title='#{ title }'>#{ @redactor.utils.getOuterHtml($image) }</a>"
|
65
|
+
|
66
|
+
if target
|
67
|
+
a.attr('target', '_blank')
|
68
|
+
|
69
|
+
$image.replaceWith(a)
|
70
|
+
|
71
|
+
else
|
72
|
+
$link.attr('href', link)
|
73
|
+
$link.attr('title', title)
|
74
|
+
|
75
|
+
if target
|
76
|
+
$link.attr('target', '_blank')
|
77
|
+
|
78
|
+
else
|
79
|
+
$link.removeAttr('target')
|
80
|
+
|
81
|
+
else if $link.size() != 0
|
82
|
+
$link.replaceWith(@redactor.utils.getOuterHtml($image))
|
83
|
+
|
84
|
+
@redactor.modal.close()
|
85
|
+
@redactor.observe.images()
|
86
|
+
@redactor.code.sync()
|
87
|
+
|
88
|
+
|
89
|
+
_show_edit: ($image) ->
|
90
|
+
$link = $image.closest('a')
|
91
|
+
|
92
|
+
@redactor.image.hideResize()
|
93
|
+
@redactor.modal.load('imageEdit', @redactor.lang.get('edit'), 705)
|
94
|
+
|
95
|
+
@redactor.modal.createCancelButton()
|
96
|
+
@redactor.image.buttonDelete = @redactor.modal.createDeleteButton(@redactor.lang.get('_delete'))
|
97
|
+
@redactor.image.buttonSave = @redactor.modal.createActionButton(@redactor.lang.get('save'))
|
98
|
+
|
99
|
+
@redactor.image.buttonDelete.on 'click', $.proxy(( => @redactor.image.remove($image) ), @redactor)
|
100
|
+
@redactor.image.buttonSave.on 'click', $.proxy(( => @redactor.image.update($image) ), @redactor)
|
101
|
+
|
102
|
+
$('#redactor-image-title').val($image.attr('alt'))
|
103
|
+
|
104
|
+
if ! @redactor.opts.imageLink
|
105
|
+
$('.redactor-image-link-option').hide()
|
106
|
+
|
107
|
+
else
|
108
|
+
$redactorImageLinkUrl = $('#redactor-image-link-url')
|
109
|
+
$redactorImageLinkTitle = $('#redactor-image-link-title')
|
110
|
+
|
111
|
+
$redactorImageLinkUrl.attr('href', $image.attr('src'))
|
112
|
+
|
113
|
+
if $link.size() != 0
|
114
|
+
$redactorImageLinkUrl.val($link.attr('href'))
|
115
|
+
$redactorImageLinkTitle.val($link.attr('title'))
|
116
|
+
|
117
|
+
if $link.attr('target') == '_blank'
|
118
|
+
$('#redactor-image-link-blank').prop('checked', true)
|
119
|
+
|
120
|
+
if ! @redactor.opts.imagePosition
|
121
|
+
$('.redactor-image-position-option').hide()
|
122
|
+
|
123
|
+
else
|
124
|
+
floatValue = if ($image.css('display') == 'block' && $image.css('float') == 'none') then 'center' else $image.css('float')
|
125
|
+
$('#redactor-image-align').val(floatValue)
|
126
|
+
|
127
|
+
@redactor.modal.show()
|
128
|
+
|
129
|
+
|
130
|
+
# for some reason when image is a link, tooltip is shown with the image edit dialog,
|
131
|
+
# add e.stopPropagation() to skip tooltip callback
|
132
|
+
_load_editable_controls: ($image) ->
|
133
|
+
imageBox =$ '<span id="redactor-image-box" data-redactor="verified">'
|
134
|
+
imageBox.css('float', $image.css('float')).attr('contenteditable', false)
|
135
|
+
|
136
|
+
if $image[0].style.margin != 'auto'
|
137
|
+
imageBox.css
|
138
|
+
marginTop: $image[0].style.marginTop
|
139
|
+
marginBottom: $image[0].style.marginBottom
|
140
|
+
marginLeft: $image[0].style.marginLeft
|
141
|
+
marginRight: $image[0].style.marginRight
|
142
|
+
|
143
|
+
$image.css('margin', '')
|
144
|
+
|
145
|
+
else
|
146
|
+
imageBox.css({ 'display': 'block', 'margin': 'auto' })
|
147
|
+
|
148
|
+
$image.css('opacity', '.5').after(imageBox)
|
149
|
+
|
150
|
+
if @redactor.opts.imageEditable
|
151
|
+
# editter
|
152
|
+
@redactor.image.editter =$ "<span id='redactor-image-editter' data-redactor='verified'>Edit</span>"
|
153
|
+
@redactor.image.editter.attr('contenteditable', false)
|
154
|
+
@redactor.image.editter.on('click', $.proxy(( (e) => e.stopPropagation() ; @redactor.image.showEdit($image) ), @redactor))
|
155
|
+
|
156
|
+
imageBox.append(@redactor.image.editter)
|
157
|
+
|
158
|
+
# position correction
|
159
|
+
editerWidth = @redactor.image.editter.innerWidth()
|
160
|
+
@redactor.image.editter.css('margin-left', '-' + editerWidth/2 + 'px')
|
161
|
+
|
162
|
+
return @redactor.image.loadResizableControls($image, imageBox)
|
163
|
+
|
164
|
+
|
165
|
+
|
166
|
+
|