summernote-rails 0.2.1.1 → 0.2.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 +14 -2
- data/lib/summernote/rails/version.rb +1 -1
- data/vendor/assets/javascripts/summernote.js +1365 -0
- data/vendor/assets/javascripts/summernote.min.js +1 -1
- data/vendor/assets/stylesheets/summernote.css +18 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 66f224d348d0825289874d387f9e713702c3fc50
|
|
4
|
+
data.tar.gz: 2bd808d70a67c2eb3aebbde46c8eb8c992d455e4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ad521e2aa228d8e545cc3c457c50fdea2f3a18184ef7afe9fc244c39d978543190e610b3a14c1d7fe8664b4b8b06908c209542f4e1daa152db72a7d0dcf18eb1
|
|
7
|
+
data.tar.gz: 343f0fa8fc0298feefc4d7db5086831bd3fde65c6a1e4ed12833a7eaf7fe642ca68798fc5f1abf3a8c3442d8df440722f724a84469f65fd36e2f977701e48b42
|
data/README.md
CHANGED
|
@@ -6,6 +6,8 @@ Website of Summernote, https://github.com/hackerwins/summernote
|
|
|
6
6
|
|
|
7
7
|
The version of summernote-rails is matched for the summernote editor.
|
|
8
8
|
|
|
9
|
+
[](http://badge.fury.io/rb/summernote-rails)
|
|
10
|
+
|
|
9
11
|
## Installation
|
|
10
12
|
|
|
11
13
|
Add the following gems to your application's Gemfile:
|
|
@@ -14,10 +16,10 @@ Add the following gems to your application's Gemfile:
|
|
|
14
16
|
gem 'simple_form', github: 'plataformatec/simple_form', tag: 'v3.0.0.beta1'
|
|
15
17
|
# for Rails 3.x
|
|
16
18
|
gem 'simple_form'
|
|
17
|
-
|
|
19
|
+
|
|
18
20
|
gem 'bootstrap-sass'
|
|
19
21
|
gem 'font-awesome-rails'
|
|
20
|
-
gem 'summernote-rails'
|
|
22
|
+
gem 'summernote-rails'
|
|
21
23
|
|
|
22
24
|
And then execute:
|
|
23
25
|
|
|
@@ -83,6 +85,16 @@ In app/views/posts/_form.html.erb, you should add 'summernote' class name to the
|
|
|
83
85
|
|
|
84
86
|
That's it.
|
|
85
87
|
|
|
88
|
+
|
|
89
|
+
## Changelogs
|
|
90
|
+
|
|
91
|
+
- v0.2.1.2 : Added InsertHorizontalRule(Cmd+Enter) in summernote editor
|
|
92
|
+
Added summernote.js
|
|
93
|
+
- v0.2.1.1 : available for Rails >= 3.1
|
|
94
|
+
- v0.2.1 : bugfixed file uploading
|
|
95
|
+
- v0.2.0 : available for Rails v4.0
|
|
96
|
+
|
|
97
|
+
|
|
86
98
|
## Contributing
|
|
87
99
|
|
|
88
100
|
1. Fork it
|
|
@@ -0,0 +1,1365 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* summernote.js
|
|
3
|
+
* (c) 2013~ Alan Hong
|
|
4
|
+
* summernote may be freely distributed under the MIT license./
|
|
5
|
+
*/
|
|
6
|
+
(function($) {
|
|
7
|
+
"use strict";
|
|
8
|
+
|
|
9
|
+
//Check Platform/Agent
|
|
10
|
+
var bMac = navigator.appVersion.indexOf('Mac') > -1;
|
|
11
|
+
var bMSIE = navigator.userAgent.indexOf('MSIE') > -1;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* func utils (for high-order func's arg)
|
|
15
|
+
*/
|
|
16
|
+
var func = function() {
|
|
17
|
+
var eq = function(nodeA) {
|
|
18
|
+
return function(nodeB) { return nodeA === nodeB; };
|
|
19
|
+
};
|
|
20
|
+
var eq2 = function(nodeA, nodeB) { return nodeA === nodeB; };
|
|
21
|
+
var fail = function() { return false; };
|
|
22
|
+
return { eq: eq, eq2: eq2, fail: fail };
|
|
23
|
+
}();
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* list utils
|
|
27
|
+
*/
|
|
28
|
+
var list = function() {
|
|
29
|
+
var head = function(array) { return array[0]; };
|
|
30
|
+
var last = function(array) { return array[array.length - 1]; };
|
|
31
|
+
var initial = function(array) { return array.slice(0, array.length - 1); };
|
|
32
|
+
var tail = function(array) { return array.slice(1); };
|
|
33
|
+
|
|
34
|
+
var clusterBy = function(array, fn) {
|
|
35
|
+
if (array.length === 0) { return []; }
|
|
36
|
+
var aTail = tail(array);
|
|
37
|
+
return aTail.reduce(function (memo, v) {
|
|
38
|
+
var aLast = last(memo);
|
|
39
|
+
if (fn(last(aLast), v)) {
|
|
40
|
+
aLast[aLast.length] = v;
|
|
41
|
+
} else {
|
|
42
|
+
memo[memo.length] = [v];
|
|
43
|
+
}
|
|
44
|
+
return memo;
|
|
45
|
+
}, [[head(array)]]);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
var compact = function(array) {
|
|
49
|
+
var aResult = [];
|
|
50
|
+
for (var idx = 0, sz = array.length; idx < sz; idx ++) {
|
|
51
|
+
if (array[idx]) { aResult.push(array[idx]); };
|
|
52
|
+
};
|
|
53
|
+
return aResult;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
return { head: head, last: last, initial: initial, tail: tail,
|
|
57
|
+
compact: compact, clusterBy: clusterBy };
|
|
58
|
+
}();
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* dom utils
|
|
62
|
+
*/
|
|
63
|
+
var dom = function() {
|
|
64
|
+
var makePredByNodeName = function(sNodeName) {
|
|
65
|
+
// nodeName of element is always uppercase.
|
|
66
|
+
return function(node) { return node && node.nodeName === sNodeName; };
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
var isPara = function(node) {
|
|
70
|
+
return node && /^P|^LI|^H[1-7]/.test(node.nodeName);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
var isList = function(node) {
|
|
74
|
+
return node && /^UL|^OL/.test(node.nodeName);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
var isEditable = function(node) {
|
|
78
|
+
return node && $(node).hasClass('note-editable');
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
var isControlSizing = function(node) {
|
|
82
|
+
return node && $(node).hasClass('note-control-sizing');
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// ancestor: find nearest ancestor predicate hit
|
|
86
|
+
var ancestor = function(node, pred) {
|
|
87
|
+
while (node) {
|
|
88
|
+
if (pred(node)) { return node; }
|
|
89
|
+
node = node.parentNode;
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// listAncestor: listing ancestor nodes (until predicate hit: optional)
|
|
95
|
+
var listAncestor = function(node, pred) {
|
|
96
|
+
pred = pred || func.fail;
|
|
97
|
+
|
|
98
|
+
var aAncestor = [];
|
|
99
|
+
ancestor(node, function(el) {
|
|
100
|
+
aAncestor.push(el);
|
|
101
|
+
return pred(el);
|
|
102
|
+
});
|
|
103
|
+
return aAncestor;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// commonAncestor: find commonAncestor
|
|
107
|
+
var commonAncestor = function(nodeA, nodeB) {
|
|
108
|
+
var aAncestor = listAncestor(nodeA);
|
|
109
|
+
for (var n = nodeB; n; n = n.parentNode) {
|
|
110
|
+
if ($.inArray(n, aAncestor) > -1) { return n; }
|
|
111
|
+
}
|
|
112
|
+
return null; // difference document area
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// listBetween: listing all Nodes between nodeA and nodeB
|
|
116
|
+
// FIXME: nodeA and nodeB must be sorted, use comparePoints later.
|
|
117
|
+
var listBetween = function(nodeA, nodeB) {
|
|
118
|
+
var aNode = [];
|
|
119
|
+
var elAncestor = commonAncestor(nodeA, nodeB);
|
|
120
|
+
//TODO: IE8, createNodeIterator
|
|
121
|
+
var iterator = document.createNodeIterator(elAncestor,
|
|
122
|
+
NodeFilter.SHOW_ALL, null,
|
|
123
|
+
false);
|
|
124
|
+
var node, bStart = false;
|
|
125
|
+
while (node = iterator.nextNode()) {
|
|
126
|
+
if (nodeA === node) { bStart = true; }
|
|
127
|
+
if (bStart) { aNode.push(node); }
|
|
128
|
+
if (nodeB === node) { break; }
|
|
129
|
+
}
|
|
130
|
+
return aNode;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// listNext: listing nextSiblings (until predicate hit: optional)
|
|
134
|
+
var listNext = function(node, pred) {
|
|
135
|
+
pred = pred || func.fail;
|
|
136
|
+
|
|
137
|
+
var aNext = [];
|
|
138
|
+
while (node) {
|
|
139
|
+
aNext.push(node);
|
|
140
|
+
if (node === pred) { break; }
|
|
141
|
+
node = node.nextSibling;
|
|
142
|
+
};
|
|
143
|
+
return aNext;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// insertAfter: insert node after preceding
|
|
147
|
+
var insertAfter = function(node, preceding) {
|
|
148
|
+
var next = preceding.nextSibling, parent = preceding.parentNode;
|
|
149
|
+
if (next) {
|
|
150
|
+
parent.insertBefore(node, next);
|
|
151
|
+
} else {
|
|
152
|
+
parent.appendChild(node);
|
|
153
|
+
}
|
|
154
|
+
return node;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// appends: append children
|
|
158
|
+
var appends = function(node, aChild) {
|
|
159
|
+
$.each(aChild, function(idx, child) {
|
|
160
|
+
node.appendChild(child);
|
|
161
|
+
});
|
|
162
|
+
return node;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
var isText = makePredByNodeName('#text');
|
|
166
|
+
|
|
167
|
+
// length: size of element.
|
|
168
|
+
var length = function(node) {
|
|
169
|
+
if (isText(node)) { return node.nodeValue.length; }
|
|
170
|
+
return node.childNodes.length;
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// position: offset from parent.
|
|
174
|
+
var position = function(node) {
|
|
175
|
+
var offset = 0;
|
|
176
|
+
while (node = node.previousSibling) { offset += 1; }
|
|
177
|
+
return offset;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// makeOffsetPath: return offsetPath(offset list) from ancestor
|
|
181
|
+
var makeOffsetPath = function(ancestor, node) {
|
|
182
|
+
var aAncestor = list.initial(listAncestor(node, func.eq(ancestor)));
|
|
183
|
+
return $.map(aAncestor, position).reverse();
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// fromtOffsetPath: return element from offsetPath(offset list)
|
|
187
|
+
var fromOffsetPath = function(ancestor, aOffset) {
|
|
188
|
+
var current = ancestor;
|
|
189
|
+
for (var i = 0, sz = aOffset.length; i < sz; i++) {
|
|
190
|
+
current = current.childNodes[aOffset[i]];
|
|
191
|
+
}
|
|
192
|
+
return current;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
// splitData: split element or #text
|
|
196
|
+
var splitData = function(node, offset) {
|
|
197
|
+
if (offset === 0) { return node; }
|
|
198
|
+
if (offset >= length(node)) { return node.nextSibling; }
|
|
199
|
+
|
|
200
|
+
// splitText
|
|
201
|
+
if (isText(node)) { return node.splitText(offset); }
|
|
202
|
+
|
|
203
|
+
// splitElement
|
|
204
|
+
var child = node.childNodes[offset];
|
|
205
|
+
node = insertAfter(node.cloneNode(false), node);
|
|
206
|
+
return appends(node, listNext(child));
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// split: split dom tree by boundaryPoint(pivot and offset)
|
|
210
|
+
var split = function(root, pivot, offset) {
|
|
211
|
+
var aAncestor = listAncestor(pivot, func.eq(root));
|
|
212
|
+
if (aAncestor.length === 1) {
|
|
213
|
+
return splitData(pivot, offset);
|
|
214
|
+
}
|
|
215
|
+
return aAncestor.reduce(function(node, parent) {
|
|
216
|
+
var clone = parent.cloneNode(false);
|
|
217
|
+
insertAfter(clone, parent);
|
|
218
|
+
if (node === pivot) {
|
|
219
|
+
node = splitData(node, offset);
|
|
220
|
+
}
|
|
221
|
+
appends(clone, listNext(node));
|
|
222
|
+
return clone;
|
|
223
|
+
});
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
return {
|
|
227
|
+
isText: isText,
|
|
228
|
+
isPara: isPara, isList: isList,
|
|
229
|
+
isEditable: isEditable, isControlSizing: isControlSizing,
|
|
230
|
+
isAnchor: makePredByNodeName('A'),
|
|
231
|
+
isDiv: makePredByNodeName('DIV'), isSpan: makePredByNodeName('SPAN'),
|
|
232
|
+
isB: makePredByNodeName('B'), isU: makePredByNodeName('U'),
|
|
233
|
+
isS: makePredByNodeName('S'), isI: makePredByNodeName('I'),
|
|
234
|
+
isImg: makePredByNodeName('IMG'),
|
|
235
|
+
ancestor: ancestor, listAncestor: listAncestor, listNext: listNext,
|
|
236
|
+
commonAncestor: commonAncestor, listBetween: listBetween,
|
|
237
|
+
insertAfter: insertAfter, position: position,
|
|
238
|
+
makeOffsetPath: makeOffsetPath, fromOffsetPath: fromOffsetPath,
|
|
239
|
+
split: split
|
|
240
|
+
};
|
|
241
|
+
}();
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Range
|
|
245
|
+
* {startContainer, startOffset, endContainer, endOffset}
|
|
246
|
+
* create Range Object From arguments or Browser Selection
|
|
247
|
+
*/
|
|
248
|
+
var bW3CRangeSupport = !!document.createRange;
|
|
249
|
+
var Range = function(sc, so, ec, eo) {
|
|
250
|
+
if (arguments.length === 0) { // from Browser Selection
|
|
251
|
+
if (document.getSelection) { // webkit, firefox
|
|
252
|
+
var nativeRng = document.getSelection().getRangeAt(0);
|
|
253
|
+
sc = nativeRng.startContainer, so = nativeRng.startOffset,
|
|
254
|
+
ec = nativeRng.endContainer, eo = nativeRng.endOffset;
|
|
255
|
+
} // TODO: handle IE8+ TextRange
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
this.sc = sc; this.so = so;
|
|
259
|
+
this.ec = ec; this.eo = eo;
|
|
260
|
+
|
|
261
|
+
// nativeRange: get nativeRange from sc, so, ec, eo
|
|
262
|
+
var nativeRange = function() {
|
|
263
|
+
if (bW3CRangeSupport) {
|
|
264
|
+
var range = document.createRange();
|
|
265
|
+
range.setStart(sc, so);
|
|
266
|
+
range.setEnd(ec, eo);
|
|
267
|
+
return range;
|
|
268
|
+
} // TODO: handle IE8+ TextRange
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
// select: update visible range
|
|
272
|
+
this.select = function() {
|
|
273
|
+
var nativeRng = nativeRange();
|
|
274
|
+
if (bW3CRangeSupport) {
|
|
275
|
+
var selection = document.getSelection();
|
|
276
|
+
if (selection.rangeCount > 0) { selection.removeAllRanges(); }
|
|
277
|
+
selection.addRange(nativeRng);
|
|
278
|
+
} // TODO: handle IE8+ TextRange
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
// listPara: listing paragraphs on range
|
|
282
|
+
this.listPara = function() {
|
|
283
|
+
var aNode = dom.listBetween(sc, ec);
|
|
284
|
+
var aPara = list.compact($.map(aNode, function(node) {
|
|
285
|
+
return dom.ancestor(node, dom.isPara);
|
|
286
|
+
}));
|
|
287
|
+
return $.map(list.clusterBy(aPara, func.eq2), list.head);
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
// isOnList: judge whether range is on list node or not
|
|
291
|
+
this.isOnList = function() {
|
|
292
|
+
var elStart = dom.ancestor(sc, dom.isList),
|
|
293
|
+
elEnd = dom.ancestor(ec, dom.isList);
|
|
294
|
+
return elStart && (elStart === elEnd);
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
// isOnAnchor: judge whether range is on anchor node or not
|
|
298
|
+
this.isOnAnchor = function() {
|
|
299
|
+
var elStart = dom.ancestor(sc, dom.isAnchor),
|
|
300
|
+
elEnd = dom.ancestor(ec, dom.isAnchor);
|
|
301
|
+
return elStart && (elStart === elEnd);
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
// isCollapsed: judge whether range was collapsed
|
|
305
|
+
this.isCollapsed = function() { return sc === ec && so === eo; };
|
|
306
|
+
|
|
307
|
+
// insertNode
|
|
308
|
+
this.insertNode = function(node) {
|
|
309
|
+
var nativeRng = nativeRange();
|
|
310
|
+
if (bW3CRangeSupport) {
|
|
311
|
+
nativeRng.insertNode(node);
|
|
312
|
+
} // TODO: IE8
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
// surroundContents
|
|
316
|
+
this.surroundContents = function(sNodeName) {
|
|
317
|
+
var node = $('<' + sNodeName + ' />')[0];
|
|
318
|
+
var nativeRng = nativeRange();
|
|
319
|
+
if (bW3CRangeSupport) {
|
|
320
|
+
nativeRng.surroundContents(node);
|
|
321
|
+
} // TODO: IE8
|
|
322
|
+
|
|
323
|
+
return node;
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
this.toString = function() {
|
|
327
|
+
var nativeRng = nativeRange();
|
|
328
|
+
if (bW3CRangeSupport) {
|
|
329
|
+
return nativeRng.toString();
|
|
330
|
+
} // TODO: IE8
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
//bookmark: offsetPath bookmark
|
|
334
|
+
this.bookmark = function(elEditable) {
|
|
335
|
+
return {
|
|
336
|
+
s: { path: dom.makeOffsetPath(elEditable, sc), offset: so },
|
|
337
|
+
e: { path: dom.makeOffsetPath(elEditable, ec), offset: eo }
|
|
338
|
+
};
|
|
339
|
+
};
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
// createRangeFromBookmark
|
|
343
|
+
var createRangeFromBookmark = function(elEditable, bookmark) {
|
|
344
|
+
return new Range(dom.fromOffsetPath(elEditable, bookmark.s.path),
|
|
345
|
+
bookmark.s.offset,
|
|
346
|
+
dom.fromOffsetPath(elEditable, bookmark.e.path),
|
|
347
|
+
bookmark.e.offset);
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Style
|
|
352
|
+
*/
|
|
353
|
+
var Style = function() {
|
|
354
|
+
// font level style
|
|
355
|
+
this.styleFont = function(rng, oStyle) {
|
|
356
|
+
//TODO: complete styleFont later only works for webkit
|
|
357
|
+
//rng.splitInline();
|
|
358
|
+
var elSpan = rng.surroundContents('span');
|
|
359
|
+
$.each(oStyle, function(sKey, sValue) {
|
|
360
|
+
elSpan.style[sKey] = sValue;
|
|
361
|
+
});
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
// para level style
|
|
365
|
+
this.stylePara = function(rng, oStyle) {
|
|
366
|
+
var aPara = rng.listPara();
|
|
367
|
+
$.each(aPara, function(idx, elPara) {
|
|
368
|
+
$.each(oStyle, function(sKey, sValue) {
|
|
369
|
+
elPara.style[sKey] = sValue;
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
// get current style, elTarget: target element on event.
|
|
375
|
+
this.current = function(rng, elTarget) {
|
|
376
|
+
var welCont = $(dom.isText(rng.sc) ? rng.sc.parentNode : rng.sc);
|
|
377
|
+
var oStyle = welCont.css(['font-size', 'font-weight', 'font-style',
|
|
378
|
+
'text-decoration', 'text-align',
|
|
379
|
+
'list-style-type', 'line-height']) || {};
|
|
380
|
+
|
|
381
|
+
oStyle['font-size'] = parseInt(oStyle['font-size']);
|
|
382
|
+
|
|
383
|
+
// FF font-weight patch(number to 'bold' or 'normal')
|
|
384
|
+
if (!isNaN(parseInt(oStyle['font-weight']))) {
|
|
385
|
+
oStyle['font-weight'] = oStyle['font-weight'] > 400 ? 'bold' : 'normal';
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// list-style-type to list-style(unordered, ordered)
|
|
389
|
+
if (!rng.isOnList()) {
|
|
390
|
+
oStyle['list-style'] = 'none';
|
|
391
|
+
} else {
|
|
392
|
+
var aOrderedType = ['circle', 'disc', 'disc-leading-zero', 'square'];
|
|
393
|
+
var bUnordered = $.inArray(oStyle['list-style-type'], aOrderedType) > -1;
|
|
394
|
+
oStyle['list-style'] = bUnordered ? 'unordered' : 'ordered';
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
var elPara = dom.ancestor(rng.sc, dom.isPara);
|
|
398
|
+
if (elPara && elPara.style['line-height']) {
|
|
399
|
+
oStyle['line-height'] = elPara.style.lineHeight;
|
|
400
|
+
} else {
|
|
401
|
+
var lineHeight = parseInt(oStyle['line-height']) / parseInt(oStyle['font-size']);
|
|
402
|
+
oStyle['line-height'] = lineHeight.toFixed(1);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
oStyle.image = dom.isImg(elTarget) && elTarget;
|
|
406
|
+
oStyle.anchor = rng.isOnAnchor() && dom.ancestor(rng.sc, dom.isAnchor);
|
|
407
|
+
oStyle.aAncestor = dom.listAncestor(rng.sc, dom.isEditable);
|
|
408
|
+
|
|
409
|
+
return oStyle;
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* History
|
|
415
|
+
*/
|
|
416
|
+
var History = function() {
|
|
417
|
+
var aUndo = [], aRedo = [];
|
|
418
|
+
|
|
419
|
+
var makeSnap = function(welEditable) {
|
|
420
|
+
var elEditable = welEditable[0], rng = new Range();
|
|
421
|
+
return {
|
|
422
|
+
contents: welEditable.html(), bookmark: rng.bookmark(elEditable),
|
|
423
|
+
scrollTop: welEditable.scrollTop()
|
|
424
|
+
};
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
var applySnap = function(welEditable, oSnap) {
|
|
428
|
+
welEditable.html(oSnap.contents).scrollTop(oSnap.scrollTop);
|
|
429
|
+
createRangeFromBookmark(welEditable[0], oSnap.bookmark).select();
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
this.undo = function(welEditable) {
|
|
433
|
+
var oSnap = makeSnap(welEditable);
|
|
434
|
+
if (aUndo.length === 0) { return; }
|
|
435
|
+
applySnap(welEditable, aUndo.pop()), aRedo.push(oSnap);
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
this.redo = function(welEditable) {
|
|
439
|
+
var oSnap = makeSnap(welEditable);
|
|
440
|
+
if (aRedo.length === 0) { return; }
|
|
441
|
+
applySnap(welEditable, aRedo.pop()), aUndo.push(oSnap);
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
this.recordUndo = function(welEditable) {
|
|
445
|
+
aRedo = [], aUndo.push(makeSnap(welEditable));
|
|
446
|
+
};
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Editor
|
|
451
|
+
*/
|
|
452
|
+
var Editor = function() {
|
|
453
|
+
//currentStyle
|
|
454
|
+
var style = new Style();
|
|
455
|
+
this.currentStyle = function(elTarget) {
|
|
456
|
+
if (document.getSelection().rangeCount == 0) { return null; }
|
|
457
|
+
return style.current((new Range()), elTarget);
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
// undo
|
|
461
|
+
this.undo = function(welEditable) {
|
|
462
|
+
welEditable.data('NoteHistory').undo(welEditable);
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
// redo
|
|
466
|
+
this.redo = function(welEditable) {
|
|
467
|
+
welEditable.data('NoteHistory').redo(welEditable);
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
// recordUndo
|
|
471
|
+
var recordUndo = this.recordUndo = function(welEditable) {
|
|
472
|
+
welEditable.data('NoteHistory').recordUndo(welEditable);
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
// native commands(with execCommand)
|
|
476
|
+
var aCmd = ['bold', 'italic', 'underline', 'justifyLeft', 'justifyCenter',
|
|
477
|
+
'justifyRight', 'justifyFull', 'insertOrderedList',
|
|
478
|
+
'insertUnorderedList', 'indent', 'outdent', 'formatBlock',
|
|
479
|
+
'removeFormat', 'backColor', 'foreColor', 'insertImage',
|
|
480
|
+
'insertHorizontalRule'];
|
|
481
|
+
|
|
482
|
+
for (var idx = 0, len=aCmd.length; idx < len; idx ++) {
|
|
483
|
+
this[aCmd[idx]] = function(sCmd) {
|
|
484
|
+
return function(welEditable, sValue) {
|
|
485
|
+
recordUndo(welEditable);
|
|
486
|
+
document.execCommand(sCmd, false, sValue);
|
|
487
|
+
};
|
|
488
|
+
}(aCmd[idx]);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
this.fontSize = function(welEditable, sValue) {
|
|
492
|
+
recordUndo(welEditable);
|
|
493
|
+
document.execCommand('fontSize', false, 3);
|
|
494
|
+
// <font size='3'> to <font style='font-size={sValue}px;'>
|
|
495
|
+
var welFont = welEditable.find('font[size=3]');
|
|
496
|
+
welFont.removeAttr('size').css('font-size', sValue + 'px');
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
this.lineHeight = function(welEditable, sValue) {
|
|
500
|
+
recordUndo(welEditable);
|
|
501
|
+
style.stylePara(new Range(), {lineHeight: sValue});
|
|
502
|
+
};
|
|
503
|
+
|
|
504
|
+
this.unlink = function(welEditable) {
|
|
505
|
+
var rng = new Range();
|
|
506
|
+
if (rng.isOnAnchor()) {
|
|
507
|
+
recordUndo(welEditable);
|
|
508
|
+
var elAnchor = dom.ancestor(rng.sc, dom.isAnchor);
|
|
509
|
+
rng = new Range(elAnchor, 0, elAnchor, 1);
|
|
510
|
+
rng.select();
|
|
511
|
+
document.execCommand('unlink');
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
this.setLinkDialog = function(welEditable, fnShowDialog) {
|
|
516
|
+
var rng = new Range();
|
|
517
|
+
if (rng.isOnAnchor()) {
|
|
518
|
+
var elAnchor = dom.ancestor(rng.sc, dom.isAnchor);
|
|
519
|
+
rng = new Range(elAnchor, 0, elAnchor, 1);
|
|
520
|
+
}
|
|
521
|
+
fnShowDialog({
|
|
522
|
+
range: rng,
|
|
523
|
+
text: rng.toString(),
|
|
524
|
+
url: rng.isOnAnchor() ? dom.ancestor(rng.sc, dom.isAnchor).href : ""
|
|
525
|
+
}, function(sLinkUrl) {
|
|
526
|
+
rng.select();
|
|
527
|
+
recordUndo(welEditable);
|
|
528
|
+
if (sLinkUrl.toLowerCase().indexOf("http://") !== 0) {
|
|
529
|
+
sLinkUrl = "http://" + sLinkUrl;
|
|
530
|
+
}
|
|
531
|
+
document.execCommand('createlink', false, sLinkUrl);
|
|
532
|
+
});
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
this.color = function(welEditable, sObjColor) {
|
|
536
|
+
var oColor = JSON.parse(sObjColor);
|
|
537
|
+
this.foreColor(welEditable, oColor.foreColor);
|
|
538
|
+
this.backColor(welEditable, oColor.backColor);
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
this.insertTable = function(welEditable, sDim) {
|
|
542
|
+
recordUndo(welEditable);
|
|
543
|
+
var aDim = sDim.split('x');
|
|
544
|
+
var nCol = aDim[0], nRow = aDim[1];
|
|
545
|
+
|
|
546
|
+
var aTD = [], sTD;
|
|
547
|
+
var sWhitespace = bMSIE ? ' ' : '<br/>';
|
|
548
|
+
for (var idxCol = 0; idxCol < nCol; idxCol++) {
|
|
549
|
+
aTD.push('<td>' + sWhitespace + '</td>');
|
|
550
|
+
}
|
|
551
|
+
sTD = aTD.join('');
|
|
552
|
+
|
|
553
|
+
var aTR = [], sTR;
|
|
554
|
+
for (var idxRow = 0; idxRow < nRow; idxRow++) {
|
|
555
|
+
aTR.push('<tr>' + sTD + '</tr>');
|
|
556
|
+
}
|
|
557
|
+
sTR = aTR.join('');
|
|
558
|
+
var sTable = '<table class="table table-bordered">' + sTR + '</table>';
|
|
559
|
+
(new Range()).insertNode($(sTable)[0]);
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
this.float = function(welEditable, sValue, elTarget) {
|
|
563
|
+
recordUndo(welEditable);
|
|
564
|
+
elTarget.style.cssFloat = sValue;
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
this.resize = function(welEditable, sValue, elTarget) {
|
|
568
|
+
recordUndo(welEditable);
|
|
569
|
+
elTarget.style.width = welEditable.width() * sValue + 'px';
|
|
570
|
+
elTarget.style.height = "";
|
|
571
|
+
};
|
|
572
|
+
|
|
573
|
+
this.resizeTo = function(pos, elTarget) {
|
|
574
|
+
elTarget.style.width = pos.x + 'px';
|
|
575
|
+
elTarget.style.height = pos.y + 'px';
|
|
576
|
+
};
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Toolbar
|
|
581
|
+
*/
|
|
582
|
+
var Toolbar = function() {
|
|
583
|
+
this.update = function(welToolbar, oStyle) {
|
|
584
|
+
//handle selectbox for fontsize, lineHeight
|
|
585
|
+
var checkDropdownMenu = function(welBtn, nValue) {
|
|
586
|
+
welBtn.find('.dropdown-menu li a').each(function() {
|
|
587
|
+
var bChecked = $(this).attr('data-value') == nValue;
|
|
588
|
+
this.className = bChecked ? 'checked' : '';
|
|
589
|
+
});
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
var welFontsize = welToolbar.find('.note-fontsize');
|
|
593
|
+
welFontsize.find('.note-current-fontsize').html(oStyle['font-size']);
|
|
594
|
+
checkDropdownMenu(welFontsize, parseFloat(oStyle['font-size']));
|
|
595
|
+
|
|
596
|
+
var welLineHeight = welToolbar.find('.note-line-height');
|
|
597
|
+
checkDropdownMenu(welLineHeight, parseFloat(oStyle['line-height']));
|
|
598
|
+
|
|
599
|
+
//check button state
|
|
600
|
+
var btnState = function(sSelector, pred) {
|
|
601
|
+
var welBtn = welToolbar.find(sSelector);
|
|
602
|
+
welBtn[pred() ? 'addClass' : 'removeClass']('active');
|
|
603
|
+
};
|
|
604
|
+
|
|
605
|
+
btnState('button[data-event="bold"]', function() {
|
|
606
|
+
return oStyle['font-weight'] === 'bold';
|
|
607
|
+
});
|
|
608
|
+
btnState('button[data-event="italic"]', function() {
|
|
609
|
+
return oStyle['font-style'] === 'italic';
|
|
610
|
+
});
|
|
611
|
+
btnState('button[data-event="underline"]', function() {
|
|
612
|
+
return oStyle['text-decoration'] === 'underline';
|
|
613
|
+
});
|
|
614
|
+
btnState('button[data-event="justifyLeft"]', function() {
|
|
615
|
+
return oStyle['text-align'] === 'left' || oStyle['text-align'] === 'start';
|
|
616
|
+
});
|
|
617
|
+
btnState('button[data-event="justifyCenter"]', function() {
|
|
618
|
+
return oStyle['text-align'] === 'center';
|
|
619
|
+
});
|
|
620
|
+
btnState('button[data-event="justifyRight"]', function() {
|
|
621
|
+
return oStyle['text-align'] === 'right';
|
|
622
|
+
});
|
|
623
|
+
btnState('button[data-event="justifyFull"]', function() {
|
|
624
|
+
return oStyle['text-align'] === 'justify';
|
|
625
|
+
});
|
|
626
|
+
btnState('button[data-event="insertUnorderedList"]', function() {
|
|
627
|
+
return oStyle['list-style'] === 'unordered';
|
|
628
|
+
});
|
|
629
|
+
btnState('button[data-event="insertOrderedList"]', function() {
|
|
630
|
+
return oStyle['list-style'] === 'ordered';
|
|
631
|
+
});
|
|
632
|
+
};
|
|
633
|
+
|
|
634
|
+
this.updateRecentColor = function(elBtn, sEvent, sValue) {
|
|
635
|
+
var welColor = $(elBtn).closest('.note-color');
|
|
636
|
+
var welRecentColor = welColor.find('.note-recent-color');
|
|
637
|
+
var oColor = JSON.parse(welRecentColor.attr('data-value'));
|
|
638
|
+
oColor[sEvent] = sValue;
|
|
639
|
+
welRecentColor.attr('data-value', JSON.stringify(oColor));
|
|
640
|
+
var sKey = sEvent === "backColor" ? 'background-color' : 'color';
|
|
641
|
+
welRecentColor.find('i').css(sKey, sValue);
|
|
642
|
+
};
|
|
643
|
+
};
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* Popover
|
|
647
|
+
*/
|
|
648
|
+
var Popover = function() {
|
|
649
|
+
this.update = function(welPopover, oStyle) {
|
|
650
|
+
var welLinkPopover = welPopover.find('.note-link-popover'),
|
|
651
|
+
welImagePopover = welPopover.find('.note-image-popover');
|
|
652
|
+
if (oStyle.anchor) {
|
|
653
|
+
var welAnchor = welLinkPopover.find('a');
|
|
654
|
+
welAnchor.attr('href', oStyle.anchor.href).html(oStyle.anchor.href);
|
|
655
|
+
|
|
656
|
+
var rect = oStyle.anchor.getBoundingClientRect();
|
|
657
|
+
welLinkPopover.css({
|
|
658
|
+
display: 'block',
|
|
659
|
+
left: rect.left,
|
|
660
|
+
top: $(document).scrollTop() + rect.bottom
|
|
661
|
+
});
|
|
662
|
+
} else {
|
|
663
|
+
welLinkPopover.hide();
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
if (oStyle.image) {
|
|
667
|
+
var rect = oStyle.image.getBoundingClientRect();
|
|
668
|
+
welImagePopover.css({
|
|
669
|
+
display: 'block',
|
|
670
|
+
left: rect.left,
|
|
671
|
+
top: $(document).scrollTop() + rect.bottom
|
|
672
|
+
});
|
|
673
|
+
} else {
|
|
674
|
+
welImagePopover.hide();
|
|
675
|
+
}
|
|
676
|
+
};
|
|
677
|
+
|
|
678
|
+
this.hide = function(welPopover) {
|
|
679
|
+
welPopover.children().hide();
|
|
680
|
+
};
|
|
681
|
+
};
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* Handle
|
|
685
|
+
*/
|
|
686
|
+
var Handle = function() {
|
|
687
|
+
this.update = function(welHandle, oStyle) {
|
|
688
|
+
var welSelection = welHandle.find('.note-control-selection');
|
|
689
|
+
if (oStyle.image) {
|
|
690
|
+
var rect = oStyle.image.getBoundingClientRect();
|
|
691
|
+
welSelection.css({
|
|
692
|
+
display: 'block',
|
|
693
|
+
left: rect.left + 'px',
|
|
694
|
+
top: $(document).scrollTop() + rect.top + 'px',
|
|
695
|
+
width: rect.width + 'px',
|
|
696
|
+
height: rect.height + 'px'
|
|
697
|
+
}).data('target', oStyle.image); // save current image element.
|
|
698
|
+
var sSizing = rect.width + 'x' + rect.height;
|
|
699
|
+
welSelection.find('.note-control-selection-info').text(sSizing);
|
|
700
|
+
} else {
|
|
701
|
+
welSelection.hide();
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
|
|
705
|
+
this.hide = function(welHandle) {
|
|
706
|
+
welHandle.children().hide();
|
|
707
|
+
};
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
/**
|
|
711
|
+
* Dialog
|
|
712
|
+
*/
|
|
713
|
+
var Dialog = function() {
|
|
714
|
+
this.showImageDialog = function(welDialog, hDropImage, fnInsertImages) {
|
|
715
|
+
var welImageDialog = welDialog.find('.note-image-dialog');
|
|
716
|
+
var welDropzone = welDialog.find('.note-dropzone'),
|
|
717
|
+
welImageInput = welDialog.find('.note-image-input');
|
|
718
|
+
|
|
719
|
+
welImageDialog.on('shown', function(e) {
|
|
720
|
+
welDropzone.on('dragenter dragover dragleave', false);
|
|
721
|
+
welDropzone.on('drop', function(e) {
|
|
722
|
+
hDropImage(e); welImageDialog.modal('hide');
|
|
723
|
+
});
|
|
724
|
+
welImageInput.on('change', function() {
|
|
725
|
+
fnInsertImages(this.files); $(this).val('');
|
|
726
|
+
welImageDialog.modal('hide');
|
|
727
|
+
});
|
|
728
|
+
}).on('hidden', function(e) {
|
|
729
|
+
welDropzone.off('dragenter dragover dragleave drop');
|
|
730
|
+
welImageInput.off('change');
|
|
731
|
+
}).modal('show');
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
this.showLinkDialog = function(welDialog, linkInfo, callback) {
|
|
735
|
+
var welLinkDialog = welDialog.find('.note-link-dialog');
|
|
736
|
+
var welLinkText = welLinkDialog.find('.note-link-text'),
|
|
737
|
+
welLinkUrl = welLinkDialog.find('.note-link-url'),
|
|
738
|
+
welLinkBtn = welLinkDialog.find('.note-link-btn');
|
|
739
|
+
|
|
740
|
+
welLinkDialog.on('shown', function(e) {
|
|
741
|
+
welLinkText.html(linkInfo.text);
|
|
742
|
+
welLinkUrl.val(linkInfo.url).keyup(function(event) {
|
|
743
|
+
if (welLinkUrl.val()) {
|
|
744
|
+
welLinkBtn.removeClass('disabled').attr('disabled', false);
|
|
745
|
+
} else {
|
|
746
|
+
welLinkBtn.addClass('disabled').attr('disabled', true);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
if (!linkInfo.text) { welLinkText.html(welLinkUrl.val()); };
|
|
750
|
+
}).trigger('focus');
|
|
751
|
+
welLinkBtn.click(function(event) {
|
|
752
|
+
welLinkDialog.modal('hide'); //hide and createLink (ie9+)
|
|
753
|
+
callback(welLinkUrl.val());
|
|
754
|
+
event.preventDefault();
|
|
755
|
+
});
|
|
756
|
+
}).on('hidden', function(e) {
|
|
757
|
+
welLinkUrl.off('keyup');
|
|
758
|
+
welLinkDialog.off('shown hidden');
|
|
759
|
+
welLinkBtn.off('click');
|
|
760
|
+
}).modal('show');
|
|
761
|
+
};
|
|
762
|
+
};
|
|
763
|
+
|
|
764
|
+
/**
|
|
765
|
+
* EventHandler
|
|
766
|
+
*
|
|
767
|
+
* handle mouse & key event on note
|
|
768
|
+
*/
|
|
769
|
+
var EventHandler = function() {
|
|
770
|
+
var editor = new Editor();
|
|
771
|
+
var toolbar = new Toolbar(), popover = new Popover();
|
|
772
|
+
var handle = new Handle(), dialog = new Dialog();
|
|
773
|
+
|
|
774
|
+
var key = { BACKSPACE: 8, TAB: 9, ENTER: 13, SPACE: 32,
|
|
775
|
+
NUM0: 48, NUM1: 49, NUM4: 52, NUM7: 55, NUM8: 56,
|
|
776
|
+
B: 66, E: 69, I: 73, J: 74, K: 75, L: 76, R: 82,
|
|
777
|
+
U: 85, Y: 89, Z: 90, BACKSLACH: 220 };
|
|
778
|
+
|
|
779
|
+
// makeLayoutInfo from editor's descendant node.
|
|
780
|
+
var makeLayoutInfo = function(descendant) {
|
|
781
|
+
var welEditor = $(descendant).closest('.note-editor');
|
|
782
|
+
return {
|
|
783
|
+
editor: function() { return welEditor; },
|
|
784
|
+
editable: function() { return welEditor.find('.note-editable'); },
|
|
785
|
+
toolbar: function() { return welEditor.find('.note-toolbar'); },
|
|
786
|
+
popover: function() { return welEditor.find('.note-popover'); },
|
|
787
|
+
handle: function() { return welEditor.find('.note-handle'); },
|
|
788
|
+
dialog: function() { return welEditor.find('.note-dialog'); }
|
|
789
|
+
};
|
|
790
|
+
};
|
|
791
|
+
|
|
792
|
+
var hKeydown = function(event) {
|
|
793
|
+
var bCmd = bMac ? event.metaKey : event.ctrlKey,
|
|
794
|
+
bShift = event.shiftKey, keyCode = event.keyCode;
|
|
795
|
+
|
|
796
|
+
// optimize
|
|
797
|
+
var oLayoutInfo = (bCmd || bShift) ? makeLayoutInfo(event.target) : null;
|
|
798
|
+
|
|
799
|
+
if (bCmd && ((bShift && keyCode === key.Z) || keyCode === key.Y)) {
|
|
800
|
+
editor.redo(oLayoutInfo.editable());
|
|
801
|
+
} else if (bCmd && keyCode === key.Z) {
|
|
802
|
+
editor.undo(oLayoutInfo.editable());
|
|
803
|
+
} else if (bCmd && keyCode === key.B) {
|
|
804
|
+
editor.bold(oLayoutInfo.editable());
|
|
805
|
+
} else if (bCmd && keyCode === key.I) {
|
|
806
|
+
editor.italic(oLayoutInfo.editable());
|
|
807
|
+
} else if (bCmd && keyCode === key.U) {
|
|
808
|
+
editor.underline(oLayoutInfo.editable());
|
|
809
|
+
} else if (bCmd && keyCode === key.BACKSLACH) {
|
|
810
|
+
editor.removeFormat(oLayoutInfo.editable());
|
|
811
|
+
} else if (bCmd && keyCode === key.K) {
|
|
812
|
+
editor.setLinkDialog(oLayoutInfo.editable(), function(linkInfo, cb) {
|
|
813
|
+
dialog.showLinkDialog(oLayoutInfo.dialog(), linkInfo, cb);
|
|
814
|
+
});
|
|
815
|
+
} else if (bCmd && bShift && keyCode === key.L) {
|
|
816
|
+
editor.justifyLeft(oLayoutInfo.editable());
|
|
817
|
+
} else if (bCmd && bShift && keyCode === key.E) {
|
|
818
|
+
editor.justifyCenter(oLayoutInfo.editable());
|
|
819
|
+
} else if (bCmd && bShift && keyCode === key.R) {
|
|
820
|
+
editor.justifyRight(oLayoutInfo.editable());
|
|
821
|
+
} else if (bCmd && bShift && keyCode === key.J) {
|
|
822
|
+
editor.justifyFull(oLayoutInfo.editable());
|
|
823
|
+
} else if (bCmd && bShift && keyCode === key.NUM7) {
|
|
824
|
+
editor.insertUnorderedList(oLayoutInfo.editable());
|
|
825
|
+
} else if (bCmd && bShift && keyCode === key.NUM8) {
|
|
826
|
+
editor.insertOrderedList(oLayoutInfo.editable());
|
|
827
|
+
} else if (bShift && keyCode === key.TAB) { // shift + tab
|
|
828
|
+
editor.outdent(oLayoutInfo.editable());
|
|
829
|
+
} else if (keyCode === key.TAB) { // tab
|
|
830
|
+
editor.indent(oLayoutInfo.editable());
|
|
831
|
+
} else if (bCmd && keyCode === key.NUM0) { // formatBlock Paragraph
|
|
832
|
+
editor.formatBlock(oLayoutInfo.editable(), 'P');
|
|
833
|
+
} else if (bCmd && (key.NUM1 <= keyCode && keyCode <= key.NUM4)) {
|
|
834
|
+
var sHeading = 'H' + String.fromCharCode(keyCode); // H1~H4
|
|
835
|
+
editor.formatBlock(oLayoutInfo.editable(), sHeading);
|
|
836
|
+
} else if (bCmd && keyCode === key.ENTER) {
|
|
837
|
+
editor.insertHorizontalRule(oLayoutInfo.editable());
|
|
838
|
+
} else {
|
|
839
|
+
if (keyCode === key.BACKSPACE || keyCode === key.ENTER ||
|
|
840
|
+
keyCode === key.SPACE) {
|
|
841
|
+
editor.recordUndo(makeLayoutInfo(event.target).editable());
|
|
842
|
+
}
|
|
843
|
+
return; // not matched
|
|
844
|
+
}
|
|
845
|
+
event.preventDefault(); //prevent default event for FF
|
|
846
|
+
};
|
|
847
|
+
|
|
848
|
+
var insertImages = function(welEditable, files) {
|
|
849
|
+
$.each(files, function(idx, file) {
|
|
850
|
+
var fileReader = new FileReader;
|
|
851
|
+
fileReader.onload = function(event) {
|
|
852
|
+
editor.insertImage(welEditable, event.target.result); // sURL
|
|
853
|
+
};
|
|
854
|
+
fileReader.readAsDataURL(file);
|
|
855
|
+
});
|
|
856
|
+
};
|
|
857
|
+
|
|
858
|
+
var hDropImage = function(event) {
|
|
859
|
+
var dataTransfer = event.originalEvent.dataTransfer;
|
|
860
|
+
if (dataTransfer && dataTransfer.files) {
|
|
861
|
+
var oLayoutInfo = makeLayoutInfo(event.currentTarget || event.target);
|
|
862
|
+
insertImages(oLayoutInfo.editable(), dataTransfer.files);
|
|
863
|
+
}
|
|
864
|
+
event.stopPropagation();
|
|
865
|
+
event.preventDefault();
|
|
866
|
+
};
|
|
867
|
+
|
|
868
|
+
var hMousedown = function(event) {
|
|
869
|
+
//preventDefault Selection for FF, IE8+
|
|
870
|
+
if (dom.isImg(event.target)) { event.preventDefault(); };
|
|
871
|
+
};
|
|
872
|
+
|
|
873
|
+
var hToolbarAndPopoverUpdate = function(event) {
|
|
874
|
+
var oLayoutInfo = makeLayoutInfo(event.currentTarget || event.target);
|
|
875
|
+
|
|
876
|
+
var oStyle = editor.currentStyle(event.target);
|
|
877
|
+
if (!oStyle) { return; }
|
|
878
|
+
toolbar.update(oLayoutInfo.toolbar(), oStyle);
|
|
879
|
+
popover.update(oLayoutInfo.popover(), oStyle);
|
|
880
|
+
handle.update(oLayoutInfo.handle(), oStyle);
|
|
881
|
+
};
|
|
882
|
+
|
|
883
|
+
var hScroll = function(event) {
|
|
884
|
+
var oLayoutInfo = makeLayoutInfo(event.currentTarget || event.target);
|
|
885
|
+
//hide popover and handle when scrolled
|
|
886
|
+
popover.hide(oLayoutInfo.popover());
|
|
887
|
+
handle.hide(oLayoutInfo.handle());
|
|
888
|
+
};
|
|
889
|
+
|
|
890
|
+
var hHandleMousedown = function(event) {
|
|
891
|
+
if (dom.isControlSizing(event.target)) {
|
|
892
|
+
var oLayoutInfo = makeLayoutInfo(event.target),
|
|
893
|
+
welHandle = oLayoutInfo.handle(), welPopover = oLayoutInfo.popover(),
|
|
894
|
+
welEditable = oLayoutInfo.editable(), welEditor = oLayoutInfo.editor();
|
|
895
|
+
|
|
896
|
+
var elTarget = welHandle.find('.note-control-selection').data('target');
|
|
897
|
+
var posStart = $(elTarget).offset(),
|
|
898
|
+
scrollTop = $(document).scrollTop(), posDistance;
|
|
899
|
+
welEditor.on('mousemove', function(event) {
|
|
900
|
+
posDistance = {x: event.clientX - posStart.left,
|
|
901
|
+
y: event.clientY - (posStart.top - scrollTop)};
|
|
902
|
+
editor.resizeTo(posDistance, elTarget);
|
|
903
|
+
handle.update(welHandle, {image: elTarget});
|
|
904
|
+
popover.update(welPopover, {image: elTarget});
|
|
905
|
+
}).on('mouseup', function() {
|
|
906
|
+
welEditor.off('mousemove').off('mouseup');
|
|
907
|
+
});
|
|
908
|
+
|
|
909
|
+
editor.recordUndo(welEditable);
|
|
910
|
+
event.stopPropagation(); event.preventDefault();
|
|
911
|
+
}
|
|
912
|
+
};
|
|
913
|
+
|
|
914
|
+
var hToolbarAndPopoverMousedown = function(event) {
|
|
915
|
+
// prevent default event when insertTable (FF, Webkit)
|
|
916
|
+
var welBtn = $(event.target).closest('[data-event]');
|
|
917
|
+
if (welBtn.length > 0) { event.preventDefault(); }
|
|
918
|
+
};
|
|
919
|
+
|
|
920
|
+
var hToolbarAndPopoverClick = function(event) {
|
|
921
|
+
var welBtn = $(event.target).closest('[data-event]');
|
|
922
|
+
|
|
923
|
+
if (welBtn.length > 0) {
|
|
924
|
+
var sEvent = welBtn.attr('data-event'),
|
|
925
|
+
sValue = welBtn.attr('data-value');
|
|
926
|
+
|
|
927
|
+
var oLayoutInfo = makeLayoutInfo(event.target);
|
|
928
|
+
var welDialog = oLayoutInfo.dialog(),
|
|
929
|
+
welEditable = oLayoutInfo.editable();
|
|
930
|
+
|
|
931
|
+
// before command
|
|
932
|
+
var elTarget;
|
|
933
|
+
if ($.inArray(sEvent, ['resize', 'float']) !== -1) {
|
|
934
|
+
var welHandle = oLayoutInfo.handle();
|
|
935
|
+
var welSelection = welHandle.find('.note-control-selection');
|
|
936
|
+
elTarget = welSelection.data('target');
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
if (editor[sEvent]) { // on command
|
|
940
|
+
welEditable.trigger('focus');
|
|
941
|
+
editor[sEvent](welEditable, sValue, elTarget);
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
// after command
|
|
945
|
+
if ($.inArray(sEvent, ["backColor", "foreColor"]) !== -1) {
|
|
946
|
+
toolbar.updateRecentColor(welBtn[0], sEvent, sValue);
|
|
947
|
+
} else if (sEvent === "showLinkDialog") { // popover to dialog
|
|
948
|
+
editor.setLinkDialog(welEditable, function(linkInfo, cb) {
|
|
949
|
+
dialog.showLinkDialog(welDialog, linkInfo, cb);
|
|
950
|
+
});
|
|
951
|
+
} else if (sEvent === "showImageDialog") {
|
|
952
|
+
dialog.showImageDialog(welDialog, hDropImage, function(files) {
|
|
953
|
+
insertImages(welEditable, files);
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
hToolbarAndPopoverUpdate(event);
|
|
958
|
+
}
|
|
959
|
+
};
|
|
960
|
+
|
|
961
|
+
var PX_PER_EM = 18;
|
|
962
|
+
var hDimensionPickerMove = function(event) {
|
|
963
|
+
var welPicker = $(event.target.parentNode); // target is mousecatcher
|
|
964
|
+
var welDimensionDisplay = welPicker.next();
|
|
965
|
+
var welCatcher = welPicker.find('.note-dimension-picker-mousecatcher');
|
|
966
|
+
var welHighlighted = welPicker.find('.note-dimension-picker-highlighted');
|
|
967
|
+
var welUnhighlighted = welPicker.find('.note-dimension-picker-unhighlighted');
|
|
968
|
+
var posOffset;
|
|
969
|
+
if (event.offsetX === undefined) {
|
|
970
|
+
// HTML5 with jQuery - e.offsetX is undefined in Firefox
|
|
971
|
+
var posCatcher = $(event.target).offset();
|
|
972
|
+
posOffset = {x: event.pageX - posCatcher.left,
|
|
973
|
+
y: event.pageY - posCatcher.top};
|
|
974
|
+
} else {
|
|
975
|
+
posOffset = {x: event.offsetX, y: event.offsetY};
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
var dim = {c: Math.ceil(posOffset.x / PX_PER_EM) || 1,
|
|
979
|
+
r: Math.ceil(posOffset.y / PX_PER_EM) || 1};
|
|
980
|
+
|
|
981
|
+
welHighlighted.css({ width: dim.c +'em', height: dim.r + 'em' });
|
|
982
|
+
welCatcher.attr('data-value', dim.c + 'x' + dim.r);
|
|
983
|
+
|
|
984
|
+
if (3 < dim.c && dim.c < 20) { // 5~20
|
|
985
|
+
welUnhighlighted.css({ width: dim.c + 1 + 'em'});
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
if (3 < dim.r && dim.r < 20) { // 5~20
|
|
989
|
+
welUnhighlighted.css({ height: dim.r + 1 + 'em'});
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
welDimensionDisplay.html(dim.c + ' x ' + dim.r);
|
|
993
|
+
};
|
|
994
|
+
|
|
995
|
+
this.attach = function(oLayoutInfo) {
|
|
996
|
+
oLayoutInfo.editable.on('keydown', hKeydown);
|
|
997
|
+
oLayoutInfo.editable.on('mousedown', hMousedown);
|
|
998
|
+
oLayoutInfo.editable.on('keyup mouseup', hToolbarAndPopoverUpdate);
|
|
999
|
+
oLayoutInfo.editable.on('scroll', hScroll);
|
|
1000
|
+
//TODO: handle Drag point
|
|
1001
|
+
oLayoutInfo.editable.on('dragenter dragover dragleave', false);
|
|
1002
|
+
oLayoutInfo.editable.on('drop', hDropImage);
|
|
1003
|
+
|
|
1004
|
+
oLayoutInfo.handle.on('mousedown', hHandleMousedown);
|
|
1005
|
+
|
|
1006
|
+
oLayoutInfo.toolbar.on('click', hToolbarAndPopoverClick);
|
|
1007
|
+
oLayoutInfo.popover.on('click', hToolbarAndPopoverClick);
|
|
1008
|
+
oLayoutInfo.toolbar.on('mousedown', hToolbarAndPopoverMousedown);
|
|
1009
|
+
oLayoutInfo.popover.on('mousedown', hToolbarAndPopoverMousedown);
|
|
1010
|
+
|
|
1011
|
+
//toolbar table dimension
|
|
1012
|
+
var welToolbar = oLayoutInfo.toolbar;
|
|
1013
|
+
var welCatcher = welToolbar.find('.note-dimension-picker-mousecatcher');
|
|
1014
|
+
welCatcher.on('mousemove', hDimensionPickerMove);
|
|
1015
|
+
};
|
|
1016
|
+
|
|
1017
|
+
this.dettach = function(oLayoutInfo) {
|
|
1018
|
+
oLayoutInfo.editable.off();
|
|
1019
|
+
oLayoutInfo.toolbar.off();
|
|
1020
|
+
oLayoutInfo.handle.off();
|
|
1021
|
+
oLayoutInfo.popover.off();
|
|
1022
|
+
};
|
|
1023
|
+
};
|
|
1024
|
+
|
|
1025
|
+
/**
|
|
1026
|
+
* Renderer
|
|
1027
|
+
*
|
|
1028
|
+
* rendering toolbar and editable
|
|
1029
|
+
*/
|
|
1030
|
+
var Renderer = function() {
|
|
1031
|
+
var sToolbar = '<div class="note-toolbar btn-toolbar">' +
|
|
1032
|
+
'<div class="note-insert btn-group">' +
|
|
1033
|
+
'<button type="button" class="btn btn-small" title="Picture" data-event="showImageDialog"><i class="icon-picture"></i></button>' +
|
|
1034
|
+
'<button type="button" class="btn btn-small" title="Link" data-event="showLinkDialog" data-shortcut="Ctrl+K" data-mac-shortcut="⌘+K" ><i class="icon-link"></i></button>' +
|
|
1035
|
+
'</div>' +
|
|
1036
|
+
'<div class="note-table btn-group">' +
|
|
1037
|
+
'<button type="button" class="btn btn-small dropdown-toggle" title="Table" data-toggle="dropdown"><i class="icon-table"></i> <span class="caret"></span></button>' +
|
|
1038
|
+
'<ul class="dropdown-menu">' +
|
|
1039
|
+
'<div class="note-dimension-picker">' +
|
|
1040
|
+
'<div class="note-dimension-picker-mousecatcher" data-event="insertTable" data-value="1x1"></div>' +
|
|
1041
|
+
'<div class="note-dimension-picker-highlighted"></div>' +
|
|
1042
|
+
'<div class="note-dimension-picker-unhighlighted"></div>' +
|
|
1043
|
+
'</div>' +
|
|
1044
|
+
'<div class="note-dimension-display"> 1 x 1 </div>' +
|
|
1045
|
+
'</ul>' +
|
|
1046
|
+
'</div>' +
|
|
1047
|
+
'<div class="note-style btn-group">' +
|
|
1048
|
+
'<button type="button" class="btn btn-small dropdown-toggle" title="Style" data-toggle="dropdown"><i class="icon-magic"></i> <span class="caret"></span></button>' +
|
|
1049
|
+
'<ul class="dropdown-menu">' +
|
|
1050
|
+
'<li><a data-event="formatBlock" data-value="p">Paragraph</a></li>' +
|
|
1051
|
+
'<li><a data-event="formatBlock" data-value="blockquote"><blockquote>Quote</blockquote></a></li>' +
|
|
1052
|
+
'<li><a data-event="formatBlock" data-value="pre">Code</a></li>' +
|
|
1053
|
+
'<li><a data-event="formatBlock" data-value="h1"><h1>Header 1</h1></a></li>' +
|
|
1054
|
+
'<li><a data-event="formatBlock" data-value="h2"><h2>Header 2</h2></a></li>' +
|
|
1055
|
+
'<li><a data-event="formatBlock" data-value="h3"><h3>Header 3</h3></a></li>' +
|
|
1056
|
+
'<li><a data-event="formatBlock" data-value="h4"><h4>Header 4</h4></a></li>' +
|
|
1057
|
+
'</ul>' +
|
|
1058
|
+
'</div>' +
|
|
1059
|
+
'<div class="note-fontsize btn-group">' +
|
|
1060
|
+
'<button type="button" class="btn btn-small dropdown-toggle" data-toggle="dropdown" title="Font Size"><span class="note-current-fontsize">11</span> <b class="caret"></b></button>' +
|
|
1061
|
+
'<ul class="dropdown-menu">' +
|
|
1062
|
+
'<li><a data-event="fontSize" data-value="8"><i class="icon-ok"></i> 8</a></li>' +
|
|
1063
|
+
'<li><a data-event="fontSize" data-value="9"><i class="icon-ok"></i> 9</a></li>' +
|
|
1064
|
+
'<li><a data-event="fontSize" data-value="10"><i class="icon-ok"></i> 10</a></li>' +
|
|
1065
|
+
'<li><a data-event="fontSize" data-value="11"><i class="icon-ok"></i> 11</a></li>' +
|
|
1066
|
+
'<li><a data-event="fontSize" data-value="12"><i class="icon-ok"></i> 12</a></li>' +
|
|
1067
|
+
'<li><a data-event="fontSize" data-value="14"><i class="icon-ok"></i> 14</a></li>' +
|
|
1068
|
+
'<li><a data-event="fontSize" data-value="18"><i class="icon-ok"></i> 18</a></li>' +
|
|
1069
|
+
'<li><a data-event="fontSize" data-value="24"><i class="icon-ok"></i> 24</a></li>' +
|
|
1070
|
+
'<li><a data-event="fontSize" data-value="36"><i class="icon-ok"></i> 36</a></li>' +
|
|
1071
|
+
'</ul>' +
|
|
1072
|
+
'</div>' +
|
|
1073
|
+
'<div class="note-color btn-group">' +
|
|
1074
|
+
'<button type="button" class="btn btn-small note-recent-color" title="Recent Color" data-event="color" data-value=\'{"foreColor":"black","backColor":"yellow"}\'><i class="icon-font" style="color:black;background-color:yellow;"></i></button>' +
|
|
1075
|
+
'<button type="button" class="btn btn-small dropdown-toggle" title="More Color" data-toggle="dropdown">' +
|
|
1076
|
+
'<span class="caret"></span>' +
|
|
1077
|
+
'</button>' +
|
|
1078
|
+
'<ul class="dropdown-menu">' +
|
|
1079
|
+
'<li>' +
|
|
1080
|
+
'<div class="btn-group">' +
|
|
1081
|
+
'<div class="note-palette-title">BackColor</div>' +
|
|
1082
|
+
'<div class="note-color-palette" data-target-event="backColor"></div>' +
|
|
1083
|
+
'</div>' +
|
|
1084
|
+
'<div class="btn-group">' +
|
|
1085
|
+
'<div class="note-palette-title">FontColor</div>' +
|
|
1086
|
+
'<div class="note-color-palette" data-target-event="foreColor"></div>' +
|
|
1087
|
+
'</div>' +
|
|
1088
|
+
'</li>' +
|
|
1089
|
+
'</ul>' +
|
|
1090
|
+
'</div>' +
|
|
1091
|
+
'<div class="note-style btn-group">' +
|
|
1092
|
+
'<button type="button" class="btn btn-small" title="Bold" data-shortcut="Ctrl+B" data-mac-shortcut="⌘+B" data-event="bold"><i class="icon-bold"></i></button>' +
|
|
1093
|
+
'<button type="button" class="btn btn-small" title="Italic" data-shortcut="Ctrl+I" data-mac-shortcut="⌘+I" data-event="italic"><i class="icon-italic"></i></button>' +
|
|
1094
|
+
'<button type="button" class="btn btn-small" title="Underline" data-shortcut="Ctrl+U" data-mac-shortcut="⌘+U" data-event="underline"><i class="icon-underline"></i></button>' +
|
|
1095
|
+
'<button type="button" class="btn btn-small" title="Remove Font Style" data-shortcut="Ctrl+\\" data-mac-shortcut="⌘+\\" data-event="removeFormat"><i class="icon-eraser"></i></button>' +
|
|
1096
|
+
'</div>' +
|
|
1097
|
+
'<div class="note-para btn-group">' +
|
|
1098
|
+
'<button type="button" class="btn btn-small" title="Unordered list" data-shortcut="Ctrl+Shift+8" data-mac-shortcut="⌘+⇧+7" data-event="insertUnorderedList"><i class="icon-list-ul"></i></button>' +
|
|
1099
|
+
'<button type="button" class="btn btn-small" title="Ordered list" data-shortcut="Ctrl+Shift+7" data-mac-shortcut="⌘+⇧+8" data-event="insertOrderedList"><i class="icon-list-ol"></i></button>' +
|
|
1100
|
+
'<button type="button" class="btn btn-small dropdown-toggle" title="Paragraph" data-toggle="dropdown"><i class="icon-align-left"></i> <span class="caret"></span></button>' +
|
|
1101
|
+
'<ul class="dropdown-menu right">' +
|
|
1102
|
+
'<li>' +
|
|
1103
|
+
'<div class="note-align btn-group">' +
|
|
1104
|
+
'<button type="button" class="btn btn-small" title="Align left" data-shortcut="Ctrl+Shift+L" data-mac-shortcut="⌘+⇧+L" data-event="justifyLeft"><i class="icon-align-left"></i></button>' +
|
|
1105
|
+
'<button type="button" class="btn btn-small" title="Align center" data-shortcut="Ctrl+Shift+E" data-mac-shortcut="⌘+⇧+E" data-event="justifyCenter"><i class="icon-align-center"></i></button>' +
|
|
1106
|
+
'<button type="button" class="btn btn-small" title="Align right" data-shortcut="Ctrl+Shift+R" data-mac-shortcut="⌘+⇧+R" data-event="justifyRight"><i class="icon-align-right"></i></button>' +
|
|
1107
|
+
'<button type="button" class="btn btn-small" title="Justify full" data-shortcut="Ctrl+Shift+J" data-mac-shortcut="⌘+⇧+J" data-event="justifyFull"><i class="icon-align-justify"></i></button>' +
|
|
1108
|
+
'</div>' +
|
|
1109
|
+
'</li>' +
|
|
1110
|
+
'<li>' +
|
|
1111
|
+
'<div class="note-list btn-group">' +
|
|
1112
|
+
'<button type="button" class="btn btn-small" title="Outdent" data-shortcut="Shift+TAB" data-mac-shortcut="⇧+TAB" data-event="outdent"><i class="icon-indent-left"></i></button>' +
|
|
1113
|
+
'<button type="button" class="btn btn-small" title="Indent" data-shortcut="TAB" data-mac-shortcut="TAB" data-event="indent"><i class="icon-indent-right"></i></button>' +
|
|
1114
|
+
'</li>' +
|
|
1115
|
+
'</ul>' +
|
|
1116
|
+
'</div>' +
|
|
1117
|
+
'<div class="note-line-height btn-group">' +
|
|
1118
|
+
'<button type="button" class="btn btn-small dropdown-toggle" data-toggle="dropdown" title="Line Height"><i class="icon-text-height"></i> <b class="caret"></b></button>' +
|
|
1119
|
+
'<ul class="dropdown-menu right">' +
|
|
1120
|
+
'<li><a data-event="lineHeight" data-value="1.0"><i class="icon-ok"></i> 1.0</a></li>' +
|
|
1121
|
+
'<li><a data-event="lineHeight" data-value="1.2"><i class="icon-ok"></i> 1.2</a></li>' +
|
|
1122
|
+
'<li><a data-event="lineHeight" data-value="1.4"><i class="icon-ok"></i> 1.4</a></li>' +
|
|
1123
|
+
'<li><a data-event="lineHeight" data-value="1.5"><i class="icon-ok"></i> 1.5</a></li>' +
|
|
1124
|
+
'<li><a data-event="lineHeight" data-value="1.6"><i class="icon-ok"></i> 1.6</a></li>' +
|
|
1125
|
+
'<li><a data-event="lineHeight" data-value="1.8"><i class="icon-ok"></i> 1.8</a></li>' +
|
|
1126
|
+
'<li><a data-event="lineHeight" data-value="2.0"><i class="icon-ok"></i> 2.0</a></li>' +
|
|
1127
|
+
'<li><a data-event="lineHeight" data-value="3.0"><i class="icon-ok"></i> 3.0</a></li>' +
|
|
1128
|
+
'</ul>' +
|
|
1129
|
+
'</div>' +
|
|
1130
|
+
'</div>';
|
|
1131
|
+
var sPopover = '<div class="note-popover">' +
|
|
1132
|
+
'<div class="note-link-popover popover fade bottom in" style="display: none;">' +
|
|
1133
|
+
'<div class="arrow"></div>' +
|
|
1134
|
+
'<div class="popover-content note-link-content">' +
|
|
1135
|
+
'<a href="http://www.google.com" target="_blank">www.google.com</a> ' +
|
|
1136
|
+
'<div class="note-insert btn-group">' +
|
|
1137
|
+
'<button type="button" class="btn btn-small" title="Edit" data-event="showLinkDialog"><i class="icon-edit"></i></button>' +
|
|
1138
|
+
'<button type="button" class="btn btn-small" title="Unlink" data-event="unlink"><i class="icon-unlink"></i></button>' +
|
|
1139
|
+
'</div>' +
|
|
1140
|
+
'</div>' +
|
|
1141
|
+
'</div>' +
|
|
1142
|
+
'<div class="note-image-popover popover fade bottom in" style="display: none;">' +
|
|
1143
|
+
'<div class="arrow"></div>' +
|
|
1144
|
+
'<div class="popover-content note-image-content">' +
|
|
1145
|
+
'<div class="btn-group">' +
|
|
1146
|
+
'<button type="button" class="btn btn-small" title="Resize Full" data-event="resize" data-value="1"><i class="icon-resize-full"></i></button>' +
|
|
1147
|
+
'<button type="button" class="btn btn-small" title="Resize Half" data-event="resize" data-value="0.5">½</button>' +
|
|
1148
|
+
'<button type="button" class="btn btn-small" title="Resize Thrid" data-event="resize" data-value="0.33">⅓</button>' +
|
|
1149
|
+
'<button type="button" class="btn btn-small" title="Resize Quarter" data-event="resize" data-value="0.25">¼</button>' +
|
|
1150
|
+
'</div>' +
|
|
1151
|
+
'<div class="btn-group">' +
|
|
1152
|
+
'<button type="button" class="btn btn-small" title="Float Left" data-event="float" data-value="left"><i class="icon-align-left"></i></button>' +
|
|
1153
|
+
'<button type="button" class="btn btn-small" title="Float Right" data-event="float" data-value="right"><i class="icon-align-right"></i></button>' +
|
|
1154
|
+
'<button type="button" class="btn btn-small" title="Float None" data-event="float" data-value="none"><i class="icon-reorder"></i></button>' +
|
|
1155
|
+
'</div>' +
|
|
1156
|
+
'</div>' +
|
|
1157
|
+
'</div>' +
|
|
1158
|
+
'</div>';
|
|
1159
|
+
|
|
1160
|
+
var sHandle = '<div class="note-handle">' +
|
|
1161
|
+
'<div class="note-control-selection">' +
|
|
1162
|
+
'<div class="note-control-selection-bg"></div>' +
|
|
1163
|
+
'<div class="note-control-holder note-control-nw"></div>' +
|
|
1164
|
+
'<div class="note-control-holder note-control-ne"></div>' +
|
|
1165
|
+
'<div class="note-control-holder note-control-sw"></div>' +
|
|
1166
|
+
'<div class="note-control-sizing note-control-se"></div>' +
|
|
1167
|
+
'<div class="note-control-selection-info"></div>' +
|
|
1168
|
+
'</div>' +
|
|
1169
|
+
'</div>';
|
|
1170
|
+
|
|
1171
|
+
var sDialog = '<div class="note-dialog">' +
|
|
1172
|
+
'<div class="note-image-dialog modal hide in" aria-hidden="false">' +
|
|
1173
|
+
'<div class="modal-header">' +
|
|
1174
|
+
'<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>' +
|
|
1175
|
+
'<h4>Insert Image</h4>' +
|
|
1176
|
+
'</div>' +
|
|
1177
|
+
'<div class="modal-body">' +
|
|
1178
|
+
'<div class="row-fluid">' +
|
|
1179
|
+
'<div class="note-dropzone span12">Drag an image here</div>' +
|
|
1180
|
+
'<div>or if you prefer...</div>' +
|
|
1181
|
+
'<input class="note-image-input" type="file" class="note-link-url" type="text" />' +
|
|
1182
|
+
'</div>' +
|
|
1183
|
+
'</div>' +
|
|
1184
|
+
'</div>' +
|
|
1185
|
+
'<div class="note-link-dialog modal hide in" aria-hidden="false">' +
|
|
1186
|
+
'<div class="modal-header">' +
|
|
1187
|
+
'<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>' +
|
|
1188
|
+
'<h4>Edit Link</h4>' +
|
|
1189
|
+
'</div>' +
|
|
1190
|
+
'<div class="modal-body">' +
|
|
1191
|
+
'<div class="row-fluid">' +
|
|
1192
|
+
'<label>Text to display</label>' +
|
|
1193
|
+
'<span class="note-link-text input-xlarge uneditable-input" />' +
|
|
1194
|
+
'<label>To what URL should this link go?</label>' +
|
|
1195
|
+
'<input class="note-link-url span12" type="text" />' +
|
|
1196
|
+
'</div>' +
|
|
1197
|
+
'</div>' +
|
|
1198
|
+
'<div class="modal-footer">' +
|
|
1199
|
+
'<a href="#" class="btn disabled note-link-btn" disabled="disabled">Link</a>' +
|
|
1200
|
+
'</div>' +
|
|
1201
|
+
'</div>' +
|
|
1202
|
+
'</div>';
|
|
1203
|
+
|
|
1204
|
+
// createTooltip
|
|
1205
|
+
var createTooltip = function(welContainer, sPlacement) {
|
|
1206
|
+
welContainer.find('button').each(function(i, elBtn) {
|
|
1207
|
+
var welBtn = $(elBtn);
|
|
1208
|
+
var sShortcut = welBtn.attr(bMac ? 'data-mac-shortcut':'data-shortcut');
|
|
1209
|
+
if (sShortcut) { welBtn.attr('title', function(i, v) { return v + ' (' + sShortcut + ')'}); }
|
|
1210
|
+
//bootstrap tooltip on btn-group bug: https://github.com/twitter/bootstrap/issues/5687
|
|
1211
|
+
}).tooltip({container: 'body', placement: sPlacement || 'top'});
|
|
1212
|
+
};
|
|
1213
|
+
|
|
1214
|
+
// pallete colors
|
|
1215
|
+
var aaColor = [
|
|
1216
|
+
['#000000', '#424242', '#636363', '#9C9C94', '#CEC6CE', '#EFEFEF', '#EFF7F7', '#FFFFFF'],
|
|
1217
|
+
['#FF0000', '#FF9C00', '#FFFF00', '#00FF00', '#00FFFF', '#0000FF', '#9C00FF', '#FF00FF'],
|
|
1218
|
+
['#F7C6CE', '#FFE7CE', '#FFEFC6', '#D6EFD6', '#CEDEE7', '#CEE7F7', '#D6D6E7', '#E7D6DE'],
|
|
1219
|
+
['#E79C9C', '#FFC69C', '#FFE79C', '#B5D6A5', '#A5C6CE', '#9CC6EF', '#B5A5D6', '#D6A5BD'],
|
|
1220
|
+
['#E76363', '#F7AD6B', '#FFD663', '#94BD7B', '#73A5AD', '#6BADDE', '#8C7BC6', '#C67BA5'],
|
|
1221
|
+
['#CE0000', '#E79439', '#EFC631', '#6BA54A', '#4A7B8C', '#3984C6', '#634AA5', '#A54A7B'],
|
|
1222
|
+
['#9C0000', '#B56308', '#BD9400', '#397B21', '#104A5A', '#085294', '#311873', '#731842'],
|
|
1223
|
+
['#630000', '#7B3900', '#846300', '#295218', '#083139', '#003163', '#21104A', '#4A1031']
|
|
1224
|
+
];
|
|
1225
|
+
|
|
1226
|
+
// createPalette
|
|
1227
|
+
var createPalette = function(welContainer) {
|
|
1228
|
+
welContainer.find('.note-color-palette').each(function() {
|
|
1229
|
+
var welPalette = $(this), sEvent = welPalette.attr('data-target-event');
|
|
1230
|
+
var sPaletteContents = '';
|
|
1231
|
+
for (var row = 0, szRow = aaColor.length; row < szRow; row++) {
|
|
1232
|
+
var aColor = aaColor[row];
|
|
1233
|
+
var sLine = '<div>';
|
|
1234
|
+
for (var col = 0, szCol = aColor.length; col < szCol; col++) {
|
|
1235
|
+
var sColor = aColor[col];
|
|
1236
|
+
var sButton = ['<button type="button" class="note-color-btn" style="background-color:', sColor,
|
|
1237
|
+
';" data-event="', sEvent,
|
|
1238
|
+
'" data-value="', sColor,
|
|
1239
|
+
'" title="', sColor,
|
|
1240
|
+
'" data-toggle="button"></button>'].join('');
|
|
1241
|
+
sLine += sButton;
|
|
1242
|
+
}
|
|
1243
|
+
sLine += '</div>';
|
|
1244
|
+
sPaletteContents += sLine;
|
|
1245
|
+
}
|
|
1246
|
+
welPalette.html(sPaletteContents);
|
|
1247
|
+
});
|
|
1248
|
+
};
|
|
1249
|
+
|
|
1250
|
+
// createLayout
|
|
1251
|
+
var createLayout = this.createLayout = function(welHolder, nHeight) {
|
|
1252
|
+
//already created
|
|
1253
|
+
if (welHolder.next().hasClass('note-editor')) { return; }
|
|
1254
|
+
|
|
1255
|
+
//01. create Editor
|
|
1256
|
+
var welEditor = $('<div class="note-editor"></div>');
|
|
1257
|
+
|
|
1258
|
+
//02. create Editable
|
|
1259
|
+
var welEditable = $('<div class="note-editable" contentEditable="true"></div>').prependTo(welEditor);
|
|
1260
|
+
if (nHeight) { welEditable.height(nHeight); }
|
|
1261
|
+
|
|
1262
|
+
welEditable.html(welHolder.html());
|
|
1263
|
+
welEditable.data('NoteHistory', new History());
|
|
1264
|
+
|
|
1265
|
+
//03. create Toolbar
|
|
1266
|
+
var welToolbar = $(sToolbar).prependTo(welEditor);
|
|
1267
|
+
createPalette(welToolbar);
|
|
1268
|
+
createTooltip(welToolbar, 'bottom');
|
|
1269
|
+
|
|
1270
|
+
//04. create Popover
|
|
1271
|
+
var welPopover = $(sPopover).prependTo(welEditor);
|
|
1272
|
+
createTooltip(welPopover);
|
|
1273
|
+
|
|
1274
|
+
//05. handle(control selection, ...)
|
|
1275
|
+
$(sHandle).prependTo(welEditor);
|
|
1276
|
+
|
|
1277
|
+
//06. create Dialog
|
|
1278
|
+
$(sDialog).prependTo(welEditor);
|
|
1279
|
+
|
|
1280
|
+
//05. Editor/Holder switch
|
|
1281
|
+
welEditor.insertAfter(welHolder);
|
|
1282
|
+
welHolder.hide();
|
|
1283
|
+
};
|
|
1284
|
+
|
|
1285
|
+
// layoutInfoFromHolder
|
|
1286
|
+
var layoutInfoFromHolder = this.layoutInfoFromHolder = function(welHolder) {
|
|
1287
|
+
var welEditor = welHolder.next();
|
|
1288
|
+
if (!welEditor.hasClass('note-editor')) { return; }
|
|
1289
|
+
|
|
1290
|
+
return {
|
|
1291
|
+
editor: welEditor,
|
|
1292
|
+
editable: welEditor.find('.note-editable'),
|
|
1293
|
+
toolbar: welEditor.find('.note-toolbar'),
|
|
1294
|
+
popover: welEditor.find('.note-popover'),
|
|
1295
|
+
handle: welEditor.find('.note-handle'),
|
|
1296
|
+
dialog: welEditor.find('.note-dialog')
|
|
1297
|
+
};
|
|
1298
|
+
};
|
|
1299
|
+
|
|
1300
|
+
// removeLayout
|
|
1301
|
+
var removeLayout = this.removeLayout = function(welHolder) {
|
|
1302
|
+
var info = layoutInfoFromHolder(welHolder);
|
|
1303
|
+
if (!info) { return; }
|
|
1304
|
+
welHolder.html(info.editable.html());
|
|
1305
|
+
|
|
1306
|
+
info.editor.remove();
|
|
1307
|
+
welHolder.show();
|
|
1308
|
+
};
|
|
1309
|
+
};
|
|
1310
|
+
|
|
1311
|
+
var renderer = new Renderer();
|
|
1312
|
+
var eventHandler = new EventHandler();
|
|
1313
|
+
|
|
1314
|
+
/**
|
|
1315
|
+
* extend jquery fn
|
|
1316
|
+
*/
|
|
1317
|
+
$.fn.extend({
|
|
1318
|
+
// create Editor Layout and attach Key and Mouse Event
|
|
1319
|
+
summernote: function(options) {
|
|
1320
|
+
options = options || {};
|
|
1321
|
+
|
|
1322
|
+
this.each(function(idx, elHolder) {
|
|
1323
|
+
var welHolder = $(elHolder);
|
|
1324
|
+
|
|
1325
|
+
// createLayout
|
|
1326
|
+
renderer.createLayout(welHolder, options.height);
|
|
1327
|
+
|
|
1328
|
+
var info = renderer.layoutInfoFromHolder(welHolder);
|
|
1329
|
+
eventHandler.attach(info);
|
|
1330
|
+
|
|
1331
|
+
if (options.focus) { info.editable.focus(); } // options focus
|
|
1332
|
+
});
|
|
1333
|
+
},
|
|
1334
|
+
// get the HTML contents of note or set the HTML contents of note.
|
|
1335
|
+
code: function(sHTML) {
|
|
1336
|
+
//get the HTML contents
|
|
1337
|
+
if (sHTML === undefined) {
|
|
1338
|
+
return this.map(function(idx, elHolder) {
|
|
1339
|
+
var info = renderer.layoutInfoFromHolder($(elHolder));
|
|
1340
|
+
return info.editable.html();
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
// set the HTML contents
|
|
1345
|
+
this.each(function(i, elHolder) {
|
|
1346
|
+
var info = renderer.layoutInfoFromHolder($(elHolder));
|
|
1347
|
+
info.editable.html(sHTML);
|
|
1348
|
+
});
|
|
1349
|
+
},
|
|
1350
|
+
// destroy Editor Layout and dettach Key and Mouse Event
|
|
1351
|
+
destroy: function() {
|
|
1352
|
+
this.each(function(idx, elHolder) {
|
|
1353
|
+
var welHolder = $(elHolder);
|
|
1354
|
+
|
|
1355
|
+
var info = renderer.layoutInfoFromHolder(welHolder);
|
|
1356
|
+
eventHandler.dettach(info);
|
|
1357
|
+
renderer.removeLayout(welHolder);
|
|
1358
|
+
});
|
|
1359
|
+
},
|
|
1360
|
+
// inner object for test
|
|
1361
|
+
summernoteInner: function() {
|
|
1362
|
+
return { dom: dom, list: list, func: func };
|
|
1363
|
+
}
|
|
1364
|
+
});
|
|
1365
|
+
})(jQuery); // jQuery
|