forked from akatov/angular-contenteditable
-
Notifications
You must be signed in to change notification settings - Fork 0
/
angular-contenteditable.js
98 lines (94 loc) · 2.85 KB
/
angular-contenteditable.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/**
* @see http://docs.angularjs.org/guide/concepts
* @see http://docs.angularjs.org/api/ng.directive:ngModel.NgModelController
* @see https://github.com/angular/angular.js/issues/528#issuecomment-7573166
*/
angular.module('contenteditable', [])
.directive('contenteditable', ['$timeout', function($timeout) { return {
restrict: 'A',
require: '?ngModel',
link: function(scope, element, attrs, ngModel) {
// don't do anything unless this is actually bound to a model
if (!ngModel) {
return
}
// options
var opts = {}
angular.forEach([
'stripBr',
'noLineBreaks',
'selectNonEditable',
'moveCaretToEndOnChange',
], function(opt) {
var o = attrs[opt]
opts[opt] = o && o !== 'false'
})
// view -> model
element.bind('input', function(e) {
scope.$apply(function() {
var html, html2, rerender
html = element.html()
rerender = false
if (opts.stripBr) {
html = html.replace(/<br>$/, '')
}
if (opts.noLineBreaks) {
html2 = html.replace(/<div>/g, '').replace(/<br>/g, '').replace(/<\/div>/g, '')
if (html2 !== html) {
rerender = true
html = html2
}
}
ngModel.$setViewValue(html)
if (rerender) {
ngModel.$render()
}
if (html === '') {
// the cursor disappears if the contents is empty
// so we need to refocus
$timeout(function(){
element[0].blur()
element[0].focus()
})
}
})
})
// model -> view
var oldRender = ngModel.$render
ngModel.$render = function() {
var el, el2, range, sel
if (!!oldRender) {
oldRender()
}
element.html(ngModel.$viewValue || '')
if (opts.moveCaretToEndOnChange) {
el = element[0]
range = document.createRange()
sel = window.getSelection()
if (el.childNodes.length > 0) {
el2 = el.childNodes[el.childNodes.length - 1]
range.setStartAfter(el2)
} else {
range.setStartAfter(el)
}
range.collapse(true)
sel.removeAllRanges()
sel.addRange(range)
}
}
if (opts.selectNonEditable) {
element.bind('click', function(e) {
var range, sel, target
target = e.toElement
if (target !== this && angular.element(target).attr('contenteditable') === 'false') {
range = document.createRange()
sel = window.getSelection()
range.setStartBefore(target)
range.setEndAfter(target)
sel.removeAllRanges()
sel.addRange(range)
}
})
}
}
}}])