diff --git a/build/jquery.notebook.min.css b/build/jquery.notebook.min.css
index a0fb2d4..071fa61 100644
--- a/build/jquery.notebook.min.css
+++ b/build/jquery.notebook.min.css
@@ -1 +1 @@
-.jquery-notebook.editor{position:relative;outline:0;min-height:50px}.jquery-notebook.editor p{z-index:2;position:relative;min-height:1px}.jquery-notebook.editor p.placeholder{position:absolute;z-index:1;opacity:.5;pointer-events:none}.jquery-notebook p:first-child,.jquery-notebook p.placeholder+p{margin-top:0}.jquery-notebook.bubble{position:absolute;z-index:3;opacity:1;height:43px;left:0;top:0;opacity:0;border-radius:5px;-webkit-box-shadow:2px 2px 2px -1px rgba(0,0,0,.7),inset 0 0 1px rgba(255,255,255,.07),inset 0 0 2px rgba(255,255,255,.15000000000000002);box-shadow:2px 2px 2px -1px rgba(0,0,0,.7),inset 0 0 1px rgba(255,255,255,.07),inset 0 0 2px rgba(255,255,255,.15000000000000002);background:#323232;-webkit-transition:.5s ease-in-out;transition:.5s ease-in-out}.jquery-notebook.bubble.active{opacity:1}.jquery-notebook.bubble:after{content:'';display:block;position:absolute;left:50%;bottom:-3px;margin-left:-4px;width:8px;height:8px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);background:#323232;-webkit-box-shadow:0 0 2px #262625;box-shadow:0 0 2px #262625}.jquery-notebook.bubble ul{padding:0;margin:0;list-style:none}.jquery-notebook.bubble ul li{display:inline}.jquery-notebook.bubble button{outline:0;border:0;background:transparent;width:41px;height:42px;font-family:FontAwesome;color:#fff;font-size:14pt;cursor:pointer;margin-top:0}.jquery-notebook.bubble button.active{color:#1ed228}.jquery-notebook.bubble button.bold:after{content:"\f032"}.jquery-notebook.bubble button.italic:after{content:"\f033"}.jquery-notebook.bubble button.underline:after{content:"\f0cd"}.jquery-notebook.bubble button.anchor:after{content:"\f0c1"}.jquery-notebook.bubble button.paste:after{content:"\f0ea"}.jquery-notebook.bubble button.h1:after{font-family:inherit;content:"h1"}.jquery-notebook.bubble button.h2:after{font-family:inherit;content:"h2"}.jquery-notebook.bubble button.ul:after{font-family:inherit;content:"\f0ca"}.jquery-notebook.bubble button.ol:after{font-family:inherit;content:"\f0cb"}.jquery-notebook .link-area{display:none}.jquery-notebook .link-area button{float:left}.jquery-notebook .link-area button:after{content:"\f00d"}.jquery-notebook input[type=text]{width:220px;height:28px;margin:6px 0 0 10px;background:0;border:0;outline:0;color:#fff;font-size:14px;float:left}
\ No newline at end of file
+.jquery-notebook.editor{position:relative;outline:0;min-height:50px}.jquery-notebook.editor p{z-index:2;position:relative;min-height:1px}.jquery-notebook.editor p.placeholder{position:absolute;z-index:1;opacity:.5;pointer-events:none}.jquery-notebook p:first-child,.jquery-notebook p.placeholder+p{margin-top:0}.jquery-notebook.bubble{position:absolute;z-index:3;opacity:1;height:43px;left:0;top:0;opacity:0;border-radius:5px;border:1px solid #1C1C1B;-webkit-box-shadow:0 2px 3px rgba(0,0,0,.2),inset 0 0 2px rgba(255,255,255,.2);box-shadow:0 2px 3px rgba(0,0,0,.2),inset 0 0 2px rgba(255,255,255,.2);background:#373735;background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,rgba(55,55,53,1)),color-stop(100%,rgba(40,40,39,1)));background:-webkit-linear-gradient(top,rgba(55,55,53,1) 0,rgba(40,40,39,1) 100%);background:-webkit-gradient(linear,left top,left bottom,from(rgba(55,55,53,1)),to(rgba(40,40,39,1)));background:-webkit-linear-gradient(top,rgba(55,55,53,1) 0,rgba(40,40,39,1) 100%);background:linear-gradient(to bottom,rgba(55,55,53,1) 0,rgba(40,40,39,1) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#373735', endColorstr='#282827', GradientType=0);-webkit-transition:.15s ease-in-out;transition:.15s ease-in-out;-webkit-transition:.15s ease-in-out}.jquery-notebook.bubble.active{opacity:1}.jquery-notebook.bubble.jump{-webkit-transition:opacity .15s;transition:opacity .15s;-webkit-transition:opacity .15s}.jquery-notebook.bubble:after{content:'';display:block;position:absolute;left:50%;bottom:-6px;margin-left:-8px;width:16px;height:16px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);background:#282827;-webkit-box-shadow:2px 2px 1px rgba(0,0,0,.1);box-shadow:2px 2px 1px rgba(0,0,0,.1)}.jquery-notebook.bubble ul{padding:0;margin:0;list-style:none}.jquery-notebook.bubble ul li{display:inline}.jquery-notebook.bubble button{outline:0;border:0;background:transparent;width:41px;height:42px;font-family:FontAwesome;color:#fff;font-size:14pt;cursor:pointer}.jquery-notebook.bubble button.active{color:#60D778}.jquery-notebook.bubble button.bold:after{content:"\f032"}.jquery-notebook.bubble button.italic:after{content:"\f033"}.jquery-notebook.bubble button.underline:after{content:"\f0cd"}.jquery-notebook.bubble button.anchor:after{content:"\f0c1"}.jquery-notebook.bubble button.paste:after{content:"\f0ea"}.jquery-notebook.bubble button.h1:after{font-family:inherit;content:"h1"}.jquery-notebook.bubble button.h2:after{font-family:inherit;content:"h2"}.jquery-notebook.bubble button.ul:after{font-family:inherit;content:"\f0ca"}.jquery-notebook.bubble button.ol:after{font-family:inherit;content:"\f0cb"}.jquery-notebook .link-area{display:none}.jquery-notebook .link-area button{float:left}.jquery-notebook .link-area button:after{content:"\f00d"}.jquery-notebook input[type=text]{width:220px;height:28px;margin:6px 0 0 10px;background:0;border:0;outline:0;color:#fff;font-size:14px;float:left}
\ No newline at end of file
diff --git a/build/jquery.notebook.min.js b/build/jquery.notebook.min.js
index 62583b2..eb1906a 100644
--- a/build/jquery.notebook.min.js
+++ b/build/jquery.notebook.min.js
@@ -1,403 +1 @@
-! function(e, t, n) {
- var o, i = function() {
- var e = function(e) {
- return e && "none" != e ? e.match(/(-?[0-9\.]+)/g) : [1, 0, 0, 1, 0, 0]
- }, t = function(e) {
- return e.css("-webkit-transform") || e.css("transform") || e.css("-moz-transform") || e.css("-o-transform") || e.css("-ms-transform")
- }, n = function(n) {
- var o = t(n);
- return e(o)
- }, o = function(e, t) {
- e.css("-webkit-transform", t), e.css("-moz-transform", t), e.css("-o-transform", t), e.css("-ms-transform", t), e.css("transform", t)
- }, i = function(e) {
- return "matrix(" + e[0] + ", " + e[1] + ", " + e[2] + ", " + e[3] + ", " + e[4] + ", " + e[5] + ")"
- }, a = function(e) {
- var t = n(e);
- return {
- x: parseInt(t[4]),
- y: parseInt(t[5])
- }
- }, l = function(e, t) {
- var a = n(e);
- a[0] = a[3] = t;
- var l = i(a);
- o(e, l)
- }, c = function(e, t, a) {
- var l = n(e);
- l[4] = t, l[5] = a;
- var c = i(l);
- o(e, c)
- }, r = function(e, t) {
- var a = n(e),
- l = t * (Math.PI / 180),
- c = -1 * l;
- a[1] = l, a[2] = c;
- var r = i(a);
- o(e, r)
- };
- return {
- scale: l,
- translate: c,
- rotate: r,
- getTranslate: a
- }
- }(),
- a = "MacIntel" == n.navigator.platform,
- l = 0,
- c = 0,
- r = {
- command: !1,
- shift: !1,
- isSelecting: !1
- }, s = {
- 66: "bold",
- 73: "italic",
- 85: "underline",
- 112: "h1",
- 113: "h2",
- 122: "undo"
- }, u = {
- keyboard: {
- isCommand: function(e, t, n) {
- a && e.metaKey || !a && e.ctrlKey ? t() : n()
- },
- isShift: function(e, t, n) {
- e.shiftKey ? t() : n()
- },
- isModifier: function(e, t) {
- var n = e.which,
- o = s[n];
- o && t.call(this, o)
- },
- isEnter: function(e, t) {
- 13 === e.which && t()
- },
- isArrow: function(e, t) {
- (e.which >= 37 || e.which <= 40) && t()
- }
- },
- html: {
- addTag: function(n, o, i, a) {
- var l = e(t.createElement(o));
- return l.attr("contenteditable", Boolean(a)), l.append(" "), n.append(l), i && (r.focusedElement = n.children().last(), u.cursor.set(n, 0, r.focusedElement)), l
- }
- },
- cursor: {
- set: function(e, o, i) {
- var a;
- if (t.createRange) {
- a = t.createRange();
- var l = n.getSelection(),
- c = e.children().last(),
- r = c.html().length - 1,
- s = i ? i[0] : c[0],
- u = "undefined" != typeof o ? o : r;
- a.setStart(s, u), a.collapse(!0), l.removeAllRanges(), l.addRange(a)
- } else a = t.body.createTextRange(), a.moveToElementText(i), a.collapse(!1), a.select()
- }
- },
- selection: {
- save: function() {
- if (n.getSelection) {
- var e = n.getSelection();
- if (e.rangeCount > 0) return e.getRangeAt(0)
- } else if (t.selection && t.selection.createRange) return t.selection.createRange();
- return null
- },
- restore: function(e) {
- if (e)
- if (n.getSelection) {
- var o = n.getSelection();
- o.removeAllRanges(), o.addRange(e)
- } else t.selection && e.select && e.select()
- },
- getText: function() {
- var e = "";
- return n.getSelection ? e = n.getSelection().toString() : t.getSelection ? e = t.getSelection().toString() : t.selection && (e = t.selection.createRange().text), e
- },
- clear: function() {
- window.getSelection ? window.getSelection().empty ? window.getSelection().empty() : window.getSelection().removeAllRanges && window.getSelection().removeAllRanges() : document.selection && document.selection.empty()
- },
- getContainer: function(e) {
- return n.getSelection && e && e.commonAncestorContainer ? e.commonAncestorContainer : t.selection && e && e.parentElement ? e.parentElement() : null
- }
- },
- validation: {
- isUrl: function(e) {
- return /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/.test(e)
- }
- }
- }, d = {
- updatePos: function(t, o) {
- var a = n.getSelection(),
- l = a.getRangeAt(0),
- c = l.getBoundingClientRect(),
- r = o.width(),
- s = o.height(),
- u = (t.offset().left, {
- x: c.left + c.width / 2 - r / 2,
- y: c.top - s - 8 + e(document).scrollTop()
- });
- i.translate(o, u.x, u.y)
- },
- updateState: function(e, t) {
- t.find("button").removeClass("active");
- var o = n.getSelection(),
- i = [];
- d.checkForFormatting(o.focusNode, i);
- for (var a = {
- b: "bold",
- i: "italic",
- h1: "h1",
- h2: "h2",
- a: "anchor",
- ul: "ul",
- ol: "ol"
- }, l = 0; l < i.length; l++) {
- var c = i[l];
- t.find("button." + a[c]).addClass("active")
- }
- },
- checkForFormatting: function(e, t) {
- var n = ["b", "i", "u", "h1", "h2", "ol", "ul", "li", "a"];
- ("#text" === e.nodeName || -1 != n.indexOf(e.nodeName.toLowerCase())) && ("#text" != e.nodeName && t.push(e.nodeName.toLowerCase()), d.checkForFormatting(e.parentNode, t))
- },
- buildMenu: function(t, n) {
- var i = u.html.addTag(n, "ul", !1, !1);
- for (var a in o.modifiers) {
- var l = u.html.addTag(i, "li", !1, !1),
- c = u.html.addTag(l, "button", !1, !1);
- c.attr("editor-command", o.modifiers[a]), c.addClass(o.modifiers[a])
- }
- n.find("button").click(function(n) {
- n.preventDefault();
- var o = e(this).attr("editor-command");
- m.commands[o].call(t, n)
- });
- var r = u.html.addTag(n, "div", !1, !1);
- r.addClass("link-area");
- var s = u.html.addTag(r, "input", !1, !1);
- s.attr({
- type: "text"
- });
- var d = u.html.addTag(r, "button", !1, !1);
- d.click(function(t) {
- t.preventDefault();
- e(this).closest(".editor");
- e(this).closest(".link-area").hide(), e(this).closest(".bubble").find("ul").show()
- })
- },
- show: function() {
- var t = e(this).parent().find(".bubble");
- t.length || (t = u.html.addTag(e(this).parent(), "div", !1, !1), t.addClass("jquery-notebook bubble"), d.buildMenu(this, t)), t.show(), d.updateState(this, t), t.addClass("active"), d.updatePos(e(this), t)
- },
- update: function() {
- var t = e(this).parent().find(".bubble");
- d.updateState(this, t)
- },
- clear: function() {
- var t = e(this).parent().find(".bubble");
- t.hasClass("active") && (t.removeClass("active"), d.hideLinkInput.call(this), d.showButtons.call(this), setTimeout(function() {
- t.hasClass("active") || t.hide()
- }, 500))
- },
- hideButtons: function() {
- e(this).parent().find(".bubble").find("ul").hide()
- },
- showButtons: function() {
- e(this).parent().find(".bubble").find("ul").show()
- },
- showLinkInput: function(t) {
- d.hideButtons.call(this);
- var n = this,
- o = e(this).parent().find(".bubble").find("input[type=text]"),
- i = o.closest(".jquery-notebook").find("button.anchor").hasClass("active");
- o.unbind("keydown"), o.keydown(function(o) {
- var a = e(this);
- u.keyboard.isEnter(o, function() {
- o.preventDefault();
- var e = a.val();
- u.validation.isUrl(e) ? (o.url = e, m.commands.createLink(o, t), d.clear.call(n)) : "" === e && i && (m.commands.removeLink(o, t), d.clear.call(n))
- })
- }), o.bind("paste", function() {
- var t = e(this);
- setTimeout(function() {
- var e = t.val();
- /http:\/\/https?:\/\//.test(e) && (e = e.substring(7), t.val(e))
- }, 1)
- });
- var a = "http://";
- if (i) {
- var l = e(u.selection.getContainer(t)).closest("a");
- a = l.prop("href") || a
- }
- e(this).parent().find(".link-area").show(), o.val(a).focus()
- },
- hideLinkInput: function() {
- e(this).parent().find(".bubble").find(".link-area").hide()
- }
- }, f = {
- bindEvents: function(t) {
- t.keydown(h.keydown), t.keyup(h.keyup), t.focus(h.focus), t.bind("paste", m.paste), t.mousedown(h.mouseClick), t.mouseup(h.mouseUp), t.mousemove(h.mouseMove), t.blur(h.blur), e("body").mouseup(function(e) {
- e.target == e.currentTarget && r.isSelecting && h.mouseUp.call(t, e)
- })
- },
- setPlaceholder: function(t) {
- if (/^\s*$/.test(e(this).text())) {
- e(this).empty();
- var n = u.html.addTag(e(this), "p").addClass("placeholder");
- n.append(e(this).attr("editor-placeholder")), u.html.addTag(e(this), "p", "undefined" != typeof t.focus ? t.focus : !1, !0)
- } else e(this).find(".placeholder").remove()
- },
- removePlaceholder: function() {
- e(this).find(".placeholder").remove()
- },
- preserveElementFocus: function() {
- var e = n.getSelection() ? n.getSelection().anchorNode : t.activeElement;
- if (e) {
- var o = e.parentNode,
- i = o !== r.focusedElement,
- a = this.children,
- l = 0;
- o === this && (o = e);
- for (var c = 0; c < a.length; c++)
- if (o === a[c]) {
- l = c;
- break
- }
- i && (r.focusedElement = o, r.focusedElementIndex = l)
- }
- },
- prepare: function(e, t) {
- if (o = t, e.attr("editor-mode", o.mode), e.attr("editor-placeholder", o.placeholder), e.attr("contenteditable", !0), e.css("position", "relative"), e.addClass("jquery-notebook editor"), f.setPlaceholder.call(e, {}), f.preserveElementFocus.call(e), o.autoFocus === !0) {
- var n = e.find("p:not(.placeholder)");
- u.cursor.set(e, 0, n)
- }
- }
- }, h = {
- keydown: function(e) {
- var t = this;
- r.command && 65 === e.which && setTimeout(function() {
- d.show.call(t)
- }, 50), u.keyboard.isCommand(e, function() {
- r.command = !0
- }, function() {
- r.command = !1
- }), u.keyboard.isShift(e, function() {
- r.shift = !0
- }, function() {
- r.shift = !1
- }), u.keyboard.isModifier.call(this, e, function(t) {
- r.command && m.commands[t].call(this, e)
- }), r.shift ? u.keyboard.isArrow.call(this, e, function() {
- setTimeout(function() {
- var e = u.selection.getText();
- "" !== e ? d.show.call(t) : d.clear.call(t)
- }, 100)
- }) : u.keyboard.isArrow.call(this, e, function() {
- d.clear.call(t)
- }), 13 === e.which && m.enterKey.call(this, e), 27 === e.which && d.clear.call(this), 86 === e.which && m.paste.call(this, e)
- },
- keyup: function(t) {
- u.keyboard.isCommand(t, function() {
- r.command = !1
- }, function() {
- r.command = !0
- }), f.preserveElementFocus.call(this), f.removePlaceholder.call(this), /^\s*$/.test(e(this).text()) && (e(this).empty(), u.html.addTag(e(this), "p", !0, !0))
- },
- focus: function() {
- r.command = !1, r.shift = !1
- },
- mouseClick: function(t) {
- var n = this;
- if (r.isSelecting = !0, 2 === t.button) return setTimeout(function() {
- d.show.call(n)
- }, 50), void t.preventDefault();
- if (e(this).find(".bubble:visible").length) {
- var o = e(this).find(".bubble:visible"),
- i = o.offset().left,
- a = o.offset().top,
- s = o.width(),
- u = o.height();
- if (l > i && i + s > l && c > a && a + u > c) return
- }
- },
- mouseUp: function(e) {
- e.preventDefault();
- var t = this;
- r.isSelecting = !1, setTimeout(function() {
- var e = u.selection.save();
- e.collapsed ? d.clear.call(t) : d.show.call(t)
- }, 50)
- },
- mouseMove: function(e) {
- l = e.pageX, c = e.pageY
- },
- blur: function() {
- f.setPlaceholder.call(this, {
- focus: !1
- })
- }
- }, m = {
- commands: {
- bold: function(e) {
- e.preventDefault(), t.execCommand("bold", !1), d.update.call(this)
- },
- italic: function(e) {
- e.preventDefault(), t.execCommand("italic", !1), d.update.call(this)
- },
- underline: function(e) {
- e.preventDefault(), t.execCommand("underline", !1), d.update.call(this)
- },
- anchor: function(e) {
- e.preventDefault();
- var t = u.selection.save();
- d.showLinkInput.call(this, t)
- },
- createLink: function(e, n) {
- u.selection.restore(n), t.execCommand("createLink", !1, e.url), d.update.call(this)
- },
- removeLink: function(t, n) {
- var o = e(u.selection.getContainer(n)).closest("a");
- o.contents().first().unwrap()
- },
- h1: function(n) {
- n.preventDefault(), e(window.getSelection().anchorNode.parentNode).is("h1") ? t.execCommand("formatBlock", !1, "
") : t.execCommand("formatBlock", !1, "
"), d.update.call(this)
- },
- h2: function(n) {
- n.preventDefault(), e(window.getSelection().anchorNode.parentNode).is("h2") ? t.execCommand("formatBlock", !1, "
") : t.execCommand("formatBlock", !1, "
"), d.update.call(this)
- },
- ul: function(e) {
- e.preventDefault(), t.execCommand("insertUnorderedList", !1), d.update.call(this)
- },
- ol: function(e) {
- e.preventDefault(), t.execCommand("insertOrderedList", !1), d.update.call(this)
- },
- undo: function(e) {
- e.preventDefault(), t.execCommand("undo", !1)
- }
- },
- enterKey: function(t) {
- return "inline" === e(this).attr("editor-mode") ? void t.preventDefault() : void 0
- },
- paste: function() {
- var t = e(this);
- setTimeout(function() {
- t.find("*").each(function() {
- var t = e(this);
- e.each(this.attributes, function() {
- "class" === this.name && t.hasClass("placeholder") || t.removeAttr(this.name)
- })
- })
- }, 100)
- }
- };
- e.fn.notebook = function(t) {
- return t = e.extend({}, e.fn.notebook.defaults, t), f.prepare(this, t), f.bindEvents(this), this
- }, e.fn.notebook.defaults = {
- autoFocus: !1,
- placeholder: "Your text here...",
- mode: "multiline",
- modifiers: ["bold", "italic", "underline", "h1", "h2", "ol", "ul", "anchor"]
- }
-}(jQuery, document, window);
\ No newline at end of file
+!function(e,t,n){var o=function(){var e=function(e){return e&&"none"!=e?e.match(/(-?[0-9\.]+)/g):[1,0,0,1,0,0]},t=function(e){return e.css("-webkit-transform")||e.css("transform")||e.css("-moz-transform")||e.css("-o-transform")||e.css("-ms-transform")},n=function(n){var o=t(n);return e(o)},o=function(e,t){e.css("-webkit-transform",t),e.css("-moz-transform",t),e.css("-o-transform",t),e.css("-ms-transform",t),e.css("transform",t)},i=function(e){return"matrix("+e[0]+", "+e[1]+", "+e[2]+", "+e[3]+", "+e[4]+", "+e[5]+")"},a=function(e){var t=n(e);return{x:parseInt(t[4]),y:parseInt(t[5])}},l=function(e,t){var a=n(e);a[0]=a[3]=t;var l=i(a);o(e,l)},r=function(e,t,a){var l=n(e);l[4]=t,l[5]=a;var r=i(l);o(e,r)},s=function(e,t){var a=n(e),l=t*(Math.PI/180),r=-1*l;a[1]=l,a[2]=r;var s=i(a);o(e,s)};return{scale:l,translate:r,rotate:s,getTranslate:a}}(),i=function(o,i){var r=this,s=0,c=0,u={command:!1,shift:!1,isSelecting:!1};e.extend(r,{init:function(){r.element=e(o),r.options=i,r.utils=new a,r.bubble=new l(r),r.prepare(),r.bindEvents()},bindEvents:function(){r.element.keydown(r.rawEvents.keydown),r.element.keyup(r.rawEvents.keyup),r.element.focus(r.rawEvents.focus),r.element.bind("paste",r.events.paste),r.element.mousedown(r.rawEvents.mouseClick),r.element.mouseup(r.rawEvents.mouseUp),r.element.mousemove(r.rawEvents.mouseMove),r.element.blur(r.rawEvents.blur),e("body").mouseup(function(e){e.target==e.currentTarget&&u.isSelecting&&r.rawEvents.mouseUp(e)})},setPlaceholder:function(e){if(/^\s*$/.test(r.element.text())){r.element.empty();var t=r.utils.html.addTag(r.element,"p").addClass("placeholder");t.append(r.element.attr("editor-placeholder")),r.utils.html.addTag(r.element,"p","undefined"!=typeof e.focus?e.focus:!1,!0)}else r.element.find(".placeholder").remove()},removePlaceholder:function(){r.element.find(".placeholder").remove()},preserveElementFocus:function(){var e=n.getSelection()?n.getSelection().anchorNode:t.activeElement;if(e){var o=e.parentNode,i=o!==u.focusedElement,a=r.element[0].children,l=0;o===r.element[0]&&(o=e);for(var s=0;sn&&n+i>s&&c>o&&o+a>c)return}},mouseUp:function(e){e.preventDefault(),u.isSelecting=!1,setTimeout(function(){var e=r.utils.selection.save();e.collapsed?r.bubble.clear():r.bubble.show()},50)},mouseMove:function(e){s=e.pageX,c=e.pageY},blur:function(){r.setPlaceholder({focus:!1})}},events:{commands:{bold:function(e){e.preventDefault(),t.execCommand("bold",!1),r.bubble.update()},italic:function(e){e.preventDefault(),t.execCommand("italic",!1),r.bubble.update()},underline:function(e){e.preventDefault(),t.execCommand("underline",!1),r.bubble.update()},anchor:function(e){e.preventDefault();var t=r.utils.selection.save();r.bubble.showLinkInput(t)},createLink:function(e,n){r.utils.selection.restore(n),t.execCommand("createLink",!1,e.url),r.bubble.update()},removeLink:function(t,n){var o=e(r.utils.selection.getContainer(n)).closest("a");o.contents().first().unwrap()},h1:function(n){n.preventDefault(),e(window.getSelection().anchorNode.parentNode).is("h1")?t.execCommand("formatBlock",!1,""):t.execCommand("formatBlock",!1,"
"),r.bubble.update()},h2:function(n){n.preventDefault(),e(window.getSelection().anchorNode.parentNode).is("h2")?t.execCommand("formatBlock",!1,"
"):t.execCommand("formatBlock",!1,"
"),r.bubble.update()},ul:function(e){e.preventDefault(),t.execCommand("insertUnorderedList",!1),r.bubble.update()},ol:function(e){e.preventDefault(),t.execCommand("insertOrderedList",!1),r.bubble.update()},undo:function(e){e.preventDefault(),t.execCommand("undo",!1)}},enterKey:function(e){return"inline"===r.element.attr("editor-mode")?void e.preventDefault():void 0},paste:function(){setTimeout(function(){r.element.find("*").each(function(){var t=e(this);e.each(this.attributes,function(){"class"===this.name&&t.hasClass("placeholder")||t.removeAttr(this.name)})})},100)}}}),r.init()},a=function(){var o,i;i=this,o="MacIntel"==n.navigator.platform,e.extend(this,{keyboard:{isCommand:function(e,t,n){o&&e.metaKey||!o&&e.ctrlKey?t():n()},isShift:function(e,t,n){e.shiftKey?t():n()},isModifier:function(e,t){var n=e.which,o=modifiers[n];o&&t(o)},isEnter:function(e,t){13===e.which&&t()},isArrow:function(e,t){(e.which>=37||e.which<=40)&&t()}},html:{addTag:function(n,o,i,a){var l=e(t.createElement(o));return l.attr("contenteditable",Boolean(a)),l.append(" "),n.append(l),i&&(cache.focusedElement=n.children().last(),this.cursor.set(n,0,cache.focusedElement)),l},decode:function(t){return e("
").html(t).text()}},cursor:{set:function(e,o,i){var a;if(t.createRange){a=t.createRange();var l=n.getSelection(),r=e.children().last(),s=r.html().length-1,c=i?i[0]:r[0],u="undefined"!=typeof o?o:s;a.setStart(c,u),a.collapse(!0),l.removeAllRanges(),l.addRange(a)}else a=t.body.createTextRange(),a.moveToElementText(i),a.collapse(!1),a.select()}},selection:{save:function(){if(n.getSelection){var e=n.getSelection();if(e.rangeCount>0)return e.getRangeAt(0)}else if(t.selection&&t.selection.createRange)return t.selection.createRange();return null},restore:function(e){if(e)if(n.getSelection){var o=n.getSelection();o.removeAllRanges(),o.addRange(e)}else t.selection&&e.select&&e.select()},getText:function(){var e="";return n.getSelection?e=n.getSelection().toString():t.getSelection?e=t.getSelection().toString():t.selection&&(e=t.selection.createRange().text),e},clear:function(){window.getSelection?window.getSelection().empty?window.getSelection().empty():window.getSelection().removeAllRanges&&window.getSelection().removeAllRanges():document.selection&&document.selection.empty()},getContainer:function(e){return n.getSelection&&e&&e.commonAncestorContainer?e.commonAncestorContainer:t.selection&&e&&e.parentElement?e.parentElement():null}},validation:{isUrl:function(e){return/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/.test(e)}}})},l=function(t){var i=this;e.extend(i,{isVisible:function(){return i.element.is(":visible")},updatePos:function(){var t=n.getSelection(),a=t.getRangeAt(0),l=a.getBoundingClientRect(),r=i.element.width(),s=i.element.height(),c=(i.notebook.element.offset().left,{x:l.left+l.width/2-r/2,y:l.top-s-8+e(document).scrollTop()});o.translate(i.element,c.x,c.y)},updateState:function(){i.element.find("button").removeClass("active");var e=n.getSelection(),t=[];i.checkForFormatting(e.focusNode,t);for(var o={b:"bold",i:"italic",u:"underline",h1:"h1",h2:"h2",a:"anchor",ul:"ul",ol:"ol"},a=0;a bubbleX && mouseX < bubbleX + bubbleWidth &&
+ mouseY > bubbleY && mouseY < bubbleY + bubbleHeight) {
+ return;
+ }
+ }
+ },
+ mouseUp: function(e) {
+ e.preventDefault();
+ cache.isSelecting = false;
+ setTimeout(function() {
+ var s = self.utils.selection.save();
+ if (s.collapsed) {
+ self.bubble.clear();
+ } else {
+ self.bubble.show();
+ }
+ }, 50);
+ },
+ mouseMove: function(e) {
+ mouseX = e.pageX;
+ mouseY = e.pageY;
+ },
+ blur: function(e) {
+ self.setPlaceholder({
+ focus: false
+ });
+ }
+ },
+ events: {
+ commands: {
+ bold: function(e) {
+ e.preventDefault();
+ d.execCommand('bold', false);
+ self.bubble.update();
+ },
+ italic: function(e) {
+ e.preventDefault();
+ d.execCommand('italic', false);
+ self.bubble.update();
+ },
+ underline: function(e) {
+ e.preventDefault();
+ d.execCommand('underline', false);
+ self.bubble.update();
+ },
+ anchor: function(e) {
+ e.preventDefault();
+ var s = self.utils.selection.save();
+ self.bubble.showLinkInput(s);
+ },
+ createLink: function(e, s) {
+ self.utils.selection.restore(s);
+ d.execCommand('createLink', false, e.url);
+ self.bubble.update();
+ },
+ removeLink: function(e, s) {
+ var el = $(self.utils.selection.getContainer(s)).closest('a');
+ el.contents().first().unwrap();
+ },
+ h1: function(e) {
+ e.preventDefault();
+ if ($(window.getSelection().anchorNode.parentNode).is('h1')) {
+ d.execCommand('formatBlock', false, '');
+ } else {
+ d.execCommand('formatBlock', false, '
');
+ }
+ self.bubble.update();
+ },
+ h2: function(e) {
+ e.preventDefault();
+ if ($(window.getSelection().anchorNode.parentNode).is('h2')) {
+ d.execCommand('formatBlock', false, '
');
+ } else {
+ d.execCommand('formatBlock', false, '
');
+ }
+ self.bubble.update();
+ },
+ ul: function(e) {
+ e.preventDefault();
+ d.execCommand('insertUnorderedList', false);
+ self.bubble.update();
+ },
+ ol: function(e) {
+ e.preventDefault();
+ d.execCommand('insertOrderedList', false);
+ self.bubble.update();
+ },
+ undo: function(e) {
+ e.preventDefault();
+ d.execCommand('undo', false);
+ }
+ },
+ enterKey: function(e) {
+ if (self.element.attr('editor-mode') === 'inline') {
+ e.preventDefault();
+ return;
+ }
+ },
+ paste: function(e) {
+ setTimeout(function() {
+ self.element.find('*').each(function() {
+ var current = $(this);
+ $.each(this.attributes, function() {
+ if (this.name !== 'class' || !current.hasClass('placeholder')) {
+ current.removeAttr(this.name);
+ }
+ });
+ });
+ }, 100);
+ }
+ }
+ });
+ self.init();
+ };
+
+ var Utils = function() {
+ var isMac, self;
+ self = this;
+ isMac = w.navigator.platform == 'MacIntel';
+ $.extend(this, {
keyboard: {
isCommand: function(e, callbackTrue, callbackFalse) {
if (isMac && e.metaKey || !isMac && e.ctrlKey) {
@@ -137,7 +420,7 @@
var key = e.which,
cmd = modifiers[key];
if (cmd) {
- callback.call(this, cmd);
+ callback(cmd);
}
},
isEnter: function(e, callback) {
@@ -159,9 +442,12 @@
elem.append(newElement);
if (focus) {
cache.focusedElement = elem.children().last();
- utils.cursor.set(elem, 0, cache.focusedElement);
+ this.cursor.set(elem, 0, cache.focusedElement);
}
return newElement;
+ },
+ decode: function(str) {
+ return $('
').html(str).text();
}
},
cursor: {
@@ -245,32 +531,39 @@
return (/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/).test(url);
}
}
- },
- bubble = {
+ });
+ };
+
+ var notebookBubble = function(editor) {
+ var self = this;
+ $.extend(self, {
/*
* This is called to position the bubble above the selection.
*/
- updatePos: function(editor, elem) {
+ isVisible: function() {
+ return self.element.is(':visible');
+ },
+ updatePos: function() {
var sel = w.getSelection(),
range = sel.getRangeAt(0),
boundary = range.getBoundingClientRect(),
- bubbleWidth = elem.width(),
- bubbleHeight = elem.height(),
- offset = editor.offset().left,
+ bubbleWidth = self.element.width(),
+ bubbleHeight = self.element.height(),
+ offset = self.notebook.element.offset().left,
pos = {
x: (boundary.left + boundary.width / 2) - bubbleWidth / 2,
y: boundary.top - bubbleHeight - 8 + $(document).scrollTop()
};
- transform.translate(elem, pos.x, pos.y);
+ transform.translate(self.element, pos.x, pos.y);
},
/*
* Updates the bubble to set the active formats for the current selection.
*/
- updateState: function(editor, elem) {
- elem.find('button').removeClass('active');
+ updateState: function() {
+ self.element.find('button').removeClass('active');
var sel = w.getSelection(),
formats = [];
- bubble.checkForFormatting(sel.focusNode, formats);
+ self.checkForFormatting(sel.focusNode, formats);
var formatDict = {
'b': 'bold',
'i': 'italic',
@@ -283,7 +576,7 @@
};
for (var i = 0; i < formats.length; i++) {
var format = formats[i];
- elem.find('button.' + formatDict[format]).addClass('active');
+ self.element.find('button.' + formatDict[format]).addClass('active');
}
},
/*
@@ -297,92 +590,86 @@
if (currentNode.nodeName != '#text') {
formats.push(currentNode.nodeName.toLowerCase());
}
- bubble.checkForFormatting(currentNode.parentNode, formats);
+ self.checkForFormatting(currentNode.parentNode, formats);
}
},
- buildMenu: function(editor, elem) {
- var ul = utils.html.addTag(elem, 'ul', false, false);
- for (var cmd in options.modifiers) {
- var li = utils.html.addTag(ul, 'li', false, false);
- var btn = utils.html.addTag(li, 'button', false, false);
- btn.attr('editor-command', options.modifiers[cmd]);
- btn.addClass(options.modifiers[cmd]);
+ buildMenu: function() {
+ var ul = self.notebook.utils.html.addTag(self.element, 'ul', false, false);
+ for (var cmd in self.notebook.options.modifiers) {
+ var li = self.notebook.utils.html.addTag(ul, 'li', false, false);
+ var btn = self.notebook.utils.html.addTag(li, 'button', false, false);
+ btn.attr('editor-command', self.notebook.options.modifiers[cmd]);
+ btn.addClass(self.notebook.options.modifiers[cmd]);
}
- elem.find('button').click(function(e) {
+ self.element.find('button').click(function(e) {
e.preventDefault();
var cmd = $(this).attr('editor-command');
- events.commands[cmd].call(editor, e);
+ self.notebook.events.commands[cmd](e);
});
- var linkArea = utils.html.addTag(elem, 'div', false, false);
+ var linkArea = self.notebook.utils.html.addTag(self.element, 'div', false, false);
linkArea.addClass('link-area');
- var linkInput = utils.html.addTag(linkArea, 'input', false, false);
+ var linkInput = self.notebook.utils.html.addTag(linkArea, 'input', false, false);
linkInput.attr({
type: 'text'
});
- var closeBtn = utils.html.addTag(linkArea, 'button', false, false);
+ var closeBtn = self.notebook.utils.html.addTag(linkArea, 'button', false, false);
closeBtn.click(function(e) {
e.preventDefault();
- var editor = $(this).closest('.editor');
$(this).closest('.link-area').hide();
- $(this).closest('.bubble').find('ul').show();
+ self.element.find('ul').show();
});
},
+ init: function(editor) {
+ self.notebook = editor;
+
+ self.element = self.notebook.utils.html.addTag(self.notebook.element.parent(), 'div', false, false);
+ self.element.addClass('jquery-notebook bubble');
+ self.buildMenu();
+ },
show: function() {
- var tag = $(this).parent().find('.bubble');
- if (!tag.length) {
- tag = utils.html.addTag($(this).parent(), 'div', false, false);
- tag.addClass('jquery-notebook bubble');
- bubble.buildMenu(this, tag);
- }
- tag.show();
- bubble.updateState(this, tag);
- if (!tag.hasClass('active')) {
- tag.addClass('jump');
- } else {
- tag.removeClass('jump');
- }
- bubble.updatePos($(this), tag);
- tag.addClass('active');
+ self.element.show();
+ self.updateState();
+ self.element.toggleClass('jump');
+ self.updatePos();
+ self.element.addClass('active');
},
update: function() {
- var tag = $(this).parent().find('.bubble');
- bubble.updateState(this, tag);
+ self.updateState();
},
clear: function() {
- var elem = $(this).parent().find('.bubble');
- if (!elem.hasClass('active')) return;
- elem.removeClass('active');
- bubble.hideLinkInput.call(this);
- bubble.showButtons.call(this);
+ if (!self.element.hasClass('active')) return;
+ self.element.removeClass('active');
+ self.hideLinkInput();
+ self.showButtons();
setTimeout(function() {
- if (elem.hasClass('active')) return;
- elem.hide();
+ if (self.element.hasClass('active')) return;
+ self.element.hide();
}, 500);
},
hideButtons: function() {
- $(this).parent().find('.bubble').find('ul').hide();
+ self.element.find('ul').hide();
},
showButtons: function() {
- $(this).parent().find('.bubble').find('ul').show();
+ self.element.find('ul').show();
},
showLinkInput: function(selection) {
- bubble.hideButtons.call(this);
- var editor = this;
- var elem = $(this).parent().find('.bubble').find('input[type=text]');
- var hasLink = elem.closest('.jquery-notebook').find('button.anchor').hasClass('active');
+ self.hideButtons();
+ var elem, hasLink;
+ elem = self.element.find('input[type=text]');
+ hasLink = elem.closest('.jquery-notebook').find('button.anchor').hasClass('active');
elem.unbind('keydown');
elem.keydown(function(e) {
- var elem = $(this);
- utils.keyboard.isEnter(e, function() {
+ var el = $(this);
+ self.notebook.utils.keyboard.isEnter(e, function() {
e.preventDefault();
- var url = elem.val();
- if (utils.validation.isUrl(url)) {
+ var url = el.val();
+ if (self.notebook.utils.validation.isUrl(url)) {
e.url = url;
- events.commands.createLink(e, selection);
- bubble.clear.call(editor);
+ self.notebook.events.commands.createLink(e, selection);
+ self.clear();
} else if (url === '' && hasLink) {
- events.commands.removeLink(e, selection);
- bubble.clear.call(editor);
+ self.notebook.events.commands.removeLink(e, selection);
+ self.clear();
}
});
});
@@ -398,291 +685,26 @@
});
var linkText = 'http://';
if (hasLink) {
- var anchor = $(utils.selection.getContainer(selection)).closest('a');
+ var anchor = $(self.notebook.utils.selection.getContainer(selection)).closest('a');
linkText = anchor.prop('href') || linkText;
}
- $(this).parent().find('.link-area').show();
+ self.notebook.element.parent().find('.link-area').show();
elem.val(linkText).focus();
},
hideLinkInput: function() {
- $(this).parent().find('.bubble').find('.link-area').hide();
+ self.element.find('.link-area').hide();
}
- },
- actions = {
- bindEvents: function(elem) {
- elem.keydown(rawEvents.keydown);
- elem.keyup(rawEvents.keyup);
- elem.focus(rawEvents.focus);
- elem.bind('paste', events.paste);
- elem.mousedown(rawEvents.mouseClick);
- elem.mouseup(rawEvents.mouseUp);
- elem.mousemove(rawEvents.mouseMove);
- elem.blur(rawEvents.blur);
- $('body').mouseup(function(e) {
- if (e.target == e.currentTarget && cache.isSelecting) {
- rawEvents.mouseUp.call(elem, e);
- }
- });
- },
- setPlaceholder: function(e) {
- if (/^\s*$/.test($(this).text())) {
- $(this).empty();
- var placeholder = utils.html.addTag($(this), 'p').addClass('placeholder');
- placeholder.append($(this).attr('editor-placeholder'));
- utils.html.addTag($(this), 'p', typeof e.focus != 'undefined' ? e.focus : false, true);
- } else {
- $(this).find('.placeholder').remove();
- }
- },
- removePlaceholder: function(e) {
- $(this).find('.placeholder').remove();
- },
- preserveElementFocus: function() {
- var anchorNode = w.getSelection() ? w.getSelection().anchorNode : d.activeElement;
- if (anchorNode) {
- var current = anchorNode.parentNode,
- diff = current !== cache.focusedElement,
- children = this.children,
- elementIndex = 0;
- if (current === this) {
- current = anchorNode;
- }
- for (var i = 0; i < children.length; i++) {
- if (current === children[i]) {
- elementIndex = i;
- break;
- }
- }
- if (diff) {
- cache.focusedElement = current;
- cache.focusedElementIndex = elementIndex;
- }
- }
- },
- prepare: function(elem, customOptions) {
- options = customOptions;
- elem.attr('editor-mode', options.mode);
- elem.attr('editor-placeholder', options.placeholder);
- elem.attr('contenteditable', true);
- elem.css('position', 'relative');
- elem.addClass('jquery-notebook editor');
- actions.setPlaceholder.call(elem, {});
- actions.preserveElementFocus.call(elem);
- if (options.autoFocus === true) {
- var firstP = elem.find('p:not(.placeholder)');
- utils.cursor.set(elem, 0, firstP);
- }
- }
- },
- rawEvents = {
- keydown: function(e) {
- var elem = this;
- if (cache.command && e.which === 65) {
- setTimeout(function() {
- bubble.show.call(elem);
- }, 50);
- }
- utils.keyboard.isCommand(e, function() {
- cache.command = true;
- }, function() {
- cache.command = false;
- });
- utils.keyboard.isShift(e, function() {
- cache.shift = true;
- }, function() {
- cache.shift = false;
- });
- utils.keyboard.isModifier.call(this, e, function(modifier) {
- if (cache.command) {
- events.commands[modifier].call(this, e);
- }
- });
-
- if (cache.shift) {
- utils.keyboard.isArrow.call(this, e, function() {
- setTimeout(function() {
- var txt = utils.selection.getText();
- if (txt !== '') {
- bubble.show.call(elem);
- } else {
- bubble.clear.call(elem);
- }
- }, 100);
- });
- } else {
- utils.keyboard.isArrow.call(this, e, function() {
- bubble.clear.call(elem);
- });
- }
+ });
- if (e.which === 13) {
- events.enterKey.call(this, e);
- }
- if (e.which === 27) {
- bubble.clear.call(this);
- }
- if (e.which === 86) {
- events.paste.call(this, e);
- }
- },
- keyup: function(e) {
- utils.keyboard.isCommand(e, function() {
- cache.command = false;
- }, function() {
- cache.command = true;
- });
- actions.preserveElementFocus.call(this);
- actions.removePlaceholder.call(this);
-
- /*
- * This breaks the undo when the whole text is deleted but so far
- * it is the only way that I fould to solve the more serious bug
- * that the editor was losing the p elements after deleting the whole text
- */
- if (/^\s*$/.test($(this).text())) {
- $(this).empty();
- utils.html.addTag($(this), 'p', true, true);
- }
- },
- focus: function(e) {
- cache.command = false;
- cache.shift = false;
- },
- mouseClick: function(e) {
- var elem = this;
- cache.isSelecting = true;
- if (e.button === 2) {
- setTimeout(function() {
- bubble.show.call(elem);
- }, 50);
- e.preventDefault();
- return;
- }
- if ($(this).find('.bubble:visible').length) {
- var bubbleTag = $(this).find('.bubble:visible'),
- bubbleX = bubbleTag.offset().left,
- bubbleY = bubbleTag.offset().top,
- bubbleWidth = bubbleTag.width(),
- bubbleHeight = bubbleTag.height();
- if (mouseX > bubbleX && mouseX < bubbleX + bubbleWidth &&
- mouseY > bubbleY && mouseY < bubbleY + bubbleHeight) {
- return;
- }
- }
- },
- mouseUp: function(e) {
- e.preventDefault();
- var elem = this;
- cache.isSelecting = false;
- setTimeout(function() {
- var s = utils.selection.save();
- if (s.collapsed) {
- bubble.clear.call(elem);
- } else {
- bubble.show.call(elem);
- }
- }, 50);
- },
- mouseMove: function(e) {
- mouseX = e.pageX;
- mouseY = e.pageY;
- },
- blur: function(e) {
- actions.setPlaceholder.call(this, {
- focus: false
- });
- }
- },
- events = {
- commands: {
- bold: function(e) {
- e.preventDefault();
- d.execCommand('bold', false);
- bubble.update.call(this);
- },
- italic: function(e) {
- e.preventDefault();
- d.execCommand('italic', false);
- bubble.update.call(this);
- },
- underline: function(e) {
- e.preventDefault();
- d.execCommand('underline', false);
- bubble.update.call(this);
- },
- anchor: function(e) {
- e.preventDefault();
- var s = utils.selection.save();
- bubble.showLinkInput.call(this, s);
- },
- createLink: function(e, s) {
- utils.selection.restore(s);
- d.execCommand('createLink', false, e.url);
- bubble.update.call(this);
- },
- removeLink: function(e, s) {
- var el = $(utils.selection.getContainer(s)).closest('a');
- el.contents().first().unwrap();
- },
- h1: function(e) {
- e.preventDefault();
- if ($(window.getSelection().anchorNode.parentNode).is('h1')) {
- d.execCommand('formatBlock', false, '
');
- } else {
- d.execCommand('formatBlock', false, '
');
- }
- bubble.update.call(this);
- },
- h2: function(e) {
- e.preventDefault();
- if ($(window.getSelection().anchorNode.parentNode).is('h2')) {
- d.execCommand('formatBlock', false, '
');
- } else {
- d.execCommand('formatBlock', false, '
');
- }
- bubble.update.call(this);
- },
- ul: function(e) {
- e.preventDefault();
- d.execCommand('insertUnorderedList', false);
- bubble.update.call(this);
- },
- ol: function(e) {
- e.preventDefault();
- d.execCommand('insertOrderedList', false);
- bubble.update.call(this);
- },
- undo: function(e) {
- e.preventDefault();
- d.execCommand('undo', false);
- }
- },
- enterKey: function(e) {
- if ($(this).attr('editor-mode') === 'inline') {
- e.preventDefault();
- return;
- }
- },
- paste: function(e) {
- var elem = $(this);
- setTimeout(function() {
- elem.find('*').each(function() {
- var current = $(this);
- $.each(this.attributes, function() {
- if (this.name !== 'class' || !current.hasClass('placeholder')) {
- current.removeAttr(this.name);
- }
- });
- });
- }, 100);
- }
- };
+ self.init(editor);
+ };
$.fn.notebook = function(options) {
options = $.extend({}, $.fn.notebook.defaults, options);
- actions.prepare(this, options);
- actions.bindEvents(this);
- return this;
+
+ return this.each(function() {
+ new Notebook(this, options);
+ });
};
$.fn.notebook.defaults = {