formagic 0.1.0

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.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/CONTRIBUTING.md +24 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE.md +21 -0
  6. data/README.md +29 -0
  7. data/Rakefile +1 -0
  8. data/app/assets/images/datedropper/done.png +0 -0
  9. data/app/assets/images/datedropper/done.svg +1 -0
  10. data/app/assets/images/datedropper/next.png +0 -0
  11. data/app/assets/images/datedropper/next.svg +1 -0
  12. data/app/assets/images/datedropper/prev.png +0 -0
  13. data/app/assets/images/datedropper/prev.svg +1 -0
  14. data/app/assets/javascripts/formagic/form.coffee +229 -0
  15. data/app/assets/javascripts/formagic/group.coffee +28 -0
  16. data/app/assets/javascripts/formagic/inputs/checkbox.coffee +83 -0
  17. data/app/assets/javascripts/formagic/inputs/color.coffee +55 -0
  18. data/app/assets/javascripts/formagic/inputs/date.coffee +69 -0
  19. data/app/assets/javascripts/formagic/inputs/datetime.coffee +130 -0
  20. data/app/assets/javascripts/formagic/inputs/document.coffee +0 -0
  21. data/app/assets/javascripts/formagic/inputs/documents.coffee +173 -0
  22. data/app/assets/javascripts/formagic/inputs/documents_reorder.coffee +67 -0
  23. data/app/assets/javascripts/formagic/inputs/file.coffee +114 -0
  24. data/app/assets/javascripts/formagic/inputs/hidden.coffee +57 -0
  25. data/app/assets/javascripts/formagic/inputs/html.coffee +81 -0
  26. data/app/assets/javascripts/formagic/inputs/image.coffee +28 -0
  27. data/app/assets/javascripts/formagic/inputs/list.coffee +154 -0
  28. data/app/assets/javascripts/formagic/inputs/list_reorder.coffee +39 -0
  29. data/app/assets/javascripts/formagic/inputs/list_typeahead.coffee +55 -0
  30. data/app/assets/javascripts/formagic/inputs/markdown.coffee +93 -0
  31. data/app/assets/javascripts/formagic/inputs/password.coffee +32 -0
  32. data/app/assets/javascripts/formagic/inputs/redactor.coffee +53 -0
  33. data/app/assets/javascripts/formagic/inputs/redactor_character.coffee +75 -0
  34. data/app/assets/javascripts/formagic/inputs/redactor_images.coffee +166 -0
  35. data/app/assets/javascripts/formagic/inputs/select.coffee +84 -0
  36. data/app/assets/javascripts/formagic/inputs/select2.coffee +33 -0
  37. data/app/assets/javascripts/formagic/inputs/string.coffee +160 -0
  38. data/app/assets/javascripts/formagic/inputs/text.coffee +43 -0
  39. data/app/assets/javascripts/formagic/inputs/time.coffee +0 -0
  40. data/app/assets/javascripts/formagic.coffee +22 -0
  41. data/app/assets/javascripts/vendor/ace.js +18280 -0
  42. data/app/assets/javascripts/vendor/datedropper.js +1005 -0
  43. data/app/assets/javascripts/vendor/jquery.scrollparent.js +14 -0
  44. data/app/assets/javascripts/vendor/jquery.textarea_autosize.js +55 -0
  45. data/app/assets/javascripts/vendor/jquery.typeahead.js +1782 -0
  46. data/app/assets/javascripts/vendor/marked.js +1272 -0
  47. data/app/assets/javascripts/vendor/mode-html.js +2436 -0
  48. data/app/assets/javascripts/vendor/mode-markdown.js +2820 -0
  49. data/app/assets/javascripts/vendor/moment.js +3083 -0
  50. data/app/assets/javascripts/vendor/redactor.fixedtoolbar.js +107 -0
  51. data/app/assets/javascripts/vendor/select2.js +5274 -0
  52. data/app/assets/stylesheets/formagic/checkbox.scss +8 -0
  53. data/app/assets/stylesheets/formagic/color.scss +12 -0
  54. data/app/assets/stylesheets/formagic/date.scss +37 -0
  55. data/app/assets/stylesheets/formagic/file.scss +29 -0
  56. data/app/assets/stylesheets/formagic/form.scss +36 -0
  57. data/app/assets/stylesheets/formagic/group.scss +22 -0
  58. data/app/assets/stylesheets/formagic/image.scss +19 -0
  59. data/app/assets/stylesheets/formagic/list.scss +39 -0
  60. data/app/assets/stylesheets/formagic/nested-form.scss +23 -0
  61. data/app/assets/stylesheets/formagic/redactor.scss +41 -0
  62. data/app/assets/stylesheets/formagic/select.scss +5 -0
  63. data/app/assets/stylesheets/formagic/select2.scss +95 -0
  64. data/app/assets/stylesheets/formagic/string.scss +14 -0
  65. data/app/assets/stylesheets/formagic/switch.scss +86 -0
  66. data/app/assets/stylesheets/formagic/text.scss +9 -0
  67. data/app/assets/stylesheets/formagic.scss +15 -0
  68. data/app/assets/stylesheets/vendor/datedropper.scss +523 -0
  69. data/app/assets/stylesheets/vendor/select2.scss +258 -0
  70. data/formagic.gemspec +30 -0
  71. data/lib/formagic/engine.rb +5 -0
  72. data/lib/formagic/version.rb +3 -0
  73. data/lib/formagic.rb +5 -0
  74. 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
+