character_editor 0.0.9 → 0.1.2
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.
- checksums.yaml +4 -4
- data/README.md +6 -1
- data/app/assets/javascripts/character_editor/insert/_insert.coffee +97 -0
- data/app/assets/javascripts/character_editor/toolbar/_templates.coffee +14 -13
- data/app/assets/javascripts/character_editor/toolbar/_toolbar.coffee +2 -2
- data/app/assets/javascripts/character_editor.coffee +19 -1
- data/app/assets/stylesheets/character_editor.scss +22 -2
- data/lib/character_editor/version.rb +1 -1
- data/vendor/assets/javascripts/keypress.js +1063 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a28ae915e435aff9c7c4b42efa95dcbddd8e2b55
|
4
|
+
data.tar.gz: 567065cb629ca416769396e391657318295d41f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d00e2832a413ae65a4d3feaea248d8f4485b2e7ebd3e0265f2419a5e4d6df2734d68f66dcf0ef50c40a7959f080a77847bd75645fbc4966d4dd76e0df6b9e22
|
7
|
+
data.tar.gz: 67543b68ee242101e2f8d06d3fa3d5e9b3c30e3627547092451782f47d0d7057a6aca4e796d4c9bead7e7d024f73b6fabe1856067bf9642bff98fad994d3e44a
|
data/README.md
CHANGED
@@ -5,7 +5,12 @@ Based on [MediumEditor](https://github.com/daviferreira/medium-editor) — Mediu
|
|
5
5
|
## TODO:
|
6
6
|
- fix copy/paste in the editor (test Safari/Chrome/FF, might be related to span issue)
|
7
7
|
- pre tag is not removed when unset
|
8
|
-
-
|
8
|
+
- buttons for image settings
|
9
|
+
- fix placeholder
|
10
|
+
- fix insert image after pre
|
11
|
+
- figure out default buttons
|
12
|
+
- hotkeys
|
13
|
+
- improve toolbar performance (no DOM changes)
|
9
14
|
|
10
15
|
### Span Issue: happens only in Chrome
|
11
16
|
|
@@ -0,0 +1,97 @@
|
|
1
|
+
#= require_self
|
2
|
+
|
3
|
+
window.delay = (ms, fnc) -> setTimeout(fnc, ms)
|
4
|
+
|
5
|
+
@CharacterEditor.Insert =
|
6
|
+
init: (options, elem) ->
|
7
|
+
@options = $.extend({}, @options, options)
|
8
|
+
|
9
|
+
@$elem = $("<div id=character_editor_insert_button class='character-editor-insert'><i class='chr-icon icon-plus-alt'></i></div>")
|
10
|
+
$(@options.viewSelector).append(@$elem)
|
11
|
+
|
12
|
+
@_build()
|
13
|
+
@_bind()
|
14
|
+
@
|
15
|
+
|
16
|
+
options: {}
|
17
|
+
|
18
|
+
_build: ->
|
19
|
+
|
20
|
+
_hide: ->
|
21
|
+
delay 50, => if not @stayVisible then @$elem.removeClass('visible')
|
22
|
+
|
23
|
+
_show: ($editorElement, offsetY=0) ->
|
24
|
+
# TODO: it looks like we don't need live recalculations, rather can have just a table of positions
|
25
|
+
delay 50, =>
|
26
|
+
if @stayVisible
|
27
|
+
offsetX = -($(@options.viewSelector).offset().left - $editorElement.offset().left) - 5 # '+' moves to the right
|
28
|
+
offsetY += Math.floor($editorElement.offset().top + $(@options.viewSelector).scrollTop() - $(@options.viewSelector).offset().top)
|
29
|
+
@$elem.css({ top: offsetY, 'margin-left': offsetX }).addClass('visible')
|
30
|
+
|
31
|
+
_bind: ->
|
32
|
+
@_bindOnHover()
|
33
|
+
@_bindImage()
|
34
|
+
|
35
|
+
_bindOnHover: ->
|
36
|
+
@$elem.on 'mouseenter', (e) => @stayVisible = true
|
37
|
+
@$elem.on 'mouseleave', (e) => @stayVisible = false ; @_hide()
|
38
|
+
@_bindMousemove()
|
39
|
+
#$(document).on 'mouseleave', '.character-editor-insert-enabled', => @stayVisible = false ; @_hide()
|
40
|
+
|
41
|
+
_bindMousemove: ->
|
42
|
+
$(document).on 'mousemove', '.character-editor-insert-enabled', (e) =>
|
43
|
+
# TODO: block this while scrolling is not stopped
|
44
|
+
$editorElement = $(e.currentTarget)
|
45
|
+
currentEditor = $editorElement.data('editor')
|
46
|
+
|
47
|
+
if currentEditor.options.disableInsert
|
48
|
+
return
|
49
|
+
|
50
|
+
if e.currentTarget == e.target # no child block is hovered
|
51
|
+
offsetY = 0
|
52
|
+
editorTop = $editorElement.offset().top
|
53
|
+
|
54
|
+
if $editorElement.children().length > 0
|
55
|
+
paddingTop = $editorElement.children().first().offset().top - editorTop
|
56
|
+
else
|
57
|
+
paddingTop = parseInt($editorElement.css('padding-top'))
|
58
|
+
|
59
|
+
if e.offsetY <= paddingTop # beginning of the editor
|
60
|
+
if $editorElement.children().length > 0
|
61
|
+
offsetY = paddingTop - @$elem.height()
|
62
|
+
|
63
|
+
@$insertAfterBlock = false
|
64
|
+
@$activeEditor = $editorElement
|
65
|
+
|
66
|
+
else # cursor in between blocks
|
67
|
+
$editorElement.children().each (i, el) =>
|
68
|
+
$block = $(el)
|
69
|
+
y = $block.offset().top - editorTop + $block.height()
|
70
|
+
|
71
|
+
if y < e.offsetY
|
72
|
+
@$insertAfterBlock = $block
|
73
|
+
offsetY = y
|
74
|
+
|
75
|
+
@stayVisible = true
|
76
|
+
@_show($editorElement, offsetY)
|
77
|
+
|
78
|
+
else
|
79
|
+
@stayVisible = false
|
80
|
+
@_hide()
|
81
|
+
|
82
|
+
_bindImage: ->
|
83
|
+
$('#character_editor_insert_button').on 'click', (e) =>
|
84
|
+
chr.execute 'showImages', true, (images) =>
|
85
|
+
_.each images.reverse(), (model) =>
|
86
|
+
@_insertImage(model.get('image'))
|
87
|
+
|
88
|
+
_insertImage: (data) ->
|
89
|
+
imageUrl = data.image.regular.url
|
90
|
+
$el = $("""<figure class='character-image' contenteditable='false'><img src='#{ imageUrl }'></figure>""")
|
91
|
+
if @$insertAfterBlock then $el.insertAfter(@$insertAfterBlock) else $el.prependTo(@$activeEditor)
|
92
|
+
|
93
|
+
destroy: ->
|
94
|
+
$('#character_editor_insert_button').off 'click'
|
95
|
+
$(document).off 'mousemove', '.character-editor-insert-enabled'
|
96
|
+
@$elem.off 'mouseenter, mouseleave'
|
97
|
+
@$elem.remove()
|
@@ -13,19 +13,19 @@
|
|
13
13
|
|
14
14
|
l =
|
15
15
|
bold: '<i class="fa fa-bold"></i>'
|
16
|
-
italic
|
16
|
+
italic: '<i class="fa fa-italic"></i>'
|
17
17
|
underline: '<i class="fa fa-underline"></i>'
|
18
18
|
strikethrough: '<i class="fa fa-strikethrough"></i>'
|
19
|
-
superscript: '<i class="fa fa-superscript"></i>'
|
20
|
-
subscript: '<i class="fa fa-subscript"></i>'
|
21
19
|
anchor: '<i class="fa fa-link"></i>'
|
22
|
-
image: '<i class="fa fa-picture-o"></i>'
|
23
20
|
quote: '<i class="fa fa-quote-right"></i>'
|
24
21
|
orderedlist: '<i class="fa fa-list-ol"></i>'
|
25
22
|
unorderedlist: '<i class="fa fa-list-ul"></i>'
|
26
23
|
pre: '<i class="fa fa-code fa-lg"></i>'
|
27
24
|
header1: "<b>#{ options.firstHeader.toUpperCase() }</b>"
|
28
25
|
header2: "<b>#{ options.secondHeader.toUpperCase() }</b>"
|
26
|
+
#image: '<i class="fa fa-picture-o"></i>'
|
27
|
+
#superscript: '<i class="fa fa-superscript"></i>'
|
28
|
+
#subscript: '<i class="fa fa-subscript"></i>'
|
29
29
|
|
30
30
|
templates =
|
31
31
|
bold: "<li><button class='#{classPrefix} #{classPrefix}-bold'
|
@@ -40,18 +40,9 @@
|
|
40
40
|
strikethrough: "<li><button class='#{classPrefix} #{classPrefix}-strikethrough'
|
41
41
|
data-action='strikethrough' data-element='strike'>#{ l.strikethrough }</button></li>"
|
42
42
|
|
43
|
-
superscript: "<li><button class='#{classPrefix} #{classPrefix}-superscript'
|
44
|
-
data-action='superscript' data-element='sup'>#{ l.superscript }</button></li>"
|
45
|
-
|
46
|
-
subscript: "<li><button class='#{classPrefix} #{classPrefix}-subscript'
|
47
|
-
data-action='subscript' data-element='sub'>#{ l.subscript }</button></li>"
|
48
|
-
|
49
43
|
anchor: "<li><button class='#{classPrefix} #{classPrefix}-anchor'
|
50
44
|
data-action='anchor' data-element='a'>#{ l.anchor }</button></li>"
|
51
45
|
|
52
|
-
image: "<li><button class='#{classPrefix} #{classPrefix}-image'
|
53
|
-
data-action='image' data-element='img'>#{ l.image }</button></li>"
|
54
|
-
|
55
46
|
quote: "<li><button class='#{classPrefix} #{classPrefix}-quote'
|
56
47
|
data-action='append-blockquote' data-element='blockquote'>#{ l.quote }</button></li>"
|
57
48
|
|
@@ -69,4 +60,14 @@
|
|
69
60
|
|
70
61
|
header2: "<li><button class='#{classPrefix} #{classPrefix}-header2'
|
71
62
|
data-action='append-#{ options.secondHeader }' data-element='#{ options.secondHeader }'>#{ l.header2 }</button></li>"
|
63
|
+
|
64
|
+
# image: "<li><button class='#{classPrefix} #{classPrefix}-image'
|
65
|
+
# data-action='image' data-element='img'>#{ l.image }</button></li>"
|
66
|
+
|
67
|
+
# superscript: "<li><button class='#{classPrefix} #{classPrefix}-superscript'
|
68
|
+
# data-action='superscript' data-element='sup'>#{ l.superscript }</button></li>"
|
69
|
+
|
70
|
+
# subscript: "<li><button class='#{classPrefix} #{classPrefix}-subscript'
|
71
|
+
# data-action='subscript' data-element='sub'>#{ l.subscript }</button></li>"
|
72
|
+
|
72
73
|
return templates
|
@@ -53,7 +53,7 @@
|
|
53
53
|
|
54
54
|
@$toolbarButtons.show()
|
55
55
|
|
56
|
-
@$anchorInput.css('width', @$elem.width() - 40
|
56
|
+
@$anchorInput.css('width', @$elem.width() - 40) # TODO: remove build in themes values
|
57
57
|
|
58
58
|
@keepToolbarVisible = false
|
59
59
|
|
@@ -102,9 +102,9 @@
|
|
102
102
|
if !@options.allowMultiParagraphSelection and hasMultiParagraphs
|
103
103
|
return @_hide()
|
104
104
|
|
105
|
-
@_setButtonStates()
|
106
105
|
@_show()
|
107
106
|
@_setPosition()
|
107
|
+
@_setButtonStates()
|
108
108
|
|
109
109
|
_setButtonStates: ->
|
110
110
|
$buttons = @$elem.find('button')
|
@@ -10,9 +10,11 @@
|
|
10
10
|
|
11
11
|
###
|
12
12
|
|
13
|
+
#= require keypress
|
13
14
|
#= require_self
|
14
15
|
#= require character_editor/_selection
|
15
16
|
#= require character_editor/toolbar/_toolbar
|
17
|
+
#= require character_editor/insert/_insert
|
16
18
|
|
17
19
|
# Object - an object representing a concept that you want
|
18
20
|
# to model (e.g. a car)
|
@@ -26,6 +28,7 @@
|
|
26
28
|
diffTop: -10
|
27
29
|
disableReturn: false
|
28
30
|
disableToolbar: false
|
31
|
+
disableInsert: false
|
29
32
|
forcePlainText: true
|
30
33
|
placeholder: 'Type your text...'
|
31
34
|
targetBlank: false
|
@@ -33,7 +36,7 @@
|
|
33
36
|
secondHeader: 'h3'
|
34
37
|
tabSpaces: ' '
|
35
38
|
viewSelector: 'body'
|
36
|
-
parentElements: ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'pre']
|
39
|
+
parentElements: ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'pre', 'ul', 'ol']
|
37
40
|
|
38
41
|
_dataOptions: ->
|
39
42
|
result = {}
|
@@ -81,6 +84,16 @@
|
|
81
84
|
if not @options.disableToolbar
|
82
85
|
@_addToolbar()
|
83
86
|
|
87
|
+
if not @options.disableInsert
|
88
|
+
@$elem.addClass 'character-editor-insert-enabled'
|
89
|
+
@_addInsert()
|
90
|
+
|
91
|
+
_addInsert: ->
|
92
|
+
@insert = window.characterEditorInsert
|
93
|
+
if not @insert
|
94
|
+
@insert = Object.create(CharacterEditor.Insert).init(@options)
|
95
|
+
window.characterEditorInsert = @insert
|
96
|
+
|
84
97
|
_addToolbar: ->
|
85
98
|
@toolbar = window.characterEditorToolbar
|
86
99
|
if not @toolbar
|
@@ -171,6 +184,11 @@
|
|
171
184
|
delete @toolbar
|
172
185
|
delete window.characterEditorToolbar
|
173
186
|
|
187
|
+
if @insert
|
188
|
+
@insert.destroy()
|
189
|
+
delete @insert
|
190
|
+
delete window.characterEditorInsert
|
191
|
+
|
174
192
|
# Object.create support test, and fallback for browsers without it
|
175
193
|
if typeof Object.create isnt "function"
|
176
194
|
Object.create = (o) ->
|
@@ -10,6 +10,26 @@ $button_size: 40px;
|
|
10
10
|
.character-editor {
|
11
11
|
&:focus { outline: 0;
|
12
12
|
}
|
13
|
+
&.character-editor-insert-enabled { padding: 20px 0;
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
.character-editor-insert { position: absolute;
|
18
|
+
width: 20px;
|
19
|
+
height: 20px;
|
20
|
+
left: 0px;
|
21
|
+
top: 0px;
|
22
|
+
visibility: hidden;
|
23
|
+
cursor: pointer;
|
24
|
+
box-sizing: border-box;
|
25
|
+
z-index: 1;
|
26
|
+
i { width: 16px;
|
27
|
+
height: 16px;
|
28
|
+
margin-left: 2px;
|
29
|
+
margin-top: 2px;
|
30
|
+
}
|
31
|
+
&.visible { visibility: visible;
|
32
|
+
}
|
13
33
|
}
|
14
34
|
|
15
35
|
.character-editor-placeholder { position: relative;
|
@@ -53,7 +73,7 @@ $button_size: 40px;
|
|
53
73
|
cursor: pointer;
|
54
74
|
font-size: 14px;
|
55
75
|
text-decoration: none;
|
56
|
-
&:hover { background-color: $border_color;
|
76
|
+
&:hover { //background-color: $border_color;
|
57
77
|
color: #fff;
|
58
78
|
}
|
59
79
|
&:focus { outline: none;
|
@@ -75,7 +95,7 @@ $button_size: 40px;
|
|
75
95
|
}
|
76
96
|
input[type='text'] { display: inline;
|
77
97
|
padding: 6px;
|
78
|
-
height: $button_size
|
98
|
+
height: $button_size;
|
79
99
|
background-color: $bgcolor!important;
|
80
100
|
color: $link_color;
|
81
101
|
border: none;
|