summernote
Advanced tools
Comparing version 0.6.1 to 0.6.5
{ | ||
"name": "summernote", | ||
"version": "0.6.1", | ||
"version": "0.6.5", | ||
"main": [ | ||
@@ -5,0 +5,0 @@ "./dist/summernote.js", |
@@ -77,2 +77,26 @@ module.exports = function (grunt) { | ||
// compress: summernote-{{version}}-dist.zip | ||
compress: { | ||
main: { | ||
options: { | ||
archive: function () { | ||
return 'dist/summernote-{{version}}-dist.zip'.replace( | ||
'{{version}}', | ||
grunt.config('pkg.version') | ||
); | ||
} | ||
}, | ||
files: [{ | ||
expand: true, | ||
src: [ | ||
'dist/*.js', | ||
'dist/summernote.css' | ||
] | ||
}, { | ||
src: ['plugin/*.js'], | ||
dest: 'dist/' | ||
}] | ||
} | ||
}, | ||
// connect configuration. | ||
@@ -124,14 +148,17 @@ connect: { | ||
// server | ||
// load all grunts/*.js | ||
grunt.loadTasks('grunts'); | ||
// server: runt server for development | ||
grunt.registerTask('server', ['connect', 'watch']); | ||
// build: build summernote.js | ||
grunt.loadTasks('build'); | ||
// test: unit test on test folder | ||
grunt.registerTask('test', ['jshint', 'qunit']); | ||
// dist | ||
// dist: make dist files | ||
grunt.registerTask('dist', ['build', 'test', 'uglify', 'recess']); | ||
// deploy: compress dist files | ||
grunt.registerTask('deploy', ['dist', 'compress']); | ||
// default: server | ||
@@ -138,0 +165,0 @@ grunt.registerTask('default', ['server']); |
### Change Log | ||
#### v0.6.4 ~ v0.6.5 2015-04-26 | ||
* Support more range API: range.pasteHTML, range.getWordRange | ||
* Merge summernote-ext-fontstyle.js plugin with base code | ||
* Bugfix : #1003, #1026, #1038, some of #1012 | ||
#### v0.6.3 2015-04-08 | ||
* Support external API access | ||
* Support callbacks with jquery custom event. | ||
#### v0.6.2 2015-03-14 | ||
* Fixed text drag and drop bug. | ||
#### v0.6.1 2015-02-08 | ||
@@ -4,0 +16,0 @@ * Fixed bugs about links, bullets and ranges. |
@@ -10,3 +10,5 @@ (function ($) { | ||
height: 'إرتفاع السطر', | ||
name: 'الخط' | ||
name: 'الخط', | ||
strikethrough: 'فى وسطه خط', | ||
size: 'الحجم' | ||
}, | ||
@@ -13,0 +15,0 @@ image: { |
@@ -9,3 +9,5 @@ (function ($) { | ||
clear: 'Treure estil de lletra', | ||
height: 'Alçada de línia' | ||
height: 'Alçada de línia', | ||
strikethrough: 'Ratllat', | ||
size: 'Mida de lletra' | ||
}, | ||
@@ -12,0 +14,0 @@ image: { |
@@ -9,3 +9,5 @@ (function ($) { | ||
clear: 'Odstranit styl písma', | ||
height: 'Výška řádku' | ||
height: 'Výška řádku', | ||
strikethrough: 'Přeškrtnuté', | ||
size: 'Velikost písma' | ||
}, | ||
@@ -12,0 +14,0 @@ image: { |
@@ -10,3 +10,7 @@ (function ($) { | ||
height: 'Højde', | ||
name: 'Skrifttype' | ||
name: 'Skrifttype', | ||
strikethrough: 'Gennemstreget', | ||
subscript: 'Sænket skrift', | ||
superscript: 'Hævet skrift', | ||
size: 'Skriftstørrelse' | ||
}, | ||
@@ -13,0 +17,0 @@ image: { |
@@ -9,3 +9,5 @@ (function ($) { | ||
clear: 'Zurücksetzen', | ||
height: 'Zeilenhöhe' | ||
height: 'Zeilenhöhe', | ||
strikethrough: 'Durchgestrichen', | ||
size: 'Schriftgröße' | ||
}, | ||
@@ -12,0 +14,0 @@ image: { |
@@ -10,3 +10,7 @@ (function ($) { | ||
height: 'Altura de línea', | ||
name: 'Fuente' | ||
name: 'Fuente', | ||
strikethrough: 'Tachado', | ||
superscript: 'Superíndice', | ||
subscript: 'Subíndice', | ||
size: 'Tamaño de la fuente' | ||
}, | ||
@@ -13,0 +17,0 @@ image: { |
@@ -10,3 +10,5 @@ (function ($) { | ||
height: 'Lerro altuera', | ||
name: 'Tipografia' | ||
name: 'Tipografia', | ||
strikethrough: 'Marratua', | ||
size: 'Letren neurria' | ||
}, | ||
@@ -13,0 +15,0 @@ image: { |
@@ -10,3 +10,5 @@ (function ($) { | ||
height: 'فاصله ی خطی', | ||
name: 'اسم فونت' | ||
name: 'اسم فونت', | ||
strikethrough: 'Strike', | ||
size: 'اندازه ی فونت' | ||
}, | ||
@@ -13,0 +15,0 @@ image: { |
@@ -10,3 +10,5 @@ (function ($) { | ||
height: 'Riviväli', | ||
name: 'Kirjasintyyppi' | ||
name: 'Kirjasintyyppi', | ||
strikethrough: 'Yliviivaus', | ||
size: 'Kirjasinkoko' | ||
}, | ||
@@ -13,0 +15,0 @@ image: { |
@@ -10,3 +10,7 @@ (function ($) { | ||
height: 'Interligne', | ||
name: 'Famille de police' | ||
name: 'Famille de police', | ||
strikethrough: 'Barré', | ||
superscript: 'Exposant', | ||
subscript: 'Indicé', | ||
size: 'Taille de police' | ||
}, | ||
@@ -13,0 +17,0 @@ image: { |
@@ -10,3 +10,7 @@ (function ($) { | ||
height: 'גובה', | ||
name: 'גופן' | ||
name: 'גופן', | ||
strikethrough: 'קו חוצה', | ||
subscript: 'כתב תחתי', | ||
superscript: 'כתב עילי', | ||
size: 'גודל גופן' | ||
}, | ||
@@ -13,0 +17,0 @@ image: { |
@@ -10,3 +10,5 @@ (function ($) { | ||
height: 'Sorköz', | ||
name: 'Betűtípus' | ||
name: 'Betűtípus', | ||
strikethrough: 'Áthúzott', | ||
size: 'Betűméret' | ||
}, | ||
@@ -13,0 +15,0 @@ image: { |
@@ -9,3 +9,5 @@ (function ($) { | ||
clear: 'Bersihkan gaya', | ||
height: 'Jarak baris' | ||
height: 'Jarak baris', | ||
strikethrough: 'Coret', | ||
size: 'Ukuran font' | ||
}, | ||
@@ -12,0 +14,0 @@ image: { |
@@ -10,3 +10,5 @@ (function ($) { | ||
height: 'Altezza della linea di testo', | ||
name: 'Famiglia Font' | ||
name: 'Famiglia Font', | ||
strikethrough: 'Testo barrato', | ||
size: 'Dimensione del carattere' | ||
}, | ||
@@ -13,0 +15,0 @@ image: { |
@@ -10,3 +10,5 @@ (function ($) { | ||
height: '文字高', | ||
name: 'フォント' | ||
name: 'フォント', | ||
strikethrough: '取り消し線', | ||
size: '大きさ' | ||
}, | ||
@@ -13,0 +15,0 @@ image: { |
(function ($) { | ||
console.log('hit'); | ||
$.extend($.summernote.lang, { | ||
@@ -10,3 +11,7 @@ 'ko-KR': { | ||
height: '줄간격', | ||
name: '글꼴' | ||
name: '글꼴', | ||
superscript: '위 첨자', | ||
subscript: '아래 첨자', | ||
strikethrough: '취소선', | ||
size: '글자 크기' | ||
}, | ||
@@ -13,0 +18,0 @@ image: { |
@@ -10,3 +10,5 @@ (function ($) { | ||
height: 'Linjehøyde', | ||
name: 'Skrifttype' | ||
name: 'Skrifttype', | ||
strikethrough: 'Gjennomstrek', | ||
size: 'Skriftstørrelse' | ||
}, | ||
@@ -13,0 +15,0 @@ image: { |
@@ -10,3 +10,5 @@ (function ($) { | ||
height: 'Regelhoogte', | ||
name: 'Lettertype' | ||
name: 'Lettertype', | ||
strikethrough: 'Doorhalen', | ||
size: 'Tekstgrootte' | ||
}, | ||
@@ -13,0 +15,0 @@ image: { |
@@ -10,3 +10,5 @@ (function ($) { | ||
height: 'Interlinia', | ||
name: 'Czcionka' | ||
name: 'Czcionka', | ||
strikethrough: 'Przekreślenie', | ||
size: 'Rozmiar' | ||
}, | ||
@@ -22,5 +24,12 @@ image: { | ||
floatNone: 'Równo z tekstem', | ||
dragImageHere: 'Przeciągnij grafikę tutaj', | ||
shapeRounded: 'Kształt: zaokrąglone', | ||
shapeCircle: 'Kształt: okrąg', | ||
shapeThumbnail: 'Kształt: miniatura', | ||
shapeNone: 'Kształt: brak', | ||
dragImageHere: 'Przeciągnij grafikę lub tekst tutaj', | ||
dropImage: 'Przeciągnij grafikę lub tekst', | ||
selectFromFiles: 'Wybierz z dysku', | ||
url: 'URL grafiki', | ||
maximumFileSize: 'Limit wielkości pliku', | ||
maximumFileSizeError: 'Przekroczono limit wielkości pliku.', | ||
url: 'Adres URL grafiki', | ||
remove: 'Usuń grafikę' | ||
@@ -34,3 +43,3 @@ }, | ||
textToDisplay: 'Tekst do wyświetlenia', | ||
url: 'Na jaki URL powinien przenosić ten link?', | ||
url: 'Na jaki adres URL powinien przenosić ten odnośnik?', | ||
openInNewWindow: 'Otwórz w nowym oknie' | ||
@@ -63,3 +72,3 @@ }, | ||
fullscreen: 'Pełny ekran', | ||
codeview: 'Zródło' | ||
codeview: 'Źródło' | ||
}, | ||
@@ -86,3 +95,3 @@ paragraph: { | ||
shortcut: { | ||
shortcuts: 'Skróty klawiszone', | ||
shortcuts: 'Skróty klawiaturowe', | ||
close: 'Zamknij', | ||
@@ -92,3 +101,4 @@ textFormatting: 'Formatowanie tekstu', | ||
paragraphFormatting: 'Formatowanie akapitu', | ||
documentStyle: 'Styl dokumentu' | ||
documentStyle: 'Styl dokumentu', | ||
extraKeys: 'Dodatkowe klawisze' | ||
}, | ||
@@ -95,0 +105,0 @@ history: { |
@@ -10,3 +10,5 @@ (function ($) { | ||
height: 'Altura da linha', | ||
name: 'Fonte' | ||
name: 'Fonte', | ||
strikethrough: 'Riscado', | ||
size: 'Tamanho da fonte' | ||
}, | ||
@@ -13,0 +15,0 @@ image: { |
@@ -9,3 +9,5 @@ (function ($) { | ||
clear: 'Înlătură formatare font', | ||
height: 'Înălțime rând' | ||
height: 'Înălțime rând', | ||
strikethrough: 'Tăiat', | ||
size: 'Dimensiune font' | ||
}, | ||
@@ -12,0 +14,0 @@ image: { |
@@ -10,3 +10,7 @@ (function ($) { | ||
height: 'Высота линии', | ||
name: 'Шрифт' | ||
name: 'Шрифт', | ||
strikethrough: 'Зачёркнутый', | ||
subscript: 'Нижний индекс', | ||
superscript: 'Верхний индекс', | ||
size: 'Размер шрифта' | ||
}, | ||
@@ -13,0 +17,0 @@ image: { |
@@ -9,3 +9,5 @@ (function ($) { | ||
clear: 'Odstrániť štýl písma', | ||
height: 'Výška riadku' | ||
height: 'Výška riadku', | ||
strikethrough: 'Preškrtnuté', | ||
size: 'Veľkosť písma' | ||
}, | ||
@@ -12,0 +14,0 @@ image: { |
@@ -10,3 +10,7 @@ (function ($) { | ||
height: 'Razmik med vrsticami', | ||
name: 'Pisava' | ||
name: 'Pisava', | ||
strikethrough: 'Prečrtano', | ||
subscript: 'Podpisano', | ||
superscript: 'Nadpisano', | ||
size: 'Velikost pisave' | ||
}, | ||
@@ -13,0 +17,0 @@ image: { |
@@ -9,3 +9,5 @@ (function ($) { | ||
clear: 'Ukloni stilove fonta', | ||
height: 'Visina linije' | ||
height: 'Visina linije', | ||
strikethrough: 'Precrtano', | ||
size: 'Veličina fonta' | ||
}, | ||
@@ -12,0 +14,0 @@ image: { |
@@ -9,3 +9,5 @@ (function ($) { | ||
clear: 'Уклони стилове фонта', | ||
height: 'Висина линије' | ||
height: 'Висина линије', | ||
strikethrough: 'Прецртано', | ||
size: 'Величина фонта' | ||
}, | ||
@@ -12,0 +14,0 @@ image: { |
@@ -10,3 +10,5 @@ (function ($) { | ||
height: 'Radavstånd', | ||
name: 'Teckensnitt' | ||
name: 'Teckensnitt', | ||
strikethrough: 'Genomstruken', | ||
size: 'Teckenstorlek' | ||
}, | ||
@@ -13,0 +15,0 @@ image: { |
@@ -10,3 +10,7 @@ (function ($) { | ||
height: 'ความสูงบรรทัด', | ||
name: 'แบบตัวอักษร' | ||
name: 'แบบตัวอักษร', | ||
strikethrough: 'ขีดฆ่า', | ||
subscript: 'ตัวห้อย', | ||
superscript: 'ตัวยก', | ||
size: 'ขนาดตัวอักษร' | ||
}, | ||
@@ -13,0 +17,0 @@ image: { |
@@ -10,3 +10,7 @@ (function ($) { | ||
height: 'Satır yüksekliği', | ||
name: 'Yazı Tipi' | ||
name: 'Yazı Tipi', | ||
strikethrough: 'Üstü çizili', | ||
subscript: 'Subscript', | ||
superscript: 'Superscript', | ||
size: 'Yazı tipi boyutu' | ||
}, | ||
@@ -13,0 +17,0 @@ image: { |
@@ -10,3 +10,7 @@ (function ($) { | ||
height: 'Висота лінії', | ||
name: 'Шрифт' | ||
name: 'Шрифт', | ||
strikethrough: 'Закреслений', | ||
subscript: 'Нижній індекс', | ||
superscript: 'Верхній індекс', | ||
size: 'Розмір шрифту' | ||
}, | ||
@@ -13,0 +17,0 @@ image: { |
@@ -10,3 +10,5 @@ (function ($) { | ||
height: 'Khoảng Cách Hàng', | ||
name: 'Phông Chữ' | ||
name: 'Phông Chữ', | ||
strikethrough: 'Gạch Ngang', | ||
size: 'Cỡ Chữ' | ||
}, | ||
@@ -13,0 +15,0 @@ image: { |
@@ -10,3 +10,5 @@ (function ($) { | ||
height: '行高', | ||
name: '字体' | ||
name: '字体', | ||
strikethrough: '删除线', | ||
size: '字号' | ||
}, | ||
@@ -13,0 +15,0 @@ image: { |
@@ -9,3 +9,5 @@ (function ($) { | ||
clear: '清除格式', | ||
height: '行高' | ||
height: '行高', | ||
strikethrough: '刪除線', | ||
size: '字體大小' | ||
}, | ||
@@ -12,0 +14,0 @@ image: { |
{ | ||
"name": "summernote", | ||
"description": "Super Simple WYSIWYG Editor on Bootstrap", | ||
"version": "0.6.1", | ||
"version": "0.6.5", | ||
"keywords": [ | ||
@@ -23,7 +23,8 @@ "editor", | ||
"grunt-contrib-jshint": "0.7.2", | ||
"grunt-contrib-qunit": "*", | ||
"grunt-contrib-qunit": "0.5.2", | ||
"grunt-contrib-uglify": "~0.2.2", | ||
"grunt-recess": "*", | ||
"grunt-contrib-watch": "*", | ||
"grunt-contrib-connect": "*", | ||
"grunt-contrib-compress": "*", | ||
"grunt-recess": "*", | ||
"grunt-exec": "^0.4.6", | ||
@@ -30,0 +31,0 @@ "connect-livereload": "*" |
@@ -11,5 +11,4 @@ (function (factory) { | ||
}(function ($) { | ||
// template, editor | ||
// template | ||
var tmpl = $.summernote.renderer.getTemplate(); | ||
var editor = $.summernote.eventHandler.getEditor(); | ||
@@ -69,3 +68,3 @@ /** | ||
events: { // events | ||
hello: function (layoutInfo) { | ||
hello: function (event, editor, layoutInfo) { | ||
// Get current editable node | ||
@@ -77,3 +76,3 @@ var $editable = layoutInfo.editable(); | ||
}, | ||
helloDropdown: function (layoutInfo, value) { | ||
helloDropdown: function (event, editor, layoutInfo, value) { | ||
// Get current editable node | ||
@@ -85,3 +84,3 @@ var $editable = layoutInfo.editable(); | ||
}, | ||
helloImage : function (layoutInfo) { | ||
helloImage : function (event, editor, layoutInfo) { | ||
var $editable = layoutInfo.editable(); | ||
@@ -88,0 +87,0 @@ |
@@ -11,5 +11,4 @@ (function (factory) { | ||
}(function ($) { | ||
// template, editor | ||
// template | ||
var tmpl = $.summernote.renderer.getTemplate(); | ||
var editor = $.summernote.eventHandler.getEditor(); | ||
@@ -99,2 +98,3 @@ // core functions: range, dom | ||
// this is not a known video link. Now what, Cat? Now what? | ||
return false; | ||
} | ||
@@ -237,3 +237,3 @@ | ||
events: { | ||
showVideoDialog: function (layoutInfo) { | ||
showVideoDialog: function (event, editor, layoutInfo) { | ||
var $dialog = layoutInfo.dialog(), | ||
@@ -251,5 +251,10 @@ $editable = layoutInfo.editable(), | ||
editor.restoreRange($editable); | ||
// insert video node | ||
editor.insertNode($editable, createVideoNode(url)); | ||
// build node | ||
var $node = createVideoNode(url); | ||
if ($node) { | ||
// insert video node | ||
editor.insertNode($editable, $node); | ||
} | ||
}).fail(function () { | ||
@@ -256,0 +261,0 @@ // when cancel button clicked |
@@ -71,2 +71,3 @@ define([ | ||
editor: function () { return $editor; }, | ||
holder : function () { return $editor.data('holder'); }, | ||
editable: function () { return $editor; }, | ||
@@ -85,2 +86,3 @@ popover: makeFinder('#note-popover-'), | ||
editor: function () { return $editor; }, | ||
holder : function () { return $editor.data('holder'); }, | ||
dropzone: makeFinder('.note-dropzone'), | ||
@@ -99,2 +101,26 @@ toolbar: makeFinder('.note-toolbar'), | ||
/** | ||
* returns makeLayoutInfo from editor's descendant node. | ||
* | ||
* @private | ||
* @param {Node} descendant | ||
* @return {Object} | ||
*/ | ||
var makeLayoutInfo = function (descendant) { | ||
var $target = $(descendant).closest('.note-editor, .note-air-editor, .note-air-layout'); | ||
if (!$target.length) { | ||
return null; | ||
} | ||
var $editor; | ||
if ($target.is('.note-editor, .note-air-editor')) { | ||
$editor = $target; | ||
} else { | ||
$editor = $('#note-editor-' + list.last($target.attr('id').split('-'))); | ||
} | ||
return buildLayoutInfo($editor); | ||
}; | ||
/** | ||
* @method makePredByNodeName | ||
@@ -220,2 +246,3 @@ * | ||
* blank HTML for cursor position | ||
* - [workaround] for MSIE IE doesn't works with bogus br | ||
*/ | ||
@@ -664,2 +691,17 @@ var blankHTML = agent.isMSIE ? ' ' : '<br>'; | ||
/** | ||
* returns whether point has character or not. | ||
* | ||
* @param {Point} point | ||
* @return {Boolean} | ||
*/ | ||
var isCharPoint = function (point) { | ||
if (!isText(point.node)) { | ||
return false; | ||
} | ||
var ch = point.node.nodeValue.charAt(point.offset - 1); | ||
return ch && (ch !== ' ' && ch !== NBSP_CHAR); | ||
}; | ||
/** | ||
* @method walkPoint | ||
@@ -728,9 +770,13 @@ * | ||
* @param {BoundaryPoint} point | ||
* @param {Boolean} [isSkipPaddingBlankHTML] | ||
* @param {Object} [options] | ||
* @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false | ||
* @param {Boolean} [options.isNotSplitEdgePoint] - default: false | ||
* @return {Node} right node of boundaryPoint | ||
*/ | ||
var splitNode = function (point, isSkipPaddingBlankHTML) { | ||
// split #text | ||
if (isText(point.node)) { | ||
// edge case | ||
var splitNode = function (point, options) { | ||
var isSkipPaddingBlankHTML = options && options.isSkipPaddingBlankHTML; | ||
var isNotSplitEdgePoint = options && options.isNotSplitEdgePoint; | ||
// edge case | ||
if (isEdgePoint(point) && (isText(point.node) || isNotSplitEdgePoint)) { | ||
if (isLeftEdgePoint(point)) { | ||
@@ -741,17 +787,19 @@ return point.node; | ||
} | ||
} | ||
// split #text | ||
if (isText(point.node)) { | ||
return point.node.splitText(point.offset); | ||
} | ||
} else { | ||
var childNode = point.node.childNodes[point.offset]; | ||
var clone = insertAfter(point.node.cloneNode(false), point.node); | ||
appendChildNodes(clone, listNext(childNode)); | ||
// split element | ||
var childNode = point.node.childNodes[point.offset]; | ||
var clone = insertAfter(point.node.cloneNode(false), point.node); | ||
appendChildNodes(clone, listNext(childNode)); | ||
if (!isSkipPaddingBlankHTML) { | ||
paddingBlankHTML(point.node); | ||
paddingBlankHTML(clone); | ||
} | ||
if (!isSkipPaddingBlankHTML) { | ||
paddingBlankHTML(point.node); | ||
paddingBlankHTML(clone); | ||
return clone; | ||
} | ||
return clone; | ||
}; | ||
@@ -766,6 +814,8 @@ | ||
* @param {BoundaryPoint} point | ||
* @param {Boolean} [isSkipPaddingBlankHTML] | ||
* @param {Object} [options] | ||
* @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false | ||
* @param {Boolean} [options.isNotSplitEdgePoint] - default: false | ||
* @return {Node} right node of boundaryPoint | ||
*/ | ||
var splitTree = function (root, point, isSkipPaddingBlankHTML) { | ||
var splitTree = function (root, point, options) { | ||
// ex) [#text, <span>, <p>] | ||
@@ -777,19 +827,14 @@ var ancestors = listAncestor(point.node, func.eq(root)); | ||
} else if (ancestors.length === 1) { | ||
return splitNode(point, isSkipPaddingBlankHTML); | ||
return splitNode(point, options); | ||
} | ||
return ancestors.reduce(function (node, parent) { | ||
var clone = insertAfter(parent.cloneNode(false), parent); | ||
if (node === point.node) { | ||
node = splitNode(point, isSkipPaddingBlankHTML); | ||
node = splitNode(point, options); | ||
} | ||
appendChildNodes(clone, listNext(node)); | ||
if (!isSkipPaddingBlankHTML) { | ||
paddingBlankHTML(parent); | ||
paddingBlankHTML(clone); | ||
} | ||
return clone; | ||
return splitNode({ | ||
node: parent, | ||
offset: node ? dom.position(node) : nodeLength(parent) | ||
}, options); | ||
}); | ||
@@ -822,5 +867,13 @@ }; | ||
// split with splitTree | ||
var pivot = splitRoot && splitTree(splitRoot, point, isInline); | ||
// if splitRoot is exists, split with splitTree | ||
var pivot = splitRoot && splitTree(splitRoot, point, { | ||
isSkipPaddingBlankHTML: isInline, | ||
isNotSplitEdgePoint: isInline | ||
}); | ||
// if container is point.node, find pivot with point.offset | ||
if (!pivot && container === point.node) { | ||
pivot = point.node.childNodes[point.offset]; | ||
} | ||
return { | ||
@@ -916,2 +969,14 @@ rightNode: pivot, | ||
/** | ||
* @param {jQuery} $node | ||
* @param {Boolean} [stripLinebreaks] - default: false | ||
*/ | ||
var value = function ($node, stripLinebreaks) { | ||
var val = isTextarea($node[0]) ? $node.val() : $node.html(); | ||
if (stripLinebreaks) { | ||
return val.replace(/[\n\r]/g, ''); | ||
} | ||
return val; | ||
}; | ||
/** | ||
* @method html | ||
@@ -925,3 +990,3 @@ * | ||
var html = function ($node, isNewlineOnBlock) { | ||
var markup = isTextarea($node[0]) ? $node.val() : $node.html(); | ||
var markup = value($node); | ||
@@ -944,10 +1009,2 @@ if (isNewlineOnBlock) { | ||
var value = function ($textarea, stripLinebreaks) { | ||
var val = $textarea.val(); | ||
if (stripLinebreaks) { | ||
return val.replace(/[\n\r]/g, ''); | ||
} | ||
return val; | ||
}; | ||
return { | ||
@@ -966,2 +1023,3 @@ /** @property {String} NBSP_CHAR */ | ||
buildLayoutInfo: buildLayoutInfo, | ||
makeLayoutInfo: makeLayoutInfo, | ||
isText: isText, | ||
@@ -972,2 +1030,3 @@ isVoid: isVoid, | ||
isInline: isInline, | ||
isBlock: func.not(isInline), | ||
isBodyInline: isBodyInline, | ||
@@ -1008,2 +1067,3 @@ isBody: isBody, | ||
nextPointUntil: nextPointUntil, | ||
isCharPoint: isCharPoint, | ||
walkPoint: walkPoint, | ||
@@ -1010,0 +1070,0 @@ ancestor: ancestor, |
@@ -101,2 +101,14 @@ define('summernote/core/func', function () { | ||
/** | ||
* @param {String} namespace | ||
* @param {String} [prefix] | ||
* @return {String} | ||
*/ | ||
var namespaceToCamel = function (namespace, prefix) { | ||
prefix = prefix || ''; | ||
return prefix + namespace.split('.').map(function (name) { | ||
return name.substring(0, 1).toUpperCase() + name.substring(1); | ||
}).join(''); | ||
}; | ||
return { | ||
@@ -113,3 +125,4 @@ eq: eq, | ||
rect2bnd: rect2bnd, | ||
invertObject: invertObject | ||
invertObject: invertObject, | ||
namespaceToCamel: namespaceToCamel | ||
}; | ||
@@ -116,0 +129,0 @@ })(); |
define([ | ||
'summernote/core/list' | ||
], function (list) { | ||
'summernote/core/list', | ||
'summernote/core/func' | ||
], function (list, func) { | ||
/** | ||
@@ -12,54 +13,59 @@ * @class core.key | ||
*/ | ||
var key = { | ||
/** | ||
* @method isEdit | ||
* | ||
* @param {Number} keyCode | ||
* @return {Boolean} | ||
*/ | ||
isEdit: function (keyCode) { | ||
return list.contains([8, 9, 13, 32], keyCode); | ||
}, | ||
/** | ||
* @property {Object} nameFromCode | ||
* @property {String} nameFromCode.8 "BACKSPACE" | ||
*/ | ||
nameFromCode: { | ||
'8': 'BACKSPACE', | ||
'9': 'TAB', | ||
'13': 'ENTER', | ||
'32': 'SPACE', | ||
var key = (function () { | ||
var keyMap = { | ||
'BACKSPACE': 8, | ||
'TAB': 9, | ||
'ENTER': 13, | ||
'SPACE': 32, | ||
// Number: 0-9 | ||
'48': 'NUM0', | ||
'49': 'NUM1', | ||
'50': 'NUM2', | ||
'51': 'NUM3', | ||
'52': 'NUM4', | ||
'53': 'NUM5', | ||
'54': 'NUM6', | ||
'55': 'NUM7', | ||
'56': 'NUM8', | ||
'NUM0': 48, | ||
'NUM1': 49, | ||
'NUM2': 50, | ||
'NUM3': 51, | ||
'NUM4': 52, | ||
'NUM5': 53, | ||
'NUM6': 54, | ||
'NUM7': 55, | ||
'NUM8': 56, | ||
// Alphabet: a-z | ||
'66': 'B', | ||
'69': 'E', | ||
'73': 'I', | ||
'74': 'J', | ||
'75': 'K', | ||
'76': 'L', | ||
'82': 'R', | ||
'83': 'S', | ||
'85': 'U', | ||
'89': 'Y', | ||
'90': 'Z', | ||
'B': 66, | ||
'E': 69, | ||
'I': 73, | ||
'J': 74, | ||
'K': 75, | ||
'L': 76, | ||
'R': 82, | ||
'S': 83, | ||
'U': 85, | ||
'Y': 89, | ||
'Z': 90, | ||
'191': 'SLASH', | ||
'219': 'LEFTBRACKET', | ||
'220': 'BACKSLASH', | ||
'221': 'RIGHTBRACKET' | ||
} | ||
}; | ||
'SLASH': 191, | ||
'LEFTBRACKET': 219, | ||
'BACKSLASH': 220, | ||
'RIGHTBRACKET': 221 | ||
}; | ||
return { | ||
/** | ||
* @method isEdit | ||
* | ||
* @param {Number} keyCode | ||
* @return {Boolean} | ||
*/ | ||
isEdit: function (keyCode) { | ||
return list.contains([8, 9, 13, 32], keyCode); | ||
}, | ||
/** | ||
* @property {Object} nameFromCode | ||
* @property {String} nameFromCode.8 "BACKSPACE" | ||
*/ | ||
nameFromCode: func.invertObject(keyMap), | ||
code: keyMap | ||
}; | ||
})(); | ||
return key; | ||
}); |
@@ -186,7 +186,33 @@ define([ | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Moves the scrollbar to start container(sc) of current range | ||
* | ||
* @return {WrappedRange} | ||
*/ | ||
this.scrollIntoView = function () { | ||
if (this.sc.scrollIntoView) { | ||
this.sc.scrollIntoView(false); | ||
} | ||
return this; | ||
}; | ||
/** | ||
* set a focus into start container of current range | ||
* | ||
* @return {WrappedRange} | ||
*/ | ||
this.focus = function () { | ||
this.sc.focus(); | ||
return this; | ||
}; | ||
/** | ||
* @return {WrappedRange} | ||
*/ | ||
this.normalize = function () { | ||
@@ -491,2 +517,17 @@ | ||
}; | ||
/** | ||
* insert html at current cursor | ||
*/ | ||
this.pasteHTML = function (markup) { | ||
var self = this; | ||
var contentsContainer = $('<div></div>').html(markup)[0]; | ||
var childNodes = list.from(contentsContainer.childNodes); | ||
this.wrapBodyInlineWithPara().deleteContents(); | ||
return $.map(childNodes.reverse(), function (childNode) { | ||
return self.insertNode(childNode); | ||
}).reverse(); | ||
}; | ||
@@ -502,2 +543,33 @@ /** | ||
}; | ||
/** | ||
* returns range for word before cursor | ||
* | ||
* @param {Boolean} [findAfter] - find after cursor, default: false | ||
* @return {WrappedRange} | ||
*/ | ||
this.getWordRange = function (findAfter) { | ||
var endPoint = this.getEndPoint(); | ||
if (!dom.isCharPoint(endPoint)) { | ||
return this; | ||
} | ||
var startPoint = dom.prevPointUntil(endPoint, function (point) { | ||
return !dom.isCharPoint(point); | ||
}); | ||
if (findAfter) { | ||
endPoint = dom.nextPointUntil(endPoint, function (point) { | ||
return !dom.isCharPoint(point); | ||
}); | ||
} | ||
return new WrappedRange( | ||
startPoint.node, | ||
startPoint.offset, | ||
endPoint.node, | ||
endPoint.offset | ||
); | ||
}; | ||
@@ -504,0 +576,0 @@ /** |
@@ -190,3 +190,5 @@ define([ | ||
offset: dom.position(last) + 1 | ||
}, true) : null; | ||
}, { | ||
isSkipPaddingBlankHTML: true | ||
}) : null; | ||
@@ -196,3 +198,5 @@ var middleList = dom.splitTree(headList, { | ||
offset: dom.position(head) | ||
}, true); | ||
}, { | ||
isSkipPaddingBlankHTML: true | ||
}); | ||
@@ -199,0 +203,0 @@ paras = isEscapseToBody ? dom.listDescendant(middleList, dom.isLi) : |
@@ -14,3 +14,3 @@ define(['summernote/core/range'], function (range) { | ||
var rng = range.create(); | ||
var emptyBookmark = {s: {path: [0], offset: 0}, e: {path: [0], offset: 0}}; | ||
var emptyBookmark = {s: {path: [], offset: 0}, e: {path: [], offset: 0}}; | ||
@@ -17,0 +17,0 @@ return { |
@@ -17,2 +17,3 @@ define([ | ||
* | ||
* [workaround] for old jQuery | ||
* passing an array of style properties to .css() | ||
@@ -19,0 +20,0 @@ * will result in an object of property-value pairs. |
define([ | ||
'summernote/core/dom', | ||
'summernote/core/range' | ||
], function (dom, range) { | ||
'summernote/core/range', | ||
'summernote/editing/Bullet' | ||
], function (dom, range, Bullet) { | ||
@@ -14,2 +15,5 @@ /** | ||
// a Bullet instance to toggle lists off | ||
var bullet = new Bullet(); | ||
/** | ||
@@ -49,10 +53,18 @@ * insert tab | ||
if (splitRoot) { | ||
nextPara = dom.splitTree(splitRoot, rng.getStartPoint()); | ||
// if it is an empty line with li | ||
if (dom.isEmpty(splitRoot) && dom.isLi(splitRoot)) { | ||
// disable UL/OL and escape! | ||
bullet.toggleList(splitRoot.parentNode.nodeName); | ||
return; | ||
// if new line has content (not a line break) | ||
} else { | ||
nextPara = dom.splitTree(splitRoot, rng.getStartPoint()); | ||
var emptyAnchors = dom.listDescendant(splitRoot, dom.isEmptyAnchor); | ||
emptyAnchors = emptyAnchors.concat(dom.listDescendant(nextPara, dom.isEmptyAnchor)); | ||
var emptyAnchors = dom.listDescendant(splitRoot, dom.isEmptyAnchor); | ||
emptyAnchors = emptyAnchors.concat(dom.listDescendant(nextPara, dom.isEmptyAnchor)); | ||
$.each(emptyAnchors, function (idx, anchor) { | ||
dom.remove(anchor); | ||
}); | ||
$.each(emptyAnchors, function (idx, anchor) { | ||
dom.remove(anchor); | ||
}); | ||
} | ||
// no paragraph: insert empty paragraph | ||
@@ -69,3 +81,4 @@ } else { | ||
range.create(nextPara, 0).normalize().select(); | ||
range.create(nextPara, 0).normalize().select().focus().scrollIntoView(); | ||
}; | ||
@@ -72,0 +85,0 @@ |
define([ | ||
'summernote/core/agent', 'summernote/core/dom', 'summernote/core/async', 'summernote/core/key', 'summernote/core/list', | ||
'summernote/editing/Style', 'summernote/editing/Editor', 'summernote/editing/History', | ||
'summernote/module/Toolbar', 'summernote/module/Popover', 'summernote/module/Handle', 'summernote/module/Dialog' | ||
], function (agent, dom, async, key, list, | ||
Style, Editor, History, | ||
Toolbar, Popover, Handle, Dialog) { | ||
'summernote/core/agent', | ||
'summernote/core/func', | ||
'summernote/core/dom', | ||
'summernote/core/async', | ||
'summernote/core/key', | ||
'summernote/core/list', | ||
'summernote/editing/History', | ||
'summernote/module/Editor', | ||
'summernote/module/Toolbar', | ||
'summernote/module/Statusbar', | ||
'summernote/module/Popover', | ||
'summernote/module/Handle', | ||
'summernote/module/Fullscreen', | ||
'summernote/module/Codeview', | ||
'summernote/module/DragAndDrop', | ||
'summernote/module/Clipboard', | ||
'summernote/module/LinkDialog', | ||
'summernote/module/ImageDialog', | ||
'summernote/module/HelpDialog' | ||
], function (agent, func, dom, async, key, list, History, | ||
Editor, Toolbar, Statusbar, Popover, Handle, Fullscreen, Codeview, | ||
DragAndDrop, Clipboard, LinkDialog, ImageDialog, HelpDialog) { | ||
var CodeMirror; | ||
if (agent.hasCodeMirror) { | ||
if (agent.isSupportAmd) { | ||
require(['CodeMirror'], function (cm) { | ||
CodeMirror = cm; | ||
}); | ||
} else { | ||
CodeMirror = window.CodeMirror; | ||
} | ||
} | ||
/** | ||
@@ -24,40 +29,65 @@ * @class EventHandler | ||
* EventHandler | ||
* - TODO: new instance per a editor | ||
* - TODO: rename EventHandler | ||
*/ | ||
var EventHandler = function () { | ||
var $window = $(window); | ||
var $document = $(document); | ||
var $scrollbar = $('html, body'); | ||
/** | ||
* Modules | ||
*/ | ||
var modules = this.modules = { | ||
editor: new Editor(this), | ||
toolbar: new Toolbar(this), | ||
statusbar: new Statusbar(this), | ||
popover: new Popover(this), | ||
handle: new Handle(this), | ||
fullscreen: new Fullscreen(this), | ||
codeview: new Codeview(this), | ||
dragAndDrop: new DragAndDrop(this), | ||
clipboard: new Clipboard(this), | ||
linkDialog: new LinkDialog(this), | ||
imageDialog: new ImageDialog(this), | ||
helpDialog: new HelpDialog(this) | ||
}; | ||
var editor = new Editor(); | ||
var toolbar = new Toolbar(), popover = new Popover(); | ||
var handle = new Handle(), dialog = new Dialog(); | ||
// TODO refactor modules and eventHandler | ||
// - remove this method and use custom event from $holder instead | ||
this.invoke = function () { | ||
var moduleAndMethod = list.head(list.from(arguments)); | ||
var args = list.tail(list.from(arguments)); | ||
var splits = moduleAndMethod.split('.'); | ||
var hasSeparator = splits.length > 1; | ||
var moduleName = hasSeparator && list.head(splits); | ||
var methodName = hasSeparator ? list.last(splits) : list.head(splits); | ||
var module = this.getModule(moduleName); | ||
var method = module[methodName]; | ||
return method && method.apply(module, args); | ||
}; | ||
/** | ||
* get editor | ||
* @returns {editing.Editor} | ||
* returns module | ||
* | ||
* @param {String} moduleName - name of module | ||
* @return {Module} - defaults is editor | ||
*/ | ||
this.getEditor = function () { | ||
return editor; | ||
this.getModule = function (moduleName) { | ||
return this.modules[moduleName] || this.modules.editor; | ||
}; | ||
/** | ||
* returns makeLayoutInfo from editor's descendant node. | ||
* | ||
* @private | ||
* @param {Node} descendant | ||
* @return {Object} | ||
* @param {jQuery} $holder | ||
* @param {Object} callbacks | ||
* @param {String} eventNamespace | ||
* @returns {Function} | ||
*/ | ||
var makeLayoutInfo = function (descendant) { | ||
var $target = $(descendant).closest('.note-editor, .note-air-editor, .note-air-layout'); | ||
if (!$target.length) { return null; } | ||
var $editor; | ||
if ($target.is('.note-editor, .note-air-editor')) { | ||
$editor = $target; | ||
} else { | ||
$editor = $('#note-editor-' + list.last($target.attr('id').split('-'))); | ||
} | ||
return dom.buildLayoutInfo($editor); | ||
var bindCustomEvent = this.bindCustomEvent = function ($holder, callbacks, eventNamespace) { | ||
return function () { | ||
var callback = callbacks[func.namespaceToCamel(eventNamespace, 'on')]; | ||
if (callback) { | ||
callback(arguments); | ||
} | ||
return $holder.trigger('summernote.' + eventNamespace, arguments); | ||
}; | ||
}; | ||
@@ -72,5 +102,6 @@ | ||
*/ | ||
var insertImages = function (layoutInfo, files) { | ||
this.insertImages = function (layoutInfo, files) { | ||
var $editor = layoutInfo.editor(), | ||
$editable = layoutInfo.editable(); | ||
$editable = layoutInfo.editable(), | ||
$holder = layoutInfo.holder(); | ||
@@ -82,3 +113,3 @@ var callbacks = $editable.data('callbacks'); | ||
if (callbacks.onImageUpload) { | ||
callbacks.onImageUpload(files, editor, $editable); | ||
bindCustomEvent($holder, callbacks, 'image.upload')([files]); | ||
// else insert Image as dataURL | ||
@@ -89,14 +120,8 @@ } else { | ||
if (options.maximumImageFileSize && options.maximumImageFileSize < file.size) { | ||
if (callbacks.onImageUploadError) { | ||
callbacks.onImageUploadError(options.langInfo.image.maximumFileSizeError); | ||
} else { | ||
alert(options.langInfo.image.maximumFileSizeError); | ||
} | ||
bindCustomEvent($holder, callbacks, 'image.upload.error')(options.langInfo.image.maximumFileSizeError); | ||
} else { | ||
async.readFileAsDataURL(file).then(function (sDataURL) { | ||
editor.insertImage($editable, sDataURL, filename); | ||
modules.editor.insertImage($editable, sDataURL, filename); | ||
}).fail(function () { | ||
if (callbacks.onImageUploadError) { | ||
callbacks.onImageUploadError(); | ||
} | ||
bindCustomEvent($holder, callbacks, 'image.upload.error')(options.langInfo.image.maximumFileSizeError); | ||
}); | ||
@@ -113,18 +138,3 @@ } | ||
showLinkDialog: function (layoutInfo) { | ||
var $editor = layoutInfo.editor(), | ||
$dialog = layoutInfo.dialog(), | ||
$editable = layoutInfo.editable(), | ||
linkInfo = editor.getLinkInfo($editable); | ||
var options = $editor.data('options'); | ||
editor.saveRange($editable); | ||
dialog.showLinkDialog($editable, $dialog, linkInfo).then(function (linkInfo) { | ||
editor.restoreRange($editable); | ||
editor.createLink($editable, linkInfo, options); | ||
// hide popover after creating link | ||
popover.hide(layoutInfo.popover()); | ||
}).fail(function () { | ||
editor.restoreRange($editable); | ||
}); | ||
modules.linkDialog.show(layoutInfo); | ||
}, | ||
@@ -136,19 +146,3 @@ | ||
showImageDialog: function (layoutInfo) { | ||
var $dialog = layoutInfo.dialog(), | ||
$editable = layoutInfo.editable(); | ||
editor.saveRange($editable); | ||
dialog.showImageDialog($editable, $dialog).then(function (data) { | ||
editor.restoreRange($editable); | ||
if (typeof data === 'string') { | ||
// image url | ||
editor.insertImage($editable, data); | ||
} else { | ||
// array of files | ||
insertImages(layoutInfo, data); | ||
} | ||
}).fail(function () { | ||
editor.restoreRange($editable); | ||
}); | ||
modules.imageDialog.show(layoutInfo); | ||
}, | ||
@@ -160,104 +154,17 @@ | ||
showHelpDialog: function (layoutInfo) { | ||
var $dialog = layoutInfo.dialog(), | ||
$editable = layoutInfo.editable(); | ||
editor.saveRange($editable, true); | ||
dialog.showHelpDialog($editable, $dialog).then(function () { | ||
editor.restoreRange($editable); | ||
}); | ||
modules.helpDialog.show(layoutInfo); | ||
}, | ||
/** | ||
* @param {Object} layoutInfo | ||
*/ | ||
fullscreen: function (layoutInfo) { | ||
var $editor = layoutInfo.editor(), | ||
$toolbar = layoutInfo.toolbar(), | ||
$editable = layoutInfo.editable(), | ||
$codable = layoutInfo.codable(); | ||
var resize = function (size) { | ||
$editable.css('height', size.h); | ||
$codable.css('height', size.h); | ||
if ($codable.data('cmeditor')) { | ||
$codable.data('cmeditor').setsize(null, size.h); | ||
} | ||
}; | ||
$editor.toggleClass('fullscreen'); | ||
var isFullscreen = $editor.hasClass('fullscreen'); | ||
if (isFullscreen) { | ||
$editable.data('orgheight', $editable.css('height')); | ||
$window.on('resize', function () { | ||
resize({ | ||
h: $window.height() - $toolbar.outerHeight() | ||
}); | ||
}).trigger('resize'); | ||
$scrollbar.css('overflow', 'hidden'); | ||
} else { | ||
$window.off('resize'); | ||
resize({ | ||
h: $editable.data('orgheight') | ||
}); | ||
$scrollbar.css('overflow', 'visible'); | ||
} | ||
toolbar.updateFullscreen($toolbar, isFullscreen); | ||
modules.fullscreen.toggle(layoutInfo); | ||
}, | ||
/** | ||
* @param {Object} layoutInfo | ||
*/ | ||
codeview: function (layoutInfo) { | ||
var $editor = layoutInfo.editor(), | ||
$toolbar = layoutInfo.toolbar(), | ||
$editable = layoutInfo.editable(), | ||
$codable = layoutInfo.codable(), | ||
$popover = layoutInfo.popover(), | ||
$handle = layoutInfo.handle(); | ||
var options = $editor.data('options'); | ||
var cmEditor, server; | ||
$editor.toggleClass('codeview'); | ||
var isCodeview = $editor.hasClass('codeview'); | ||
if (isCodeview) { | ||
$codable.val(dom.html($editable, options.prettifyHtml)); | ||
$codable.height($editable.height()); | ||
toolbar.deactivate($toolbar); | ||
popover.hide($popover); | ||
handle.hide($handle); | ||
$codable.focus(); | ||
// activate CodeMirror as codable | ||
if (agent.hasCodeMirror) { | ||
cmEditor = CodeMirror.fromTextArea($codable[0], options.codemirror); | ||
// CodeMirror TernServer | ||
if (options.codemirror.tern) { | ||
server = new CodeMirror.TernServer(options.codemirror.tern); | ||
cmEditor.ternServer = server; | ||
cmEditor.on('cursorActivity', function (cm) { | ||
server.updateArgHints(cm); | ||
}); | ||
} | ||
// CodeMirror hasn't Padding. | ||
cmEditor.setSize(null, $editable.outerHeight()); | ||
$codable.data('cmEditor', cmEditor); | ||
} | ||
} else { | ||
// deactivate CodeMirror as codable | ||
if (agent.hasCodeMirror) { | ||
cmEditor = $codable.data('cmEditor'); | ||
$codable.val(cmEditor.getValue()); | ||
cmEditor.toTextArea(); | ||
} | ||
$editable.html(dom.value($codable, options.prettifyHtml) || dom.emptyPara); | ||
$editable.height(options.height ? $codable.height() : 'auto'); | ||
toolbar.activate($toolbar); | ||
$editable.focus(); | ||
} | ||
toolbar.updateCodeview(layoutInfo.toolbar(), isCodeview); | ||
modules.codeview.toggle(layoutInfo); | ||
} | ||
@@ -276,4 +183,4 @@ }; | ||
setTimeout(function () { | ||
var layoutInfo = makeLayoutInfo(event.currentTarget || event.target); | ||
var styleInfo = editor.currentStyle(event.target); | ||
var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target); | ||
var styleInfo = modules.editor.currentStyle(event.target); | ||
if (!styleInfo) { return; } | ||
@@ -283,7 +190,7 @@ | ||
if (!isAirMode) { | ||
toolbar.update(layoutInfo.toolbar(), styleInfo); | ||
modules.toolbar.update(layoutInfo.toolbar(), styleInfo); | ||
} | ||
popover.update(layoutInfo.popover(), styleInfo, isAirMode); | ||
handle.update(layoutInfo.handle(), styleInfo, isAirMode); | ||
modules.popover.update(layoutInfo.popover(), styleInfo, isAirMode); | ||
modules.handle.update(layoutInfo.handle(), styleInfo, isAirMode); | ||
}, 0); | ||
@@ -293,105 +200,8 @@ }; | ||
var hScroll = function (event) { | ||
var layoutInfo = makeLayoutInfo(event.currentTarget || event.target); | ||
var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target); | ||
//hide popover and handle when scrolled | ||
popover.hide(layoutInfo.popover()); | ||
handle.hide(layoutInfo.handle()); | ||
modules.popover.hide(layoutInfo.popover()); | ||
modules.handle.hide(layoutInfo.handle()); | ||
}; | ||
/** | ||
* paste clipboard image | ||
* | ||
* @param {Event} event | ||
*/ | ||
var hPasteClipboardImage = function (event) { | ||
var clipboardData = event.originalEvent.clipboardData; | ||
var layoutInfo = makeLayoutInfo(event.currentTarget || event.target); | ||
var $editable = layoutInfo.editable(); | ||
if (!clipboardData || !clipboardData.items || !clipboardData.items.length) { | ||
var callbacks = $editable.data('callbacks'); | ||
// only can run if it has onImageUpload method | ||
if (!callbacks.onImageUpload) { | ||
return; | ||
} | ||
// save cursor | ||
editor.saveNode($editable); | ||
editor.saveRange($editable); | ||
$editable.html(''); | ||
setTimeout(function () { | ||
var $img = $editable.find('img'); | ||
var datauri = $img[0].src; | ||
var data = atob(datauri.split(',')[1]); | ||
var array = new Uint8Array(data.length); | ||
for (var i = 0; i < data.length; i++) { | ||
array[i] = data.charCodeAt(i); | ||
} | ||
var blob = new Blob([array], { type : 'image/png'}); | ||
blob.name = 'clipboard.png'; | ||
editor.restoreNode($editable); | ||
editor.restoreRange($editable); | ||
insertImages(layoutInfo, [blob]); | ||
editor.afterCommand($editable); | ||
}, 0); | ||
return; | ||
} | ||
var item = list.head(clipboardData.items); | ||
var isClipboardImage = item.kind === 'file' && item.type.indexOf('image/') !== -1; | ||
if (isClipboardImage) { | ||
insertImages(layoutInfo, [item.getAsFile()]); | ||
} | ||
editor.afterCommand($editable); | ||
}; | ||
/** | ||
* `mousedown` event handler on $handle | ||
* - controlSizing: resize image | ||
* | ||
* @param {MouseEvent} event | ||
*/ | ||
var hHandleMousedown = function (event) { | ||
if (dom.isControlSizing(event.target)) { | ||
event.preventDefault(); | ||
event.stopPropagation(); | ||
var layoutInfo = makeLayoutInfo(event.target), | ||
$handle = layoutInfo.handle(), $popover = layoutInfo.popover(), | ||
$editable = layoutInfo.editable(), | ||
$editor = layoutInfo.editor(); | ||
var target = $handle.find('.note-control-selection').data('target'), | ||
$target = $(target), posStart = $target.offset(), | ||
scrollTop = $document.scrollTop(); | ||
var isAirMode = $editor.data('options').airMode; | ||
$document.on('mousemove', function (event) { | ||
editor.resizeTo({ | ||
x: event.clientX - posStart.left, | ||
y: event.clientY - (posStart.top - scrollTop) | ||
}, $target, !event.shiftKey); | ||
handle.update($handle, {image: target}, isAirMode); | ||
popover.update($popover, {image: target}, isAirMode); | ||
}).one('mouseup', function () { | ||
$document.off('mousemove'); | ||
editor.afterCommand($editable); | ||
}); | ||
if (!$target.data('ratio')) { // original ratio. | ||
$target.data('ratio', $target.height() / $target.width()); | ||
} | ||
} | ||
}; | ||
var hToolbarAndPopoverMousedown = function (event) { | ||
@@ -413,3 +223,3 @@ // prevent default event when insertTable (FF, Webkit) | ||
var layoutInfo = makeLayoutInfo(event.target); | ||
var layoutInfo = dom.makeLayoutInfo(event.target); | ||
@@ -430,7 +240,7 @@ // before command: detect control selection element($target) | ||
if ($.isFunction($.summernote.pluginEvents[eventName])) { | ||
$.summernote.pluginEvents[eventName](event, editor, layoutInfo, value); | ||
} else if (editor[eventName]) { // on command | ||
$.summernote.pluginEvents[eventName](event, modules.editor, layoutInfo, value); | ||
} else if (modules.editor[eventName]) { // on command | ||
var $editable = layoutInfo.editable(); | ||
$editable.trigger('focus'); | ||
editor[eventName]($editable, value, $target); | ||
$editable.focus(); | ||
modules.editor[eventName]($editable, value, $target); | ||
event.preventDefault(); | ||
@@ -445,3 +255,3 @@ } else if (commands[eventName]) { | ||
var options = layoutInfo.editor().data('options', options); | ||
var module = options.airMode ? popover : toolbar; | ||
var module = options.airMode ? modules.popover : modules.toolbar; | ||
module.updateRecentColor(list.head($btn), eventName, value); | ||
@@ -454,30 +264,2 @@ } | ||
var EDITABLE_PADDING = 24; | ||
/** | ||
* `mousedown` event handler on statusbar | ||
* | ||
* @param {MouseEvent} event | ||
*/ | ||
var hStatusbarMousedown = function (event) { | ||
event.preventDefault(); | ||
event.stopPropagation(); | ||
var $editable = makeLayoutInfo(event.target).editable(); | ||
var nEditableTop = $editable.offset().top - $document.scrollTop(); | ||
var layoutInfo = makeLayoutInfo(event.currentTarget || event.target); | ||
var options = layoutInfo.editor().data('options'); | ||
$document.on('mousemove', function (event) { | ||
var nHeight = event.clientY - (nEditableTop + EDITABLE_PADDING); | ||
nHeight = (options.minHeight > 0) ? Math.max(nHeight, options.minHeight) : nHeight; | ||
nHeight = (options.maxHeight > 0) ? Math.min(nHeight, options.maxHeight) : nHeight; | ||
$editable.height(nHeight); | ||
}).one('mouseup', function () { | ||
$document.off('mousemove'); | ||
}); | ||
}; | ||
var PX_PER_EM = 18; | ||
@@ -524,88 +306,4 @@ var hDimensionPickerMove = function (event, options) { | ||
}; | ||
/** | ||
* Drag and Drop Events | ||
* | ||
* @param {Object} layoutInfo - layout Informations | ||
* @param {Object} options | ||
*/ | ||
var handleDragAndDropEvent = function (layoutInfo, options) { | ||
if (options.disableDragAndDrop) { | ||
// prevent default drop event | ||
$document.on('drop', function (e) { | ||
e.preventDefault(); | ||
}); | ||
} else { | ||
attachDragAndDropEvent(layoutInfo, options); | ||
} | ||
}; | ||
/** | ||
* attach Drag and Drop Events | ||
* | ||
* @param {Object} layoutInfo - layout Informations | ||
* @param {Object} options | ||
*/ | ||
var attachDragAndDropEvent = function (layoutInfo, options) { | ||
var collection = $(), | ||
$dropzone = layoutInfo.dropzone, | ||
$dropzoneMessage = layoutInfo.dropzone.find('.note-dropzone-message'); | ||
// show dropzone on dragenter when dragging a object to document | ||
// -but only if the editor is visible, i.e. has a positive width and height | ||
$document.on('dragenter', function (e) { | ||
var isCodeview = layoutInfo.editor.hasClass('codeview'); | ||
if (!isCodeview && !collection.length && layoutInfo.editor.width() > 0 && layoutInfo.editor.height() > 0) { | ||
layoutInfo.editor.addClass('dragover'); | ||
$dropzone.width(layoutInfo.editor.width()); | ||
$dropzone.height(layoutInfo.editor.height()); | ||
$dropzoneMessage.text(options.langInfo.image.dragImageHere); | ||
} | ||
collection = collection.add(e.target); | ||
}).on('dragleave', function (e) { | ||
collection = collection.not(e.target); | ||
if (!collection.length) { | ||
layoutInfo.editor.removeClass('dragover'); | ||
} | ||
}).on('drop', function () { | ||
collection = $(); | ||
layoutInfo.editor.removeClass('dragover'); | ||
}); | ||
// change dropzone's message on hover. | ||
$dropzone.on('dragenter', function () { | ||
$dropzone.addClass('hover'); | ||
$dropzoneMessage.text(options.langInfo.image.dropImage); | ||
}).on('dragleave', function () { | ||
$dropzone.removeClass('hover'); | ||
$dropzoneMessage.text(options.langInfo.image.dragImageHere); | ||
}); | ||
// attach dropImage | ||
$dropzone.on('drop', function (event) { | ||
event.preventDefault(); | ||
var dataTransfer = event.originalEvent.dataTransfer; | ||
var html = dataTransfer.getData('text/html'); | ||
var text = dataTransfer.getData('text/plain'); | ||
var layoutInfo = makeLayoutInfo(event.currentTarget || event.target); | ||
if (dataTransfer && dataTransfer.files && dataTransfer.files.length) { | ||
layoutInfo.editable().focus(); | ||
insertImages(layoutInfo, dataTransfer.files); | ||
} else if (html) { | ||
$(html).each(function () { | ||
layoutInfo.editable().focus(); | ||
editor.insertNode(layoutInfo.editable(), this); | ||
}); | ||
} else if (text) { | ||
layoutInfo.editable().focus(); | ||
editor.insertText(layoutInfo.editable(), text); | ||
} | ||
}).on('dragover', false); // prevent default dragover event | ||
}; | ||
/** | ||
* bind KeyMap on keydown | ||
@@ -617,20 +315,20 @@ * | ||
this.bindKeyMap = function (layoutInfo, keyMap) { | ||
var $editor = layoutInfo.editor; | ||
var $editable = layoutInfo.editable; | ||
var $editor = layoutInfo.editor(); | ||
var $editable = layoutInfo.editable(); | ||
layoutInfo = makeLayoutInfo($editable); | ||
$editable.on('keydown', function (event) { | ||
var aKey = []; | ||
var keys = []; | ||
// modifier | ||
if (event.metaKey) { aKey.push('CMD'); } | ||
if (event.ctrlKey && !event.altKey) { aKey.push('CTRL'); } | ||
if (event.shiftKey) { aKey.push('SHIFT'); } | ||
if (event.metaKey) { keys.push('CMD'); } | ||
if (event.ctrlKey && !event.altKey) { keys.push('CTRL'); } | ||
if (event.shiftKey) { keys.push('SHIFT'); } | ||
// keycode | ||
var keyName = key.nameFromCode[event.keyCode]; | ||
if (keyName) { aKey.push(keyName); } | ||
if (keyName) { | ||
keys.push(keyName); | ||
} | ||
var eventName = keyMap[aKey.join('+')]; | ||
var eventName = keyMap[keys.join('+')]; | ||
if (eventName) { | ||
@@ -640,6 +338,6 @@ if ($.summernote.pluginEvents[eventName]) { | ||
if ($.isFunction(plugin)) { | ||
plugin(event, editor, layoutInfo); | ||
plugin(event, modules.editor, layoutInfo); | ||
} | ||
} else if (editor[eventName]) { | ||
editor[eventName]($editable, $editor.data('options')); | ||
} else if (modules.editor[eventName]) { | ||
modules.editor[eventName]($editable, $editor.data('options')); | ||
event.preventDefault(); | ||
@@ -651,3 +349,3 @@ } else if (commands[eventName]) { | ||
} else if (key.isEdit(event.keyCode)) { | ||
editor.afterCommand($editable); | ||
modules.editor.afterCommand($editable); | ||
} | ||
@@ -662,10 +360,2 @@ }); | ||
* @param {Object} options - user options include custom event handlers | ||
* @param {function(event)} [options.onenter] - enter key handler | ||
* @param {function(event)} [options.onfocus] | ||
* @param {function(event)} [options.onblur] | ||
* @param {function(event)} [options.onkeyup] | ||
* @param {function(event)} [options.onkeydown] | ||
* @param {function(event)} [options.onpaste] | ||
* @param {function(event)} [options.onToolBarclick] | ||
* @param {function(event)} [options.onChange] | ||
*/ | ||
@@ -677,30 +367,28 @@ this.attach = function (layoutInfo, options) { | ||
} | ||
layoutInfo.editable.on('mousedown', hMousedown); | ||
layoutInfo.editable.on('keyup mouseup', hToolbarAndPopoverUpdate); | ||
layoutInfo.editable.on('scroll', hScroll); | ||
layoutInfo.editable.on('paste', hPasteClipboardImage); | ||
layoutInfo.editable().on('mousedown', hMousedown); | ||
layoutInfo.editable().on('keyup mouseup', hToolbarAndPopoverUpdate); | ||
layoutInfo.editable().on('scroll', hScroll); | ||
modules.clipboard.attach(layoutInfo, options); | ||
// handler for handle and popover | ||
layoutInfo.handle.on('mousedown', hHandleMousedown); | ||
layoutInfo.popover.on('click', hToolbarAndPopoverClick); | ||
layoutInfo.popover.on('mousedown', hToolbarAndPopoverMousedown); | ||
modules.handle.attach(layoutInfo, options); | ||
layoutInfo.popover().on('click', hToolbarAndPopoverClick); | ||
layoutInfo.popover().on('mousedown', hToolbarAndPopoverMousedown); | ||
// handler for drag and drop | ||
modules.dragAndDrop.attach(layoutInfo, options); | ||
// handlers for frame mode (toolbar, statusbar) | ||
if (!options.airMode) { | ||
// handler for drag and drop | ||
handleDragAndDropEvent(layoutInfo, options); | ||
// handler for toolbar | ||
layoutInfo.toolbar.on('click', hToolbarAndPopoverClick); | ||
layoutInfo.toolbar.on('mousedown', hToolbarAndPopoverMousedown); | ||
layoutInfo.toolbar().on('click', hToolbarAndPopoverClick); | ||
layoutInfo.toolbar().on('mousedown', hToolbarAndPopoverMousedown); | ||
// handler for statusbar | ||
if (!options.disableResizeEditor) { | ||
layoutInfo.statusbar.on('mousedown', hStatusbarMousedown); | ||
} | ||
modules.statusbar.attach(layoutInfo, options); | ||
} | ||
// handler for table dimension | ||
var $catcherContainer = options.airMode ? layoutInfo.popover : | ||
layoutInfo.toolbar; | ||
var $catcherContainer = options.airMode ? layoutInfo.popover() : | ||
layoutInfo.toolbar(); | ||
var $catcher = $catcherContainer.find('.note-dimension-picker-mousecatcher'); | ||
@@ -715,7 +403,8 @@ $catcher.css({ | ||
// save options on editor | ||
layoutInfo.editor.data('options', options); | ||
layoutInfo.editor().data('options', options); | ||
// ret styleWithCSS for backColor / foreColor clearing with 'inherit'. | ||
if (!agent.isMSIE) { | ||
// protect FF Error: NS_ERROR_FAILURE: Failure | ||
// [workaround] for Firefox | ||
// - protect FF Error: NS_ERROR_FAILURE: Failure | ||
setTimeout(function () { | ||
@@ -727,59 +416,108 @@ document.execCommand('styleWithCSS', 0, options.styleWithSpan); | ||
// History | ||
var history = new History(layoutInfo.editable); | ||
layoutInfo.editable.data('NoteHistory', history); | ||
var history = new History(layoutInfo.editable()); | ||
layoutInfo.editable().data('NoteHistory', history); | ||
// basic event callbacks (lowercase) | ||
// enter, focus, blur, keyup, keydown | ||
if (options.onenter) { | ||
layoutInfo.editable.keypress(function (event) { | ||
if (event.keyCode === key.ENTER) { options.onenter(event); } | ||
// All editor status will be saved on editable with jquery's data | ||
// for support multiple editor with singleton object. | ||
layoutInfo.editable().data('callbacks', { | ||
onInit: options.onInit, | ||
onFocus: options.onFocus, | ||
onBlur: options.onBlur, | ||
onKeydown: options.onKeydown, | ||
onKeyup: options.onKeyup, | ||
onMousedown: options.onMousedown, | ||
onEnter: options.onEnter, | ||
onPaste: options.onPaste, | ||
onBeforeCommand: options.onBeforeCommand, | ||
onChange: options.onChange, | ||
onImageUpload: options.onImageUpload, | ||
onImageUploadError: options.onImageUploadError, | ||
onMediaDelete : options.onMediaDelete | ||
}); | ||
// Textarea: auto filling the code before form submit. | ||
if (dom.isTextarea(list.head(layoutInfo.holder()))) { | ||
layoutInfo.holder().closest('form').submit(function () { | ||
var contents = layoutInfo.holder().code(); | ||
layoutInfo.holder().val(contents); | ||
// callback on submit | ||
if (options.onsubmit) { | ||
options.onsubmit(contents); | ||
} | ||
}); | ||
} | ||
}; | ||
if (options.onfocus) { layoutInfo.editable.focus(options.onfocus); } | ||
if (options.onblur) { layoutInfo.editable.blur(options.onblur); } | ||
if (options.onkeyup) { layoutInfo.editable.keyup(options.onkeyup); } | ||
if (options.onkeydown) { layoutInfo.editable.keydown(options.onkeydown); } | ||
if (options.onpaste) { layoutInfo.editable.on('paste', options.onpaste); } | ||
/** | ||
* attach jquery custom event | ||
* | ||
* @param {Object} layoutInfo - layout Informations | ||
*/ | ||
this.attachCustomEvent = function (layoutInfo, options) { | ||
var $holder = layoutInfo.holder(); | ||
var $editable = layoutInfo.editable(); | ||
var callbacks = $editable.data('callbacks'); | ||
$editable.focus(bindCustomEvent($holder, callbacks, 'focus')); | ||
$editable.blur(bindCustomEvent($holder, callbacks, 'blur')); | ||
$editable.keydown(function (event) { | ||
if (event.keyCode === key.code.ENTER) { | ||
bindCustomEvent($holder, callbacks, 'enter').call(this, event); | ||
} | ||
bindCustomEvent($holder, callbacks, 'keydown').call(this, event); | ||
}); | ||
$editable.keyup(bindCustomEvent($holder, callbacks, 'keyup')); | ||
$editable.on('mousedown', bindCustomEvent($holder, callbacks, 'mousedown')); | ||
$editable.on('mouseup', bindCustomEvent($holder, callbacks, 'mouseup')); | ||
$editable.on('scroll', bindCustomEvent($holder, callbacks, 'scroll')); | ||
$editable.on('paste', bindCustomEvent($holder, callbacks, 'paste')); | ||
// [workaround] for old IE - IE8 don't have input events | ||
if (agent.isMSIE) { | ||
var sDomEvents = 'DOMCharacterDataModified DOMSubtreeModified DOMNodeInserted'; | ||
$editable.on(sDomEvents, bindCustomEvent($holder, callbacks, 'change')); | ||
} else { | ||
$editable.on('input', bindCustomEvent($holder, callbacks, 'change')); | ||
} | ||
// callbacks for advanced features (camel) | ||
if (options.onToolbarClick) { layoutInfo.toolbar.click(options.onToolbarClick); } | ||
if (options.onChange) { | ||
var hChange = function () { | ||
editor.triggerOnChange(layoutInfo.editable); | ||
}; | ||
if (!options.airMode) { | ||
layoutInfo.toolbar().click(bindCustomEvent($holder, callbacks, 'toolbar.click')); | ||
layoutInfo.popover().click(bindCustomEvent($holder, callbacks, 'popover.click')); | ||
} | ||
if (agent.isMSIE) { | ||
var sDomEvents = 'DOMCharacterDataModified DOMSubtreeModified DOMNodeInserted'; | ||
layoutInfo.editable.on(sDomEvents, hChange); | ||
} else { | ||
layoutInfo.editable.on('input', hChange); | ||
// Textarea: auto filling the code before form submit. | ||
if (dom.isTextarea(list.head($holder))) { | ||
$holder.closest('form').submit(function (e) { | ||
bindCustomEvent($holder, callbacks, 'submit').call(this, e, $holder.code()); | ||
}); | ||
} | ||
// fire init event | ||
bindCustomEvent($holder, callbacks, 'init')(layoutInfo); | ||
// fire plugin init event | ||
for (var i = 0, len = $.summernote.plugins.length; i < len; i++) { | ||
if ($.isFunction($.summernote.plugins[i].init)) { | ||
$.summernote.plugins[i].init(layoutInfo); | ||
} | ||
} | ||
// All editor status will be saved on editable with jquery's data | ||
// for support multiple editor with singleton object. | ||
layoutInfo.editable.data('callbacks', { | ||
onBeforeChange: options.onBeforeChange, | ||
onChange: options.onChange, | ||
onAutoSave: options.onAutoSave, | ||
onImageUpload: options.onImageUpload, | ||
onImageUploadError: options.onImageUploadError, | ||
onFileUpload: options.onFileUpload, | ||
onFileUploadError: options.onFileUpload, | ||
onMediaDelete : options.onMediaDelete | ||
}); | ||
}; | ||
this.detach = function (layoutInfo, options) { | ||
layoutInfo.editable.off(); | ||
layoutInfo.holder().off(); | ||
layoutInfo.editable().off(); | ||
layoutInfo.popover.off(); | ||
layoutInfo.handle.off(); | ||
layoutInfo.dialog.off(); | ||
layoutInfo.popover().off(); | ||
layoutInfo.handle().off(); | ||
layoutInfo.dialog().off(); | ||
if (!options.airMode) { | ||
layoutInfo.dropzone.off(); | ||
layoutInfo.toolbar.off(); | ||
layoutInfo.statusbar.off(); | ||
layoutInfo.dropzone().off(); | ||
layoutInfo.toolbar().off(); | ||
layoutInfo.statusbar().off(); | ||
} | ||
@@ -786,0 +524,0 @@ }; |
define([ | ||
'summernote/core/list' | ||
], function (list) { | ||
'summernote/core/list', | ||
'summernote/core/agent' | ||
], function (list, agent) { | ||
/** | ||
@@ -87,6 +88,14 @@ * @class module.Button | ||
if (!!selectedFont) { | ||
selectedFont = list.head(selectedFont.split(',')); | ||
selectedFont = selectedFont.replace(/\'/g, ''); | ||
var list = selectedFont.split(','); | ||
for (var i = 0, len = list.length; i < len; i++) { | ||
selectedFont = list[i].replace(/[\'\"]/g, '').replace(/\s+$/, '').replace(/^\s+/, ''); | ||
if (agent.isFontInstalled(selectedFont)) { | ||
break; | ||
} | ||
} | ||
$fontname.find('.note-current-fontname').text(selectedFont); | ||
checkDropdownMenu($fontname, selectedFont); | ||
} | ||
@@ -93,0 +102,0 @@ } |
@@ -1,2 +0,4 @@ | ||
define('summernote/module/Handle', function () { | ||
define([ | ||
'summernote/core/dom' | ||
], function (dom) { | ||
/** | ||
@@ -7,4 +9,52 @@ * @class module.Handle | ||
*/ | ||
var Handle = function () { | ||
var Handle = function (handler) { | ||
var $document = $(document); | ||
/** | ||
* `mousedown` event handler on $handle | ||
* - controlSizing: resize image | ||
* | ||
* @param {MouseEvent} event | ||
*/ | ||
var hHandleMousedown = function (event) { | ||
if (dom.isControlSizing(event.target)) { | ||
event.preventDefault(); | ||
event.stopPropagation(); | ||
var layoutInfo = dom.makeLayoutInfo(event.target), | ||
$handle = layoutInfo.handle(), | ||
$popover = layoutInfo.popover(), | ||
$editable = layoutInfo.editable(), | ||
$editor = layoutInfo.editor(); | ||
var target = $handle.find('.note-control-selection').data('target'), | ||
$target = $(target), posStart = $target.offset(), | ||
scrollTop = $document.scrollTop(); | ||
var isAirMode = $editor.data('options').airMode; | ||
$document.on('mousemove', function (event) { | ||
handler.invoke('editor.resizeTo', { | ||
x: event.clientX - posStart.left, | ||
y: event.clientY - (posStart.top - scrollTop) | ||
}, $target, !event.shiftKey); | ||
handler.invoke('handle.update', $handle, {image: target}, isAirMode); | ||
handler.invoke('popover.update', $popover, {image: target}, isAirMode); | ||
}).one('mouseup', function () { | ||
$document.off('mousemove'); | ||
handler.invoke('editor.afterCommand', $editable); | ||
}); | ||
if (!$target.data('ratio')) { // original ratio. | ||
$target.data('ratio', $target.height() / $target.width()); | ||
} | ||
} | ||
}; | ||
this.attach = function (layoutInfo) { | ||
layoutInfo.handle().on('mousedown', hHandleMousedown); | ||
}; | ||
/** | ||
* update handle | ||
@@ -11,0 +61,0 @@ * @param {jQuery} $handle |
@@ -67,3 +67,9 @@ define([ | ||
var href = $(styleInfo.anchor).attr('href'); | ||
var target = $(styleInfo.anchor).attr('target'); | ||
$anchor.attr('href', href).html(href); | ||
if (!target) { | ||
$anchor.removeAttr('target'); | ||
} else { | ||
$anchor.attr('target', '_blank'); | ||
} | ||
showPopover($linkPopover, posFromPlaceholder(styleInfo.anchor, isAirMode)); | ||
@@ -70,0 +76,0 @@ } else { |
define([ | ||
'summernote/core/list', | ||
'summernote/core/dom', | ||
'summernote/module/Button' | ||
], function (list, Button) { | ||
], function (list, dom, Button) { | ||
/** | ||
@@ -47,3 +48,2 @@ * @class module.Toolbar | ||
/** | ||
* | ||
* @param {jQuery} $container | ||
@@ -58,3 +58,2 @@ * @param {Boolean} [bFullscreen=false] | ||
/** | ||
* | ||
* @param {jQuery} $container | ||
@@ -66,3 +65,35 @@ * @param {Boolean} [isCodeview=false] | ||
$btn.toggleClass('active', isCodeview); | ||
if (isCodeview) { | ||
this.deactivate($container); | ||
} else { | ||
this.activate($container); | ||
} | ||
}; | ||
/** | ||
* get button in toolbar | ||
* | ||
* @param {jQuery} $editable | ||
* @param {String} name | ||
* @return {jQuery} | ||
*/ | ||
this.get = function ($editable, name) { | ||
var $toolbar = dom.makeLayoutInfo($editable).toolbar(); | ||
return $toolbar.find('[data-name=' + name + ']'); | ||
}; | ||
/** | ||
* set button state | ||
* @param {jQuery} $editable | ||
* @param {String} name | ||
* @param {Boolean} [isActive=true] | ||
*/ | ||
this.setButtonState = function ($editable, name, isActive) { | ||
isActive = (isActive === false) ? false : true; | ||
var $button = this.get($editable, name); | ||
$button.toggleClass('active', isActive); | ||
}; | ||
}; | ||
@@ -69,0 +100,0 @@ |
define([ | ||
'summernote/core/agent', 'summernote/core/dom', 'summernote/core/func' | ||
'summernote/core/agent', | ||
'summernote/core/dom', | ||
'summernote/core/func' | ||
], function (agent, dom, func) { | ||
@@ -72,8 +74,10 @@ /** | ||
var tplPopover = function (className, content) { | ||
return '<div class="' + className + ' popover bottom in" style="display: none;">' + | ||
var $popover = $('<div class="' + className + ' popover bottom in" style="display: none;">' + | ||
'<div class="arrow"></div>' + | ||
'<div class="popover-content">' + | ||
content + | ||
'</div>' + | ||
'</div>'; | ||
'</div>'); | ||
$popover.find('.popover-content').append(content); | ||
return $popover; | ||
}; | ||
@@ -99,8 +103,6 @@ | ||
) + | ||
'<form class="note-modal-form">' + | ||
'<div class="modal-body">' + body + '</div>' + | ||
(footer ? | ||
'<div class="modal-footer">' + footer + '</div>' : '' | ||
) + | ||
'</form>' + | ||
'<div class="modal-body">' + body + '</div>' + | ||
(footer ? | ||
'<div class="modal-footer">' + footer + '</div>' : '' | ||
) + | ||
'</div>' + | ||
@@ -112,4 +114,4 @@ '</div>' + | ||
var tplButtonInfo = { | ||
picture: function (lang) { | ||
return tplIconButton('fa fa-picture-o', { | ||
picture: function (lang, options) { | ||
return tplIconButton(options.iconPrefix + 'picture-o', { | ||
event: 'showImageDialog', | ||
@@ -120,4 +122,4 @@ title: lang.image.image, | ||
}, | ||
link: function (lang) { | ||
return tplIconButton('fa fa-link', { | ||
link: function (lang, options) { | ||
return tplIconButton(options.iconPrefix + 'link', { | ||
event: 'showLinkDialog', | ||
@@ -128,3 +130,3 @@ title: lang.link.link, | ||
}, | ||
table: function (lang) { | ||
table: function (lang, options) { | ||
var dropdown = '<ul class="note-table dropdown-menu">' + | ||
@@ -138,3 +140,3 @@ '<div class="note-dimension-picker">' + | ||
'</ul>'; | ||
return tplIconButton('fa fa-table', { | ||
return tplIconButton(options.iconPrefix + 'table', { | ||
title: lang.table.table, | ||
@@ -155,3 +157,3 @@ dropdown: dropdown | ||
return tplIconButton('fa fa-magic', { | ||
return tplIconButton(options.iconPrefix + 'magic', { | ||
title: lang.style.style, | ||
@@ -162,2 +164,3 @@ dropdown: '<ul class="dropdown-menu">' + items + '</ul>' | ||
fontname: function (lang, options) { | ||
var realFontList = []; | ||
var items = options.fontNames.reduce(function (memo, v) { | ||
@@ -167,8 +170,13 @@ if (!agent.isFontInstalled(v) && options.fontNamesIgnoreCheck.indexOf(v) === -1) { | ||
} | ||
realFontList.push(v); | ||
return memo + '<li><a data-event="fontName" href="#" data-value="' + v + '" style="font-family:\'' + v + '\'">' + | ||
'<i class="fa fa-check"></i> ' + v + | ||
'<i class="' + options.iconPrefix + 'check"></i> ' + v + | ||
'</a></li>'; | ||
}, ''); | ||
var hasDefaultFont = agent.isFontInstalled(options.defaultFontName); | ||
var defaultFontName = (hasDefaultFont) ? options.defaultFontName : realFontList[0]; | ||
var label = '<span class="note-current-fontname">' + | ||
options.defaultFontName + | ||
defaultFontName + | ||
'</span>'; | ||
@@ -180,4 +188,17 @@ return tplButton(label, { | ||
}, | ||
color: function (lang) { | ||
var colorButtonLabel = '<i class="fa fa-font" style="color:black;background-color:yellow;"></i>'; | ||
fontsize: function (lang, options) { | ||
var items = options.fontSizes.reduce(function (memo, v) { | ||
return memo + '<li><a data-event="fontSize" href="#" data-value="' + v + '">' + | ||
'<i class="fa fa-check"></i> ' + v + | ||
'</a></li>'; | ||
}, ''); | ||
var label = '<span class="note-current-fontsize">11</span>'; | ||
return tplButton(label, { | ||
title: lang.font.size, | ||
dropdown: '<ul class="dropdown-menu">' + items + '</ul>' | ||
}); | ||
}, | ||
color: function (lang, options) { | ||
var colorButtonLabel = '<i class="' + options.iconPrefix + 'font" style="color:black;background-color:yellow;"></i>'; | ||
var colorButton = tplButton(colorButtonLabel, { | ||
@@ -217,4 +238,4 @@ className: 'note-recent-color', | ||
}, | ||
bold: function (lang) { | ||
return tplIconButton('fa fa-bold', { | ||
bold: function (lang, options) { | ||
return tplIconButton(options.iconPrefix + 'bold', { | ||
event: 'bold', | ||
@@ -224,4 +245,4 @@ title: lang.font.bold | ||
}, | ||
italic: function (lang) { | ||
return tplIconButton('fa fa-italic', { | ||
italic: function (lang, options) { | ||
return tplIconButton(options.iconPrefix + 'italic', { | ||
event: 'italic', | ||
@@ -231,4 +252,4 @@ title: lang.font.italic | ||
}, | ||
underline: function (lang) { | ||
return tplIconButton('fa fa-underline', { | ||
underline: function (lang, options) { | ||
return tplIconButton(options.iconPrefix + 'underline', { | ||
event: 'underline', | ||
@@ -238,4 +259,22 @@ title: lang.font.underline | ||
}, | ||
clear: function (lang) { | ||
return tplIconButton('fa fa-eraser', { | ||
strikethrough: function (lang) { | ||
return tplIconButton('fa fa-strikethrough', { | ||
event: 'strikethrough', | ||
title: lang.font.strikethrough | ||
}); | ||
}, | ||
superscript: function (lang) { | ||
return tplIconButton('fa fa-superscript', { | ||
event: 'superscript', | ||
title: lang.font.superscript | ||
}); | ||
}, | ||
subscript: function (lang) { | ||
return tplIconButton('fa fa-subscript', { | ||
event: 'subscript', | ||
title: lang.font.subscript | ||
}); | ||
}, | ||
clear: function (lang, options) { | ||
return tplIconButton(options.iconPrefix + 'eraser', { | ||
event: 'removeFormat', | ||
@@ -245,4 +284,4 @@ title: lang.font.clear | ||
}, | ||
ul: function (lang) { | ||
return tplIconButton('fa fa-list-ul', { | ||
ul: function (lang, options) { | ||
return tplIconButton(options.iconPrefix + 'list-ul', { | ||
event: 'insertUnorderedList', | ||
@@ -252,4 +291,4 @@ title: lang.lists.unordered | ||
}, | ||
ol: function (lang) { | ||
return tplIconButton('fa fa-list-ol', { | ||
ol: function (lang, options) { | ||
return tplIconButton(options.iconPrefix + 'list-ol', { | ||
event: 'insertOrderedList', | ||
@@ -259,16 +298,16 @@ title: lang.lists.ordered | ||
}, | ||
paragraph: function (lang) { | ||
var leftButton = tplIconButton('fa fa-align-left', { | ||
paragraph: function (lang, options) { | ||
var leftButton = tplIconButton(options.iconPrefix + 'align-left', { | ||
title: lang.paragraph.left, | ||
event: 'justifyLeft' | ||
}); | ||
var centerButton = tplIconButton('fa fa-align-center', { | ||
var centerButton = tplIconButton(options.iconPrefix + 'align-center', { | ||
title: lang.paragraph.center, | ||
event: 'justifyCenter' | ||
}); | ||
var rightButton = tplIconButton('fa fa-align-right', { | ||
var rightButton = tplIconButton(options.iconPrefix + 'align-right', { | ||
title: lang.paragraph.right, | ||
event: 'justifyRight' | ||
}); | ||
var justifyButton = tplIconButton('fa fa-align-justify', { | ||
var justifyButton = tplIconButton(options.iconPrefix + 'align-justify', { | ||
title: lang.paragraph.justify, | ||
@@ -278,7 +317,7 @@ event: 'justifyFull' | ||
var outdentButton = tplIconButton('fa fa-outdent', { | ||
var outdentButton = tplIconButton(options.iconPrefix + 'outdent', { | ||
title: lang.paragraph.outdent, | ||
event: 'outdent' | ||
}); | ||
var indentButton = tplIconButton('fa fa-indent', { | ||
var indentButton = tplIconButton(options.iconPrefix + 'indent', { | ||
title: lang.paragraph.indent, | ||
@@ -297,3 +336,3 @@ event: 'indent' | ||
return tplIconButton('fa fa-align-left', { | ||
return tplIconButton(options.iconPrefix + 'align-left', { | ||
title: lang.paragraph.paragraph, | ||
@@ -306,7 +345,7 @@ dropdown: dropdown | ||
return memo + '<li><a data-event="lineHeight" href="#" data-value="' + parseFloat(v) + '">' + | ||
'<i class="fa fa-check"></i> ' + v + | ||
'<i class="' + options.iconPrefix + 'check"></i> ' + v + | ||
'</a></li>'; | ||
}, ''); | ||
return tplIconButton('fa fa-text-height', { | ||
return tplIconButton(options.iconPrefix + 'text-height', { | ||
title: lang.font.height, | ||
@@ -317,4 +356,4 @@ dropdown: '<ul class="dropdown-menu">' + items + '</ul>' | ||
}, | ||
help: function (lang) { | ||
return tplIconButton('fa fa-question', { | ||
help: function (lang, options) { | ||
return tplIconButton(options.iconPrefix + 'question', { | ||
event: 'showHelpDialog', | ||
@@ -325,4 +364,4 @@ title: lang.options.help, | ||
}, | ||
fullscreen: function (lang) { | ||
return tplIconButton('fa fa-arrows-alt', { | ||
fullscreen: function (lang, options) { | ||
return tplIconButton(options.iconPrefix + 'arrows-alt', { | ||
event: 'fullscreen', | ||
@@ -332,4 +371,4 @@ title: lang.options.fullscreen | ||
}, | ||
codeview: function (lang) { | ||
return tplIconButton('fa fa-code', { | ||
codeview: function (lang, options) { | ||
return tplIconButton(options.iconPrefix + 'code', { | ||
event: 'codeview', | ||
@@ -339,4 +378,4 @@ title: lang.options.codeview | ||
}, | ||
undo: function (lang) { | ||
return tplIconButton('fa fa-undo', { | ||
undo: function (lang, options) { | ||
return tplIconButton(options.iconPrefix + 'undo', { | ||
event: 'undo', | ||
@@ -346,4 +385,4 @@ title: lang.history.undo | ||
}, | ||
redo: function (lang) { | ||
return tplIconButton('fa fa-repeat', { | ||
redo: function (lang, options) { | ||
return tplIconButton(options.iconPrefix + 'repeat', { | ||
event: 'redo', | ||
@@ -353,4 +392,4 @@ title: lang.history.redo | ||
}, | ||
hr: function (lang) { | ||
return tplIconButton('fa fa-minus', { | ||
hr: function (lang, options) { | ||
return tplIconButton(options.iconPrefix + 'minus', { | ||
event: 'insertHorizontalRule', | ||
@@ -364,3 +403,3 @@ title: lang.hr.insert | ||
var tplLinkPopover = function () { | ||
var linkButton = tplIconButton('fa fa-edit', { | ||
var linkButton = tplIconButton(options.iconPrefix + 'edit', { | ||
title: lang.link.edit, | ||
@@ -370,3 +409,3 @@ event: 'showLinkDialog', | ||
}); | ||
var unlinkButton = tplIconButton('fa fa-unlink', { | ||
var unlinkButton = tplIconButton(options.iconPrefix + 'unlink', { | ||
title: lang.link.unlink, | ||
@@ -399,3 +438,3 @@ event: 'unlink' | ||
var leftButton = tplIconButton('fa fa-align-left', { | ||
var leftButton = tplIconButton(options.iconPrefix + 'align-left', { | ||
title: lang.image.floatLeft, | ||
@@ -405,3 +444,3 @@ event: 'floatMe', | ||
}); | ||
var rightButton = tplIconButton('fa fa-align-right', { | ||
var rightButton = tplIconButton(options.iconPrefix + 'align-right', { | ||
title: lang.image.floatRight, | ||
@@ -411,3 +450,3 @@ event: 'floatMe', | ||
}); | ||
var justifyButton = tplIconButton('fa fa-align-justify', { | ||
var justifyButton = tplIconButton(options.iconPrefix + 'align-justify', { | ||
title: lang.image.floatNone, | ||
@@ -418,3 +457,3 @@ event: 'floatMe', | ||
var roundedButton = tplIconButton('fa fa-square', { | ||
var roundedButton = tplIconButton(options.iconPrefix + 'square', { | ||
title: lang.image.shapeRounded, | ||
@@ -424,3 +463,3 @@ event: 'imageShape', | ||
}); | ||
var circleButton = tplIconButton('fa fa-circle-o', { | ||
var circleButton = tplIconButton(options.iconPrefix + 'circle-o', { | ||
title: lang.image.shapeCircle, | ||
@@ -430,3 +469,3 @@ event: 'imageShape', | ||
}); | ||
var thumbnailButton = tplIconButton('fa fa-picture-o', { | ||
var thumbnailButton = tplIconButton(options.iconPrefix + 'picture-o', { | ||
title: lang.image.shapeThumbnail, | ||
@@ -436,3 +475,3 @@ event: 'imageShape', | ||
}); | ||
var noneButton = tplIconButton('fa fa-times', { | ||
var noneButton = tplIconButton(options.iconPrefix + 'times', { | ||
title: lang.image.shapeNone, | ||
@@ -443,3 +482,3 @@ event: 'imageShape', | ||
var removeButton = tplIconButton('fa fa-trash-o', { | ||
var removeButton = tplIconButton(options.iconPrefix + 'trash-o', { | ||
title: lang.image.remove, | ||
@@ -458,20 +497,30 @@ event: 'removeMedia', | ||
var tplAirPopover = function () { | ||
var content = ''; | ||
var $content = $('<div />'); | ||
for (var idx = 0, len = options.airPopover.length; idx < len; idx ++) { | ||
var group = options.airPopover[idx]; | ||
content += '<div class="note-' + group[0] + ' btn-group">'; | ||
var $group = $('<div class="note-' + group[0] + ' btn-group">'); | ||
for (var i = 0, lenGroup = group[1].length; i < lenGroup; i++) { | ||
content += tplButtonInfo[group[1][i]](lang, options); | ||
var $button = $(tplButtonInfo[group[1][i]](lang, options)); | ||
$button.attr('data-name', group[1][i]); | ||
$group.append($button); | ||
} | ||
content += '</div>'; | ||
$content.append($group); | ||
} | ||
return tplPopover('note-air-popover', content); | ||
return tplPopover('note-air-popover', $content.children()); | ||
}; | ||
return '<div class="note-popover">' + | ||
tplLinkPopover() + | ||
tplImagePopover() + | ||
(options.airMode ? tplAirPopover() : '') + | ||
'</div>'; | ||
var $notePopover = $('<div class="note-popover" />'); | ||
$notePopover.append(tplLinkPopover()); | ||
$notePopover.append(tplImagePopover()); | ||
if (options.airMode) { | ||
$notePopover.append(tplAirPopover()); | ||
} | ||
return $notePopover; | ||
}; | ||
@@ -821,3 +870,3 @@ | ||
//04. create Toolbar | ||
var toolbarHTML = ''; | ||
var $toolbar = $('<div class="note-toolbar btn-toolbar" />'); | ||
for (var idx = 0, len = options.toolbar.length; idx < len; idx ++) { | ||
@@ -827,3 +876,3 @@ var groupName = options.toolbar[idx][0]; | ||
toolbarHTML += '<div class="note-' + groupName + ' btn-group">'; | ||
var $group = $('<div class="note-' + groupName + ' btn-group" />'); | ||
for (var i = 0, btnLength = groupButtons.length; i < btnLength; i++) { | ||
@@ -833,10 +882,11 @@ var buttonInfo = tplButtonInfo[groupButtons[i]]; | ||
if (!$.isFunction(buttonInfo)) { continue; } | ||
toolbarHTML += buttonInfo(langInfo, options); | ||
var $button = $(buttonInfo(langInfo, options)); | ||
$button.attr('data-name', groupButtons[i]); // set button's alias, becuase to get button element from $toolbar | ||
$group.append($button); | ||
} | ||
toolbarHTML += '</div>'; | ||
$toolbar.append($group); | ||
} | ||
toolbarHTML = '<div class="note-toolbar btn-toolbar">' + toolbarHTML + '</div>'; | ||
var $toolbar = $(toolbarHTML).prependTo($editor); | ||
$toolbar.prependTo($editor); | ||
var keyMap = options.keyMap[agent.isMac ? 'mac' : 'pc']; | ||
@@ -868,2 +918,6 @@ createPalette($toolbar, options); | ||
this.hasNoteEditor = function ($holder) { | ||
return this.noteEditorFromHolder($holder).length > 0; | ||
}; | ||
this.noteEditorFromHolder = function ($holder) { | ||
@@ -886,6 +940,2 @@ if ($holder.hasClass('note-air-editor')) { | ||
this.createLayout = function ($holder, options) { | ||
if (this.noteEditorFromHolder($holder).length) { | ||
return; | ||
} | ||
if (options.airMode) { | ||
@@ -902,16 +952,14 @@ this.createLayoutByAirMode($holder, options); | ||
* @param {jQuery} $holder - placeholder | ||
* @returns {Object} | ||
* @return {Object} | ||
*/ | ||
this.layoutInfoFromHolder = function ($holder) { | ||
var $editor = this.noteEditorFromHolder($holder); | ||
if (!$editor.length) { return; } | ||
if (!$editor.length) { | ||
return; | ||
} | ||
var layoutInfo = dom.buildLayoutInfo($editor); | ||
// cache all properties. | ||
for (var key in layoutInfo) { | ||
if (layoutInfo.hasOwnProperty(key)) { | ||
layoutInfo[key] = layoutInfo[key].call(); | ||
} | ||
} | ||
return layoutInfo; | ||
// connect $holder to $editor | ||
$editor.data('holder', $holder); | ||
return dom.buildLayoutInfo($editor); | ||
}; | ||
@@ -932,9 +980,9 @@ | ||
layoutInfo.popover.remove(); | ||
layoutInfo.handle.remove(); | ||
layoutInfo.dialog.remove(); | ||
layoutInfo.popover().remove(); | ||
layoutInfo.handle().remove(); | ||
layoutInfo.dialog().remove(); | ||
} else { | ||
$holder.html(layoutInfo.editable.html()); | ||
$holder.html(layoutInfo.editable().html()); | ||
layoutInfo.editor.remove(); | ||
layoutInfo.editor().remove(); | ||
$holder.show(); | ||
@@ -941,0 +989,0 @@ } |
define([ | ||
'summernote/core/agent', 'summernote/core/dom', | ||
'summernote/core/agent', | ||
'summernote/core/list', | ||
'summernote/core/dom', | ||
'summernote/core/range', | ||
'summernote/settings', | ||
'summernote/EventHandler', 'summernote/Renderer' | ||
], function (agent, dom, range, settings, EventHandler, Renderer) { | ||
'summernote/defaults', | ||
'summernote/EventHandler', | ||
'summernote/Renderer' | ||
], function (agent, list, dom, range, | ||
defaults, EventHandler, Renderer) { | ||
@@ -14,3 +18,3 @@ // jQuery namespace for summernote | ||
* | ||
* @mixin settings | ||
* @mixin defaults | ||
* @singleton | ||
@@ -21,4 +25,7 @@ * | ||
// extends default `settings` | ||
$.extend($.summernote, settings); | ||
// extends default settings | ||
// - $.summernote.version | ||
// - $.summernote.options | ||
// - $.summernote.lang | ||
$.extend($.summernote, defaults); | ||
@@ -63,3 +70,5 @@ var renderer = new Renderer(); | ||
*/ | ||
pluginEvents: {} | ||
pluginEvents: {}, | ||
plugins : [] | ||
}); | ||
@@ -125,2 +134,6 @@ | ||
$.summernote.addPlugin = function (plugin) { | ||
// save plugin list | ||
$.summernote.plugins.push(plugin); | ||
if (plugin.buttons) { | ||
@@ -171,7 +184,15 @@ $.each(plugin.buttons, function (name, button) { | ||
* @member $.fn | ||
* @param {Object} options reference to $.summernote.options | ||
* @returns {this} | ||
* @param {Object|String} options reference to $.summernote.options | ||
* @return {this} | ||
*/ | ||
summernote: function (options) { | ||
// extend default options | ||
summernote: function () { | ||
// check first argument's type | ||
// - {String}: External API call {{module}}.{{method}} | ||
// - {Object}: init options | ||
var type = $.type(list.head(arguments)); | ||
var isExternalAPICalled = type === 'string'; | ||
var isInitOptions = type === 'object'; | ||
// extend default options with custom user options | ||
var options = isInitOptions ? list.head(arguments) : {}; | ||
options = $.extend({}, $.summernote.options, options); | ||
@@ -186,36 +207,39 @@ | ||
// createLayout with options | ||
renderer.createLayout($holder, options); | ||
// if layout isn't created yet, createLayout and attach events | ||
if (!renderer.hasNoteEditor($holder)) { | ||
renderer.createLayout($holder, options); | ||
var info = renderer.layoutInfoFromHolder($holder); | ||
eventHandler.attach(info, options); | ||
var layoutInfo = renderer.layoutInfoFromHolder($holder); | ||
// Textarea: auto filling the code before form submit. | ||
if (dom.isTextarea($holder[0])) { | ||
$holder.closest('form').submit(function () { | ||
var contents = $holder.code(); | ||
$holder.val(contents); | ||
eventHandler.attach(layoutInfo, options); | ||
eventHandler.attachCustomEvent(layoutInfo, options); | ||
// callback on submit | ||
if (options.onsubmit) { | ||
options.onsubmit(contents); | ||
} | ||
}); | ||
} | ||
}); | ||
// focus on first editable element | ||
if (this.first().length && options.focus) { | ||
var info = renderer.layoutInfoFromHolder(this.first()); | ||
info.editable.focus(); | ||
} | ||
// callback on init | ||
if (this.length && options.oninit) { | ||
if (!isExternalAPICalled && this.length && options.oninit) { | ||
options.oninit(); | ||
} | ||
var $first = this.first(); | ||
if ($first.length) { | ||
var layoutInfo = renderer.layoutInfoFromHolder($first); | ||
// external API | ||
if (isExternalAPICalled) { | ||
var moduleAndMethod = list.head(list.from(arguments)); | ||
var args = list.tail(list.from(arguments)); | ||
// TODO now external API only works for editor | ||
var params = [moduleAndMethod, layoutInfo.editable()].concat(args); | ||
return eventHandler.invoke.apply(eventHandler, params); | ||
} else if (options.focus) { | ||
// focus on first editable element for initialize editor | ||
layoutInfo.editable().focus(); | ||
} | ||
} | ||
return this; | ||
}, | ||
// | ||
@@ -238,19 +262,23 @@ /** | ||
* @member $.fn | ||
* @param {String} [sHTML] - HTML contents(optional, set) | ||
* @returns {this|String} - context(set) or HTML contents of note(get). | ||
* @param {String} [html] - HTML contents(optional, set) | ||
* @return {this|String} - context(set) or HTML contents of note(get). | ||
*/ | ||
code: function (sHTML) { | ||
code: function (html) { | ||
// get the HTML contents of note | ||
if (sHTML === undefined) { | ||
if (html === undefined) { | ||
var $holder = this.first(); | ||
if (!$holder.length) { return; } | ||
var info = renderer.layoutInfoFromHolder($holder); | ||
if (!!(info && info.editable)) { | ||
var isCodeview = info.editor.hasClass('codeview'); | ||
if (isCodeview && agent.hasCodeMirror) { | ||
info.codable.data('cmEditor').save(); | ||
} | ||
return isCodeview ? info.codable.val() : info.editable.html(); | ||
if (!$holder.length) { | ||
return; | ||
} | ||
return dom.isTextarea($holder[0]) ? $holder.val() : $holder.html(); | ||
var layoutInfo = renderer.layoutInfoFromHolder($holder); | ||
var $editable = layoutInfo && layoutInfo.editable(); | ||
if ($editable && $editable.length) { | ||
var isCodeview = eventHandler.invoke('codeview.isActivated', layoutInfo); | ||
eventHandler.invoke('codeview.sync', layoutInfo); | ||
return isCodeview ? layoutInfo.codable().val() : | ||
layoutInfo.editable().html(); | ||
} | ||
return dom.value($holder); | ||
} | ||
@@ -260,4 +288,7 @@ | ||
this.each(function (i, holder) { | ||
var info = renderer.layoutInfoFromHolder($(holder)); | ||
if (info && info.editable) { info.editable.html(sHTML); } | ||
var layoutInfo = renderer.layoutInfoFromHolder($(holder)); | ||
var $editable = layoutInfo && layoutInfo.editable(); | ||
if ($editable) { | ||
$editable.html(html); | ||
} | ||
}); | ||
@@ -274,3 +305,3 @@ | ||
* @member $.fn | ||
* @returns {this} | ||
* @return {this} | ||
*/ | ||
@@ -281,7 +312,9 @@ destroy: function () { | ||
if (!renderer.hasNoteEditor($holder)) { | ||
return; | ||
} | ||
var info = renderer.layoutInfoFromHolder($holder); | ||
if (!info || !info.editable) { return; } | ||
var options = info.editor().data('options'); | ||
var options = info.editor.data('options'); | ||
eventHandler.detach(info, options); | ||
@@ -288,0 +321,0 @@ renderer.removeLayout($holder, info, options); |
@@ -243,3 +243,20 @@ /** | ||
}); | ||
test('dom.splitPoint', function () { | ||
var $editable, $para, $br; | ||
$editable = $('<div class="note-editable"><p><br></p></div>'); | ||
$para = $editable.clone().find('p'); | ||
$br = $para.find('br'); | ||
deepEqual(dom.splitPoint({ | ||
node: $para[0], | ||
offset: 0 | ||
}, true), { | ||
rightNode: $br[0], | ||
container: $para[0] | ||
}, 'splitPoint empty paragraph with inline should returns rightNode:<br> container:<p>'); | ||
}); | ||
}; | ||
}); |
@@ -124,2 +124,53 @@ /** | ||
test('rng.pasteHTML', function () { | ||
var $cont, $p, $b, markup; | ||
// split text with inline nodes | ||
$cont = $('<div class="note-editable"><p>text</p></div>'); | ||
$p = $cont.find('p'); | ||
markup = '<span>span</span><i>italic</i>'; | ||
range.create($p[0].firstChild, 2).pasteHTML(markup); | ||
equalsToUpperCase($cont.html(), '<p>te<span>span</span><i>italic</i>xt</p>', 'rng.pasteHTML with inlines should not split text.'); | ||
// split inline node with inline nodes | ||
$cont = $('<div class="note-editable"><p><b>bold</b></p></div>'); | ||
$p = $cont.find('p'); | ||
$b = $cont.find('b'); | ||
markup = '<span>span</span><i>italic</i>'; | ||
range.create($b[0].firstChild, 2).pasteHTML(markup); | ||
equalsToUpperCase( | ||
$cont.html(), | ||
'<p><b>bo</b><span>span</span><i>italic</i><b>ld</b></p>', | ||
'rng.pasteHTML with inlines should not split text.' | ||
); | ||
// split inline node with inline and block nodes | ||
$cont = $('<div class="note-editable"><p><b>bold</b></p></div>'); | ||
$p = $cont.find('p'); | ||
$b = $cont.find('b'); | ||
markup = '<span>span</span><p><i>italic</i></p>'; | ||
range.create($b[0].firstChild, 2).pasteHTML(markup); | ||
equalsToUpperCase( | ||
$cont.html(), | ||
'<p><b>bo</b><span>span</span></p><p><i>italic</i></p><p><b>ld</b></p>', | ||
'rng.pasteHTML with inlines should not split text.' | ||
); | ||
// split inline node with inline and block | ||
$cont = $('<div class="note-editable"><p><b>bold</b></p></div>'); | ||
$p = $cont.find('p'); | ||
$b = $cont.find('b'); | ||
markup = '<span>span</span><p><i>italic</i></p>'; | ||
range.create($b[0].firstChild, 2).pasteHTML(markup); | ||
equalsToUpperCase( | ||
$cont.html(), | ||
'<p><b>bo</b><span>span</span></p><p><i>italic</i></p><p><b>ld</b></p>', | ||
'rng.pasteHTML with inlines should not split text.' | ||
); | ||
}); | ||
test('rng.deleteContents', function () { | ||
@@ -182,3 +233,52 @@ var $cont, $p, $b, $u; | ||
}); | ||
test('rng.getWordRange', function () { | ||
var $cont, rng; | ||
$cont = $('<div class="note-editable">super simple wysiwyg editor</div>'); | ||
// no word before cursor | ||
rng = range.create( | ||
$cont[0].firstChild, 0 | ||
).getWordRange(); | ||
deepEqual([ | ||
rng.sc, rng.so, rng.ec, rng.eo | ||
], [ | ||
$cont[0].firstChild, 0, $cont[0].firstChild, 0 | ||
], 'rng.getWordRange with no word before cursor should return itself'); | ||
// find word before cursor | ||
rng = range.create( | ||
$cont[0].firstChild, 5 | ||
).getWordRange(); | ||
deepEqual([ | ||
rng.sc, rng.so, rng.ec, rng.eo | ||
], [ | ||
$cont[0].firstChild, 0, $cont[0].firstChild, 5 | ||
], 'rng.getWordRange with word before cursor should return expanded range'); | ||
rng = range.create( | ||
$cont[0].firstChild, 3 | ||
).getWordRange(); | ||
deepEqual([ | ||
rng.sc, rng.so, rng.ec, rng.eo | ||
], [ | ||
$cont[0].firstChild, 0, $cont[0].firstChild, 3 | ||
], 'rng.getWordRange with half word before cursor should expanded range'); | ||
rng = range.create( | ||
$cont[0].firstChild, 12 | ||
).getWordRange(); | ||
deepEqual([ | ||
rng.sc, rng.so, rng.ec, rng.eo | ||
], [ | ||
$cont[0].firstChild, 6, $cont[0].firstChild, 12 | ||
], 'rng.getWordRange with half word before cursor should expanded range'); | ||
}); | ||
}; | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
1403014
122
34379
12