diff --git a/frappe/boot.py b/frappe/boot.py index 8cf75e02bb..0dfcb8d1b4 100644 --- a/frappe/boot.py +++ b/frappe/boot.py @@ -21,7 +21,7 @@ from frappe.website.doctype.web_page_view.web_page_view import is_tracking_enabl from frappe.social.doctype.energy_point_log.energy_point_log import get_energy_points from frappe.model.base_document import get_controller from frappe.social.doctype.post.post import frequently_visited_links -from frappe.core.doctype.navbar_settings.navbar_settings import get_navbar_settings +from frappe.core.doctype.navbar_settings.navbar_settings import get_navbar_settings, get_app_logo def get_bootinfo(): """build and return boot info""" @@ -62,6 +62,7 @@ def get_bootinfo(): doclist.extend(get_meta_bundle("Page")) bootinfo.home_folder = frappe.db.get_value("File", {"is_home_folder": 1}) bootinfo.navbar_settings = get_navbar_settings() + bootinfo.notification_settings = get_notification_settings() # ipinfo if frappe.session.data.get('ipinfo'): @@ -90,6 +91,7 @@ def get_bootinfo(): bootinfo.link_preview_doctypes = get_link_preview_doctypes() bootinfo.additional_filters_config = get_additional_filters_from_hooks() bootinfo.desk_settings = get_desk_settings() + bootinfo.app_logo_url = get_app_logo() return bootinfo @@ -323,4 +325,7 @@ def get_desk_settings(): for key in desk_properties: desk_settings[key] = desk_settings.get(key) or role.get(key) - return desk_settings \ No newline at end of file + return desk_settings + +def get_notification_settings(): + return frappe.get_cached_doc('Notification Settings', frappe.session.user) diff --git a/frappe/core/doctype/navbar_settings/navbar_settings.py b/frappe/core/doctype/navbar_settings/navbar_settings.py index db510981a4..2244bc9e4e 100644 --- a/frappe/core/doctype/navbar_settings/navbar_settings.py +++ b/frappe/core/doctype/navbar_settings/navbar_settings.py @@ -25,7 +25,7 @@ class NavbarSettings(Document): @frappe.whitelist(allow_guest=True) def get_app_logo(): - app_logo = frappe.db.get_single_value('Navbar Settings', 'app_logo') + app_logo = frappe.db.get_single_value('Navbar Settings', 'app_logo', cache=True) if not app_logo: app_logo = frappe.get_hooks('app_logo_url')[-1] diff --git a/frappe/email/test_email_body.py b/frappe/email/test_email_body.py index 9b0b5e41d7..3fcabb9495 100644 --- a/frappe/email/test_email_body.py +++ b/frappe/email/test_email_body.py @@ -17,7 +17,7 @@ class TestEmailBody(unittest.TestCase):
This is embedded image you asked for
-tags if they are specified in the 'unformatted array' - for (var i=0; i]*>\s*$/); - - // if next_tag comes back but is not an isolated tag, then - // let's treat the 'a' tag as having content - // and respect the unformatted option - if (!tag || this.Utils.in_array(tag, unformatted)){ - return true; - } else { - return false; - } - }; - - this.printer = function (js_source, indent_character, indent_size, max_char, brace_style) { //handles input/output and some other printing functions - - this.input = js_source || ''; //gets the input for the Parser - this.output = []; - this.indent_character = indent_character; - this.indent_string = ''; - this.indent_size = indent_size; - this.brace_style = brace_style; - this.indent_level = 0; - this.max_char = max_char; - this.line_char_count = 0; //count to see if max_char was exceeded - - for (var i=0; i 0) { - this.indent_level--; - } - }; - }; - return this; - } - - /*_____________________--------------------_____________________*/ - - multi_parser = new Parser(); //wrapping functions Parser - multi_parser.printer(html_source, indent_character, indent_size, max_char, brace_style); //initialize starting values - - while (true) { - var t = multi_parser.get_token(); - multi_parser.token_text = t[0]; - multi_parser.token_type = t[1]; - - if (multi_parser.token_type === 'TK_EOF') { - break; - } - - switch (multi_parser.token_type) { - case 'TK_TAG_START': - multi_parser.print_newline(false, multi_parser.output); - multi_parser.print_token(multi_parser.token_text); - multi_parser.indent(); - multi_parser.current_mode = 'CONTENT'; - break; - case 'TK_TAG_STYLE': - case 'TK_TAG_SCRIPT': - multi_parser.print_newline(false, multi_parser.output); - multi_parser.print_token(multi_parser.token_text); - multi_parser.current_mode = 'CONTENT'; - break; - case 'TK_TAG_END': - //Print new line only if the tag has no content and has child - if (multi_parser.last_token === 'TK_CONTENT' && multi_parser.last_text === '') { - var tag_name = multi_parser.token_text.match(/\w+/)[0]; - var tag_extracted_from_last_output = multi_parser.output[multi_parser.output.length -1].match(/<\s*(\w+)/); - if (tag_extracted_from_last_output === null || tag_extracted_from_last_output[1] !== tag_name) { - multi_parser.print_newline(true, multi_parser.output); - } - } - multi_parser.print_token(multi_parser.token_text); - multi_parser.current_mode = 'CONTENT'; - break; - case 'TK_TAG_SINGLE': - // Don't add a newline before elements that should remain unformatted. - var tag_check = multi_parser.token_text.match(/^\s*<([a-z]+)/i); - if (!tag_check || !multi_parser.Utils.in_array(tag_check[1], unformatted)){ - multi_parser.print_newline(false, multi_parser.output); - } - multi_parser.print_token(multi_parser.token_text); - multi_parser.current_mode = 'CONTENT'; - break; - case 'TK_CONTENT': - if (multi_parser.token_text !== '') { - multi_parser.print_token(multi_parser.token_text); - } - multi_parser.current_mode = 'TAG'; - break; - case 'TK_STYLE': - case 'TK_SCRIPT': - if (multi_parser.token_text !== '') { - multi_parser.output.push('\n'); - var text = multi_parser.token_text, - _beautifier, - script_indent_level = 1; - if (multi_parser.token_type === 'TK_SCRIPT') { - _beautifier = typeof js_beautify === 'function' && js_beautify; - } else if (multi_parser.token_type === 'TK_STYLE') { - _beautifier = typeof css_beautify === 'function' && css_beautify; - } - - if (options.indent_scripts === "keep") { - script_indent_level = 0; - } else if (options.indent_scripts === "separate") { - script_indent_level = -multi_parser.indent_level; - } - - var indentation = multi_parser.get_full_indent(script_indent_level); - if (_beautifier) { - // call the Beautifier if avaliable - text = _beautifier(text.replace(/^\s*/, indentation), options); - } else { - // simply indent the string otherwise - var white = text.match(/^\s*/)[0]; - var _level = white.match(/[^\n\r]*$/)[0].split(multi_parser.indent_string).length - 1; - var reindent = multi_parser.get_full_indent(script_indent_level -_level); - text = text.replace(/^\s*/, indentation) - .replace(/\r\n|\r|\n/g, '\n' + reindent) - .replace(/\s*$/, ''); - } - if (text) { - multi_parser.print_token(text); - multi_parser.print_newline(true, multi_parser.output); - } - } - multi_parser.current_mode = 'TAG'; - break; - } - multi_parser.last_token = multi_parser.token_type; - multi_parser.last_text = multi_parser.token_text; - } - return multi_parser.output.join(''); - } - - // If we're running a web page and don't have either of the above, add our one global - window.html_beautify = function(html_source, options) { - return style_html(html_source, options, window.js_beautify, window.css_beautify); - }; - -}()); \ No newline at end of file diff --git a/frappe/public/js/lib/jscolor/arrow.gif b/frappe/public/js/lib/jscolor/arrow.gif deleted file mode 100644 index 246478a864..0000000000 Binary files a/frappe/public/js/lib/jscolor/arrow.gif and /dev/null differ diff --git a/frappe/public/js/lib/jscolor/cross.gif b/frappe/public/js/lib/jscolor/cross.gif deleted file mode 100644 index 0ee9c7ac51..0000000000 Binary files a/frappe/public/js/lib/jscolor/cross.gif and /dev/null differ diff --git a/frappe/public/js/lib/jscolor/demo.html b/frappe/public/js/lib/jscolor/demo.html deleted file mode 100644 index cb86066490..0000000000 --- a/frappe/public/js/lib/jscolor/demo.html +++ /dev/null @@ -1,12 +0,0 @@ - - - jscolor demo - - - - - - Click here: - - - diff --git a/frappe/public/js/lib/jscolor/hs.png b/frappe/public/js/lib/jscolor/hs.png deleted file mode 100644 index 3d94486ced..0000000000 Binary files a/frappe/public/js/lib/jscolor/hs.png and /dev/null differ diff --git a/frappe/public/js/lib/jscolor/hv.png b/frappe/public/js/lib/jscolor/hv.png deleted file mode 100644 index 1c5e01f8bc..0000000000 Binary files a/frappe/public/js/lib/jscolor/hv.png and /dev/null differ diff --git a/frappe/public/js/lib/jscolor/jscolor.js b/frappe/public/js/lib/jscolor/jscolor.js deleted file mode 100644 index 986f89bfc2..0000000000 --- a/frappe/public/js/lib/jscolor/jscolor.js +++ /dev/null @@ -1,997 +0,0 @@ -/** - * jscolor, JavaScript Color Picker - * - * @version 1.4.2 - * @license GNU Lesser General Public License, http://www.gnu.org/copyleft/lesser.html - * @author Jan Odvarko, http://odvarko.cz - * @created 2008-06-15 - * @updated 2013-11-25 - * @link http://jscolor.com - */ - - -var jscolor = { - - - dir : 'assets/frappe/js/lib/jscolor/', // location of jscolor directory (leave empty to autodetect) - bindClass : 'color', // class name - binding : true, // automatic binding via - preloading : true, // use image preloading? - - - install : function() { - jscolor.addEvent(window, 'load', jscolor.init); - }, - - - init : function() { - if(jscolor.binding) { - jscolor.bind(); - } - if(jscolor.preloading) { - jscolor.preload(); - } - }, - - - getDir : function() { - if(!jscolor.dir) { - var detected = jscolor.detectDir(); - jscolor.dir = detected!==false ? detected : 'assets/frappe/js/lib/'; - } - return jscolor.dir; - }, - - - detectDir : function() { - var base = location.href; - - var e = document.getElementsByTagName('base'); - for(var i=0; ivs[a] ? - (-vp[a]+tp[a]+ts[a]/2 > vs[a]/2 && tp[a]+ts[a]-ps[a] >= 0 ? tp[a]+ts[a]-ps[a] : tp[a]) : - tp[a], - -vp[b]+tp[b]+ts[b]+ps[b]-l+l*c > vs[b] ? - (-vp[b]+tp[b]+ts[b]/2 > vs[b]/2 && tp[b]+ts[b]-l-l*c >= 0 ? tp[b]+ts[b]-l-l*c : tp[b]+ts[b]-l+l*c) : - (tp[b]+ts[b]-l+l*c >= 0 ? tp[b]+ts[b]-l+l*c : tp[b]+ts[b]-l-l*c) - ]; - } - drawPicker(pp[a], pp[b]); - } - }; - - - this.importColor = function() { - if(!valueElement) { - this.exportColor(); - } else { - if(!this.adjust) { - if(!this.fromString(valueElement.value, leaveValue)) { - styleElement.style.backgroundImage = styleElement.jscStyle.backgroundImage; - styleElement.style.backgroundColor = styleElement.jscStyle.backgroundColor; - styleElement.style.color = styleElement.jscStyle.color; - this.exportColor(leaveValue | leaveStyle); - } - } else if(!this.required && /^\s*$/.test(valueElement.value)) { - valueElement.value = ''; - styleElement.style.backgroundImage = styleElement.jscStyle.backgroundImage; - styleElement.style.backgroundColor = styleElement.jscStyle.backgroundColor; - styleElement.style.color = styleElement.jscStyle.color; - this.exportColor(leaveValue | leaveStyle); - - } else if(this.fromString(valueElement.value)) { - // OK - } else { - this.exportColor(); - } - } - }; - - - this.exportColor = function(flags) { - if(!(flags & leaveValue) && valueElement) { - var value = this.toString(); - if(this.caps) { value = value.toUpperCase(); } - if(this.hash) { value = '#'+value; } - valueElement.value = value; - } - if(!(flags & leaveStyle) && styleElement) { - styleElement.style.backgroundImage = "none"; - styleElement.style.backgroundColor = - '#'+this.toString(); - styleElement.style.color = - 0.213 * this.rgb[0] + - 0.715 * this.rgb[1] + - 0.072 * this.rgb[2] - < 0.5 ? '#FFF' : '#000'; - } - if(!(flags & leavePad) && isPickerOwner()) { - redrawPad(); - } - if(!(flags & leaveSld) && isPickerOwner()) { - redrawSld(); - } - }; - - - this.fromHSV = function(h, s, v, flags) { // null = don't change - if(h !== null) { h = Math.max(0.0, this.minH, Math.min(6.0, this.maxH, h)); } - if(s !== null) { s = Math.max(0.0, this.minS, Math.min(1.0, this.maxS, s)); } - if(v !== null) { v = Math.max(0.0, this.minV, Math.min(1.0, this.maxV, v)); } - - this.rgb = HSV_RGB( - h===null ? this.hsv[0] : (this.hsv[0]=h), - s===null ? this.hsv[1] : (this.hsv[1]=s), - v===null ? this.hsv[2] : (this.hsv[2]=v) - ); - - this.exportColor(flags); - }; - - - this.fromRGB = function(r, g, b, flags) { // null = don't change - if(r !== null) { r = Math.max(0.0, Math.min(1.0, r)); } - if(g !== null) { g = Math.max(0.0, Math.min(1.0, g)); } - if(b !== null) { b = Math.max(0.0, Math.min(1.0, b)); } - - var hsv = RGB_HSV( - r===null ? this.rgb[0] : r, - g===null ? this.rgb[1] : g, - b===null ? this.rgb[2] : b - ); - if(hsv[0] !== null) { - this.hsv[0] = Math.max(0.0, this.minH, Math.min(6.0, this.maxH, hsv[0])); - } - if(hsv[2] !== 0) { - this.hsv[1] = hsv[1]===null ? null : Math.max(0.0, this.minS, Math.min(1.0, this.maxS, hsv[1])); - } - this.hsv[2] = hsv[2]===null ? null : Math.max(0.0, this.minV, Math.min(1.0, this.maxV, hsv[2])); - - // update RGB according to final HSV, as some values might be trimmed - var rgb = HSV_RGB(this.hsv[0], this.hsv[1], this.hsv[2]); - this.rgb[0] = rgb[0]; - this.rgb[1] = rgb[1]; - this.rgb[2] = rgb[2]; - - this.exportColor(flags); - }; - - - this.fromString = function(hex, flags) { - var m = hex.match(/^\W*([0-9A-F]{3}([0-9A-F]{3})?)\W*$/i); - if(!m) { - return false; - } else { - if(m[1].length === 6) { // 6-char notation - this.fromRGB( - parseInt(m[1].substr(0,2),16) / 255, - parseInt(m[1].substr(2,2),16) / 255, - parseInt(m[1].substr(4,2),16) / 255, - flags - ); - } else { // 3-char notation - this.fromRGB( - parseInt(m[1].charAt(0)+m[1].charAt(0),16) / 255, - parseInt(m[1].charAt(1)+m[1].charAt(1),16) / 255, - parseInt(m[1].charAt(2)+m[1].charAt(2),16) / 255, - flags - ); - } - return true; - } - }; - - - this.toString = function() { - return ( - (0x100 | Math.round(255*this.rgb[0])).toString(16).substr(1) + - (0x100 | Math.round(255*this.rgb[1])).toString(16).substr(1) + - (0x100 | Math.round(255*this.rgb[2])).toString(16).substr(1) - ); - }; - - - function RGB_HSV(r, g, b) { - var n = Math.min(Math.min(r,g),b); - var v = Math.max(Math.max(r,g),b); - var m = v - n; - if(m === 0) { return [ null, 0, v ]; } - var h = r===n ? 3+(b-g)/m : (g===n ? 5+(r-b)/m : 1+(g-r)/m); - return [ h===6?0:h, m/v, v ]; - } - - - function HSV_RGB(h, s, v) { - if(h === null) { return [ v, v, v ]; } - var i = Math.floor(h); - var f = i%2 ? h-i : 1-(h-i); - var m = v * (1 - s); - var n = v * (1 - s*f); - switch(i) { - case 6: - case 0: return [v,n,m]; - case 1: return [n,v,m]; - case 2: return [m,v,n]; - case 3: return [m,n,v]; - case 4: return [n,m,v]; - case 5: return [v,m,n]; - } - } - - - function removePicker() { - delete jscolor.picker.owner; - document.getElementsByTagName('body')[0].removeChild(jscolor.picker.boxB); - } - - - function drawPicker(x, y) { - if(!jscolor.picker) { - jscolor.picker = { - box : document.createElement('div'), - boxB : document.createElement('div'), - pad : document.createElement('div'), - padB : document.createElement('div'), - padM : document.createElement('div'), - sld : document.createElement('div'), - sldB : document.createElement('div'), - sldM : document.createElement('div'), - btn : document.createElement('div'), - btnS : document.createElement('span'), - btnT : document.createTextNode(THIS.pickerCloseText) - }; - for(var i=0,segSize=4; i .btn-group,.panel-heading.note-toolbar>.btn-group{margin-top:5px;margin-right:5px;margin-left:0}.note-popover .popover-content .btn-group .note-table,.panel-heading.note-toolbar .btn-group .note-table{min-width:0;padding:5px}.note-popover .popover-content .btn-group .note-table .note-dimension-picker,.panel-heading.note-toolbar .btn-group .note-table .note-dimension-picker{font-size:18px}.note-popover .popover-content .btn-group .note-table .note-dimension-picker .note-dimension-picker-mousecatcher,.panel-heading.note-toolbar .btn-group .note-table .note-dimension-picker .note-dimension-picker-mousecatcher{position:absolute!important;z-index:3;width:10em;height:10em;cursor:pointer}.note-popover .popover-content .btn-group .note-table .note-dimension-picker .note-dimension-picker-unhighlighted,.panel-heading.note-toolbar .btn-group .note-table .note-dimension-picker .note-dimension-picker-unhighlighted{position:relative!important;z-index:1;width:5em;height:5em;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIj4+Pjp6ekKlAqjAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKhmnaJzPAAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC') repeat}.note-popover .popover-content .btn-group .note-table .note-dimension-picker .note-dimension-picker-highlighted,.panel-heading.note-toolbar .btn-group .note-table .note-dimension-picker .note-dimension-picker-highlighted{position:absolute!important;z-index:2;width:1em;height:1em;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIjd6vvD2f9LKLW+AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKwNDEVT0AAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC') repeat}.note-popover .popover-content .note-style h1,.panel-heading.note-toolbar .note-style h1,.note-popover .popover-content .note-style h2,.panel-heading.note-toolbar .note-style h2,.note-popover .popover-content .note-style h3,.panel-heading.note-toolbar .note-style h3,.note-popover .popover-content .note-style h4,.panel-heading.note-toolbar .note-style h4,.note-popover .popover-content .note-style h5,.panel-heading.note-toolbar .note-style h5,.note-popover .popover-content .note-style h6,.panel-heading.note-toolbar .note-style h6,.note-popover .popover-content .note-style blockquote,.panel-heading.note-toolbar .note-style blockquote{margin:0}.note-popover .popover-content .note-color .dropdown-toggle,.panel-heading.note-toolbar .note-color .dropdown-toggle{width:20px;padding-left:5px}.note-popover .popover-content .note-color .dropdown-menu,.panel-heading.note-toolbar .note-color .dropdown-menu{min-width:340px}.note-popover .popover-content .note-color .dropdown-menu .btn-group,.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group{margin:0}.note-popover .popover-content .note-color .dropdown-menu .btn-group:first-child,.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group:first-child{margin:0 5px}.note-popover .popover-content .note-color .dropdown-menu .btn-group .note-palette-title,.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group .note-palette-title{margin:2px 7px;font-size:12px;text-align:center;border-bottom:1px solid #eee}.note-popover .popover-content .note-color .dropdown-menu .btn-group .note-color-reset,.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group .note-color-reset{width:100%;padding:0 3px;margin:3px;font-size:11px;cursor:pointer;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.note-popover .popover-content .note-color .dropdown-menu .btn-group .note-color-row,.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group .note-color-row{height:20px}.note-popover .popover-content .note-color .dropdown-menu .btn-group .note-color-reset:hover,.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group .note-color-reset:hover{background:#eee}.note-popover .popover-content .note-para .dropdown-menu,.panel-heading.note-toolbar .note-para .dropdown-menu{min-width:216px;padding:5px}.note-popover .popover-content .note-para .dropdown-menu>div:first-child,.panel-heading.note-toolbar .note-para .dropdown-menu>div:first-child{margin-right:5px}.note-popover .popover-content .dropdown-menu,.panel-heading.note-toolbar .dropdown-menu{min-width:90px}.note-popover .popover-content .dropdown-menu.right,.panel-heading.note-toolbar .dropdown-menu.right{right:0;left:auto}.note-popover .popover-content .dropdown-menu.right::before,.panel-heading.note-toolbar .dropdown-menu.right::before{right:9px;left:auto!important}.note-popover .popover-content .dropdown-menu.right::after,.panel-heading.note-toolbar .dropdown-menu.right::after{right:10px;left:auto!important}.note-popover .popover-content .dropdown-menu.note-check li a i,.panel-heading.note-toolbar .dropdown-menu.note-check li a i{color:deepskyblue;visibility:hidden}.note-popover .popover-content .dropdown-menu.note-check li a.checked i,.panel-heading.note-toolbar .dropdown-menu.note-check li a.checked i{visibility:visible}.note-popover .popover-content .note-fontsize-10,.panel-heading.note-toolbar .note-fontsize-10{font-size:10px}.note-popover .popover-content .note-color-palette,.panel-heading.note-toolbar .note-color-palette{line-height:1}.note-popover .popover-content .note-color-palette div .note-color-btn,.panel-heading.note-toolbar .note-color-palette div .note-color-btn{width:20px;height:20px;padding:0;margin:0;border:1px solid #fff}.note-popover .popover-content .note-color-palette div .note-color-btn:hover,.panel-heading.note-toolbar .note-color-palette div .note-color-btn:hover{border:1px solid #000}.note-dialog>div{display:none}.note-dialog .form-group{margin-right:0;margin-left:0}.note-dialog .note-modal-form{margin:0}.note-dialog .note-image-dialog .note-dropzone{min-height:100px;margin-bottom:10px;font-size:30px;line-height:4;color:lightgray;text-align:center;border:4px dashed lightgray}@-moz-document url-prefix(){.note-image-input{height:auto}}.note-placeholder{position:absolute;display:none;color:gray}.note-handle .note-control-selection{position:absolute;display:none;border:1px solid black}.note-handle .note-control-selection>div{position:absolute}.note-handle .note-control-selection .note-control-selection-bg{width:100%;height:100%;background-color:black;-webkit-opacity:.3;-khtml-opacity:.3;-moz-opacity:.3;opacity:.3;-ms-filter:alpha(opacity=30);filter:alpha(opacity=30)}.note-handle .note-control-selection .note-control-handle{width:7px;height:7px;border:1px solid black}.note-handle .note-control-selection .note-control-holder{width:7px;height:7px;border:1px solid black}.note-handle .note-control-selection .note-control-sizing{width:7px;height:7px;background-color:white;border:1px solid black}.note-handle .note-control-selection .note-control-nw{top:-5px;left:-5px;border-right:0;border-bottom:0}.note-handle .note-control-selection .note-control-ne{top:-5px;right:-5px;border-bottom:0;border-left:none}.note-handle .note-control-selection .note-control-sw{bottom:-5px;left:-5px;border-top:0;border-right:0}.note-handle .note-control-selection .note-control-se{right:-5px;bottom:-5px;cursor:se-resize}.note-handle .note-control-selection .note-control-se.note-control-holder{cursor:default;border-top:0;border-left:none}.note-handle .note-control-selection .note-control-selection-info{right:0;bottom:0;padding:5px;margin:5px;font-size:12px;color:white;background-color:black;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;-webkit-opacity:.7;-khtml-opacity:.7;-moz-opacity:.7;opacity:.7;-ms-filter:alpha(opacity=70);filter:alpha(opacity=70)}.note-hint-popover{min-width:100px;padding:2px}.note-hint-popover .popover-content{max-height:150px;padding:3px;overflow:auto}.note-hint-popover .popover-content .note-hint-group .note-hint-item{display:block!important;padding:3px}.note-hint-popover .popover-content .note-hint-group .note-hint-item.active,.note-hint-popover .popover-content .note-hint-group .note-hint-item:hover{display:block;clear:both;font-weight:400;line-height:1.4;color:white;text-decoration:none;white-space:nowrap;cursor:pointer;background-color:#428bca;outline:0} \ No newline at end of file diff --git a/frappe/public/js/lib/summernote/summernote.js b/frappe/public/js/lib/summernote/summernote.js deleted file mode 100755 index 6b410ebd11..0000000000 --- a/frappe/public/js/lib/summernote/summernote.js +++ /dev/null @@ -1,7069 +0,0 @@ -/** - * Super simple wysiwyg editor v0.8.2 - * http://summernote.org/ - * - * summernote.js - * Copyright 2013-2016 Alan Hong. and other contributors - * summernote may be freely distributed under the MIT license./ - * - * Date: 2016-08-07T05:11Z - */ -(function (factory) { - /* global define */ - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - define(['jquery'], factory); - } else if (typeof module === 'object' && module.exports) { - // Node/CommonJS - module.exports = factory(require('jquery')); - } else { - // Browser globals - factory(window.jQuery); - } -}(function ($) { - 'use strict'; - - /** - * @class core.func - * - * func utils (for high-order func's arg) - * - * @singleton - * @alternateClassName func - */ - var func = (function () { - var eq = function (itemA) { - return function (itemB) { - return itemA === itemB; - }; - }; - - var eq2 = function (itemA, itemB) { - return itemA === itemB; - }; - - var peq2 = function (propName) { - return function (itemA, itemB) { - return itemA[propName] === itemB[propName]; - }; - }; - - var ok = function () { - return true; - }; - - var fail = function () { - return false; - }; - - var not = function (f) { - return function () { - return !f.apply(f, arguments); - }; - }; - - var and = function (fA, fB) { - return function (item) { - return fA(item) && fB(item); - }; - }; - - var self = function (a) { - return a; - }; - - var invoke = function (obj, method) { - return function () { - return obj[method].apply(obj, arguments); - }; - }; - - var idCounter = 0; - - /** - * generate a globally-unique id - * - * @param {String} [prefix] - */ - var uniqueId = function (prefix) { - var id = ++idCounter + ''; - return prefix ? prefix + id : id; - }; - - /** - * returns bnd (bounds) from rect - * - * - IE Compatibility Issue: http://goo.gl/sRLOAo - * - Scroll Issue: http://goo.gl/sNjUc - * - * @param {Rect} rect - * @return {Object} bounds - * @return {Number} bounds.top - * @return {Number} bounds.left - * @return {Number} bounds.width - * @return {Number} bounds.height - */ - var rect2bnd = function (rect) { - var $document = $(document); - return { - top: rect.top + $document.scrollTop(), - left: rect.left + $document.scrollLeft(), - width: rect.right - rect.left, - height: rect.bottom - rect.top - }; - }; - - /** - * returns a copy of the object where the keys have become the values and the values the keys. - * @param {Object} obj - * @return {Object} - */ - var invertObject = function (obj) { - var inverted = {}; - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - inverted[obj[key]] = key; - } - } - return inverted; - }; - - /** - * @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(''); - }; - - /** - * Returns a function, that, as long as it continues to be invoked, will not - * be triggered. The function will be called after it stops being called for - * N milliseconds. If `immediate` is passed, trigger the function on the - * leading edge, instead of the trailing. - * @param {Function} func - * @param {Number} wait - * @param {Boolean} immediate - * @return {Function} - */ - var debounce = function (func, wait, immediate) { - var timeout; - return function () { - var context = this, args = arguments; - var later = function () { - timeout = null; - if (!immediate) { - func.apply(context, args); - } - }; - var callNow = immediate && !timeout; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - if (callNow) { - func.apply(context, args); - } - }; - }; - - return { - eq: eq, - eq2: eq2, - peq2: peq2, - ok: ok, - fail: fail, - self: self, - not: not, - and: and, - invoke: invoke, - uniqueId: uniqueId, - rect2bnd: rect2bnd, - invertObject: invertObject, - namespaceToCamel: namespaceToCamel, - debounce: debounce - }; - })(); - - /** - * @class core.list - * - * list utils - * - * @singleton - * @alternateClassName list - */ - var list = (function () { - /** - * returns the first item of an array. - * - * @param {Array} array - */ - var head = function (array) { - return array[0]; - }; - - /** - * returns the last item of an array. - * - * @param {Array} array - */ - var last = function (array) { - return array[array.length - 1]; - }; - - /** - * returns everything but the last entry of the array. - * - * @param {Array} array - */ - var initial = function (array) { - return array.slice(0, array.length - 1); - }; - - /** - * returns the rest of the items in an array. - * - * @param {Array} array - */ - var tail = function (array) { - return array.slice(1); - }; - - /** - * returns item of array - */ - var find = function (array, pred) { - for (var idx = 0, len = array.length; idx < len; idx ++) { - var item = array[idx]; - if (pred(item)) { - return item; - } - } - }; - - /** - * returns true if all of the values in the array pass the predicate truth test. - */ - var all = function (array, pred) { - for (var idx = 0, len = array.length; idx < len; idx ++) { - if (!pred(array[idx])) { - return false; - } - } - return true; - }; - - /** - * returns index of item - */ - var indexOf = function (array, item) { - return $.inArray(item, array); - }; - - /** - * returns true if the value is present in the list. - */ - var contains = function (array, item) { - return indexOf(array, item) !== -1; - }; - - /** - * get sum from a list - * - * @param {Array} array - array - * @param {Function} fn - iterator - */ - var sum = function (array, fn) { - fn = fn || func.self; - return array.reduce(function (memo, v) { - return memo + fn(v); - }, 0); - }; - - /** - * returns a copy of the collection with array type. - * @param {Collection} collection - collection eg) node.childNodes, ... - */ - var from = function (collection) { - var result = [], idx = -1, length = collection.length; - while (++idx < length) { - result[idx] = collection[idx]; - } - return result; - }; - - /** - * returns whether list is empty or not - */ - var isEmpty = function (array) { - return !array || !array.length; - }; - - /** - * cluster elements by predicate function. - * - * @param {Array} array - array - * @param {Function} fn - predicate function for cluster rule - * @param {Array[]} - */ - var clusterBy = function (array, fn) { - if (!array.length) { return []; } - var aTail = tail(array); - return aTail.reduce(function (memo, v) { - var aLast = last(memo); - if (fn(last(aLast), v)) { - aLast[aLast.length] = v; - } else { - memo[memo.length] = [v]; - } - return memo; - }, [[head(array)]]); - }; - - /** - * returns a copy of the array with all false values removed - * - * @param {Array} array - array - * @param {Function} fn - predicate function for cluster rule - */ - var compact = function (array) { - var aResult = []; - for (var idx = 0, len = array.length; idx < len; idx ++) { - if (array[idx]) { aResult.push(array[idx]); } - } - return aResult; - }; - - /** - * produces a duplicate-free version of the array - * - * @param {Array} array - */ - var unique = function (array) { - var results = []; - - for (var idx = 0, len = array.length; idx < len; idx ++) { - if (!contains(results, array[idx])) { - results.push(array[idx]); - } - } - - return results; - }; - - /** - * returns next item. - * @param {Array} array - */ - var next = function (array, item) { - var idx = indexOf(array, item); - if (idx === -1) { return null; } - - return array[idx + 1]; - }; - - /** - * returns prev item. - * @param {Array} array - */ - var prev = function (array, item) { - var idx = indexOf(array, item); - if (idx === -1) { return null; } - - return array[idx - 1]; - }; - - return { head: head, last: last, initial: initial, tail: tail, - prev: prev, next: next, find: find, contains: contains, - all: all, sum: sum, from: from, isEmpty: isEmpty, - clusterBy: clusterBy, compact: compact, unique: unique }; - })(); - - var isSupportAmd = typeof define === 'function' && define.amd; - - /** - * returns whether font is installed or not. - * - * @param {String} fontName - * @return {Boolean} - */ - var isFontInstalled = function (fontName) { - var testFontName = fontName === 'Comic Sans MS' ? 'Courier New' : 'Comic Sans MS'; - var $tester = $(' ').css({ - position: 'absolute', - left: '-9999px', - top: '-9999px', - fontSize: '200px' - }).text('mmmmmmmmmwwwwwww').appendTo(document.body); - - var originalWidth = $tester.css('fontFamily', testFontName).width(); - var width = $tester.css('fontFamily', fontName + ',' + testFontName).width(); - - $tester.remove(); - - return originalWidth !== width; - }; - - var userAgent = navigator.userAgent; - var isMSIE = /MSIE|Trident/i.test(userAgent); - var browserVersion; - if (isMSIE) { - var matches = /MSIE (\d+[.]\d+)/.exec(userAgent); - if (matches) { - browserVersion = parseFloat(matches[1]); - } - matches = /Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/.exec(userAgent); - if (matches) { - browserVersion = parseFloat(matches[1]); - } - } - - var isEdge = /Edge\/\d+/.test(userAgent); - - var hasCodeMirror = !!window.CodeMirror; - if (!hasCodeMirror && isSupportAmd && typeof require !== 'undefined') { - if (typeof require.resolve !== 'undefined') { - try { - // If CodeMirror can't be resolved, `require.resolve` will throw an - // exception and `hasCodeMirror` won't be set to `true`. - require.resolve('codemirror'); - hasCodeMirror = true; - } catch (e) { - // Do nothing. - } - } else if (typeof eval('require').specified !== 'undefined') { - hasCodeMirror = eval('require').specified('codemirror'); - } - } - - /** - * @class core.agent - * - * Object which check platform and agent - * - * @singleton - * @alternateClassName agent - */ - var agent = { - isMac: navigator.appVersion.indexOf('Mac') > -1, - isMSIE: isMSIE, - isEdge: isEdge, - isFF: !isEdge && /firefox/i.test(userAgent), - isPhantom: /PhantomJS/i.test(userAgent), - isWebkit: !isEdge && /webkit/i.test(userAgent), - isChrome: !isEdge && /chrome/i.test(userAgent), - isSafari: !isEdge && /safari/i.test(userAgent), - browserVersion: browserVersion, - jqueryVersion: parseFloat($.fn.jquery), - isSupportAmd: isSupportAmd, - hasCodeMirror: hasCodeMirror, - isFontInstalled: isFontInstalled, - isW3CRangeSupport: !!document.createRange - }; - - - var NBSP_CHAR = String.fromCharCode(160); - var ZERO_WIDTH_NBSP_CHAR = '\ufeff'; - - /** - * @class core.dom - * - * Dom functions - * - * @singleton - * @alternateClassName dom - */ - var dom = (function () { - /** - * @method isEditable - * - * returns whether node is `note-editable` or not. - * - * @param {Node} node - * @return {Boolean} - */ - var isEditable = function (node) { - return node && $(node).hasClass('note-editable'); - }; - - /** - * @method isControlSizing - * - * returns whether node is `note-control-sizing` or not. - * - * @param {Node} node - * @return {Boolean} - */ - var isControlSizing = function (node) { - return node && $(node).hasClass('note-control-sizing'); - }; - - /** - * @method makePredByNodeName - * - * returns predicate which judge whether nodeName is same - * - * @param {String} nodeName - * @return {Function} - */ - var makePredByNodeName = function (nodeName) { - nodeName = nodeName.toUpperCase(); - return function (node) { - return node && node.nodeName.toUpperCase() === nodeName; - }; - }; - - /** - * @method isText - * - * - * - * @param {Node} node - * @return {Boolean} true if node's type is text(3) - */ - var isText = function (node) { - return node && node.nodeType === 3; - }; - - /** - * @method isElement - * - * - * - * @param {Node} node - * @return {Boolean} true if node's type is element(1) - */ - var isElement = function (node) { - return node && node.nodeType === 1; - }; - - /** - * ex) br, col, embed, hr, img, input, ... - * @see http://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements - */ - var isVoid = function (node) { - return node && /^BR|^IMG|^HR|^IFRAME|^BUTTON/.test(node.nodeName.toUpperCase()); - }; - - var isPara = function (node) { - if (isEditable(node)) { - return false; - } - - // Chrome(v31.0), FF(v25.0.1) use DIV for paragraph - return node && /^DIV|^P|^LI|^H[1-7]/.test(node.nodeName.toUpperCase()); - }; - - var isHeading = function (node) { - return node && /^H[1-7]/.test(node.nodeName.toUpperCase()); - }; - - var isPre = makePredByNodeName('PRE'); - - var isLi = makePredByNodeName('LI'); - - var isPurePara = function (node) { - return isPara(node) && !isLi(node); - }; - - var isTable = makePredByNodeName('TABLE'); - - var isData = makePredByNodeName('DATA'); - - var isInline = function (node) { - return !isBodyContainer(node) && - !isList(node) && - !isHr(node) && - !isPara(node) && - !isTable(node) && - !isBlockquote(node) && - !isData(node); - }; - - var isList = function (node) { - return node && /^UL|^OL/.test(node.nodeName.toUpperCase()); - }; - - var isHr = makePredByNodeName('HR'); - - var isCell = function (node) { - return node && /^TD|^TH/.test(node.nodeName.toUpperCase()); - }; - - var isBlockquote = makePredByNodeName('BLOCKQUOTE'); - - var isBodyContainer = function (node) { - return isCell(node) || isBlockquote(node) || isEditable(node); - }; - - var isAnchor = makePredByNodeName('A'); - - var isParaInline = function (node) { - return isInline(node) && !!ancestor(node, isPara); - }; - - var isBodyInline = function (node) { - return isInline(node) && !ancestor(node, isPara); - }; - - var isBody = makePredByNodeName('BODY'); - - /** - * returns whether nodeB is closest sibling of nodeA - * - * @param {Node} nodeA - * @param {Node} nodeB - * @return {Boolean} - */ - var isClosestSibling = function (nodeA, nodeB) { - return nodeA.nextSibling === nodeB || - nodeA.previousSibling === nodeB; - }; - - /** - * returns array of closest siblings with node - * - * @param {Node} node - * @param {function} [pred] - predicate function - * @return {Node[]} - */ - var withClosestSiblings = function (node, pred) { - pred = pred || func.ok; - - var siblings = []; - if (node.previousSibling && pred(node.previousSibling)) { - siblings.push(node.previousSibling); - } - siblings.push(node); - if (node.nextSibling && pred(node.nextSibling)) { - siblings.push(node.nextSibling); - } - return siblings; - }; - - /** - * blank HTML for cursor position - * - [workaround] old IE only works with - * - [workaround] IE11 and other browser works with bogus br - */ - var blankHTML = agent.isMSIE && agent.browserVersion < 11 ? ' ' : '
'; - - /** - * @method nodeLength - * - * returns #text's text size or element's childNodes size - * - * @param {Node} node - */ - var nodeLength = function (node) { - if (isText(node)) { - return node.nodeValue.length; - } - - if (node) { - return node.childNodes.length; - } - - return 0; - - }; - - /** - * returns whether node is empty or not. - * - * @param {Node} node - * @return {Boolean} - */ - var isEmpty = function (node) { - var len = nodeLength(node); - - if (len === 0) { - return true; - } else if (!isText(node) && len === 1 && node.innerHTML === blankHTML) { - // ex),
- return true; - } else if (list.all(node.childNodes, isText) && node.innerHTML === '') { - // ex) , - return true; - } - - return false; - }; - - /** - * padding blankHTML if node is empty (for cursor position) - */ - var paddingBlankHTML = function (node) { - if (!isVoid(node) && !nodeLength(node)) { - node.innerHTML = blankHTML; - } - }; - - /** - * find nearest ancestor predicate hit - * - * @param {Node} node - * @param {Function} pred - predicate function - */ - var ancestor = function (node, pred) { - while (node) { - if (pred(node)) { return node; } - if (isEditable(node)) { break; } - - node = node.parentNode; - } - return null; - }; - - /** - * find nearest ancestor only single child blood line and predicate hit - * - * @param {Node} node - * @param {Function} pred - predicate function - */ - var singleChildAncestor = function (node, pred) { - node = node.parentNode; - - while (node) { - if (nodeLength(node) !== 1) { break; } - if (pred(node)) { return node; } - if (isEditable(node)) { break; } - - node = node.parentNode; - } - return null; - }; - - /** - * returns new array of ancestor nodes (until predicate hit). - * - * @param {Node} node - * @param {Function} [optional] pred - predicate function - */ - var listAncestor = function (node, pred) { - pred = pred || func.fail; - - var ancestors = []; - ancestor(node, function (el) { - if (!isEditable(el)) { - ancestors.push(el); - } - - return pred(el); - }); - return ancestors; - }; - - /** - * find farthest ancestor predicate hit - */ - var lastAncestor = function (node, pred) { - var ancestors = listAncestor(node); - return list.last(ancestors.filter(pred)); - }; - - /** - * returns common ancestor node between two nodes. - * - * @param {Node} nodeA - * @param {Node} nodeB - */ - var commonAncestor = function (nodeA, nodeB) { - var ancestors = listAncestor(nodeA); - for (var n = nodeB; n; n = n.parentNode) { - if ($.inArray(n, ancestors) > -1) { return n; } - } - return null; // difference document area - }; - - /** - * listing all previous siblings (until predicate hit). - * - * @param {Node} node - * @param {Function} [optional] pred - predicate function - */ - var listPrev = function (node, pred) { - pred = pred || func.fail; - - var nodes = []; - while (node) { - if (pred(node)) { break; } - nodes.push(node); - node = node.previousSibling; - } - return nodes; - }; - - /** - * listing next siblings (until predicate hit). - * - * @param {Node} node - * @param {Function} [pred] - predicate function - */ - var listNext = function (node, pred) { - pred = pred || func.fail; - - var nodes = []; - while (node) { - if (pred(node)) { break; } - nodes.push(node); - node = node.nextSibling; - } - return nodes; - }; - - /** - * listing descendant nodes - * - * @param {Node} node - * @param {Function} [pred] - predicate function - */ - var listDescendant = function (node, pred) { - var descendants = []; - pred = pred || func.ok; - - // start DFS(depth first search) with node - (function fnWalk(current) { - if (node !== current && pred(current)) { - descendants.push(current); - } - for (var idx = 0, len = current.childNodes.length; idx < len; idx++) { - fnWalk(current.childNodes[idx]); - } - })(node); - - return descendants; - }; - - /** - * wrap node with new tag. - * - * @param {Node} node - * @param {Node} tagName of wrapper - * @return {Node} - wrapper - */ - var wrap = function (node, wrapperName) { - var parent = node.parentNode; - var wrapper = $('<' + wrapperName + '>')[0]; - - parent.insertBefore(wrapper, node); - wrapper.appendChild(node); - - return wrapper; - }; - - /** - * insert node after preceding - * - * @param {Node} node - * @param {Node} preceding - predicate function - */ - var insertAfter = function (node, preceding) { - var next = preceding.nextSibling, parent = preceding.parentNode; - if (next) { - parent.insertBefore(node, next); - } else { - parent.appendChild(node); - } - return node; - }; - - /** - * append elements. - * - * @param {Node} node - * @param {Collection} aChild - */ - var appendChildNodes = function (node, aChild) { - $.each(aChild, function (idx, child) { - node.appendChild(child); - }); - return node; - }; - - /** - * returns whether boundaryPoint is left edge or not. - * - * @param {BoundaryPoint} point - * @return {Boolean} - */ - var isLeftEdgePoint = function (point) { - return point.offset === 0; - }; - - /** - * returns whether boundaryPoint is right edge or not. - * - * @param {BoundaryPoint} point - * @return {Boolean} - */ - var isRightEdgePoint = function (point) { - return point.offset === nodeLength(point.node); - }; - - /** - * returns whether boundaryPoint is edge or not. - * - * @param {BoundaryPoint} point - * @return {Boolean} - */ - var isEdgePoint = function (point) { - return isLeftEdgePoint(point) || isRightEdgePoint(point); - }; - - /** - * returns whether node is left edge of ancestor or not. - * - * @param {Node} node - * @param {Node} ancestor - * @return {Boolean} - */ - var isLeftEdgeOf = function (node, ancestor) { - while (node && node !== ancestor) { - if (position(node) !== 0) { - return false; - } - node = node.parentNode; - } - - return true; - }; - - /** - * returns whether node is right edge of ancestor or not. - * - * @param {Node} node - * @param {Node} ancestor - * @return {Boolean} - */ - var isRightEdgeOf = function (node, ancestor) { - if (!ancestor) { - return false; - } - while (node && node !== ancestor) { - if (position(node) !== nodeLength(node.parentNode) - 1) { - return false; - } - node = node.parentNode; - } - - return true; - }; - - /** - * returns whether point is left edge of ancestor or not. - * @param {BoundaryPoint} point - * @param {Node} ancestor - * @return {Boolean} - */ - var isLeftEdgePointOf = function (point, ancestor) { - return isLeftEdgePoint(point) && isLeftEdgeOf(point.node, ancestor); - }; - - /** - * returns whether point is right edge of ancestor or not. - * @param {BoundaryPoint} point - * @param {Node} ancestor - * @return {Boolean} - */ - var isRightEdgePointOf = function (point, ancestor) { - return isRightEdgePoint(point) && isRightEdgeOf(point.node, ancestor); - }; - - /** - * returns offset from parent. - * - * @param {Node} node - */ - var position = function (node) { - var offset = 0; - while ((node = node.previousSibling)) { - offset += 1; - } - return offset; - }; - - var hasChildren = function (node) { - return !!(node && node.childNodes && node.childNodes.length); - }; - - /** - * returns previous boundaryPoint - * - * @param {BoundaryPoint} point - * @param {Boolean} isSkipInnerOffset - * @return {BoundaryPoint} - */ - var prevPoint = function (point, isSkipInnerOffset) { - var node, offset; - - if (point.offset === 0) { - if (isEditable(point.node)) { - return null; - } - - node = point.node.parentNode; - offset = position(point.node); - } else if (hasChildren(point.node)) { - node = point.node.childNodes[point.offset - 1]; - offset = nodeLength(node); - } else { - node = point.node; - offset = isSkipInnerOffset ? 0 : point.offset - 1; - } - - return { - node: node, - offset: offset - }; - }; - - /** - * returns next boundaryPoint - * - * @param {BoundaryPoint} point - * @param {Boolean} isSkipInnerOffset - * @return {BoundaryPoint} - */ - var nextPoint = function (point, isSkipInnerOffset) { - var node, offset; - - if (nodeLength(point.node) === point.offset) { - if (isEditable(point.node)) { - return null; - } - - node = point.node.parentNode; - offset = position(point.node) + 1; - } else if (hasChildren(point.node)) { - node = point.node.childNodes[point.offset]; - offset = 0; - } else { - node = point.node; - offset = isSkipInnerOffset ? nodeLength(point.node) : point.offset + 1; - } - - return { - node: node, - offset: offset - }; - }; - - /** - * returns whether pointA and pointB is same or not. - * - * @param {BoundaryPoint} pointA - * @param {BoundaryPoint} pointB - * @return {Boolean} - */ - var isSamePoint = function (pointA, pointB) { - return pointA.node === pointB.node && pointA.offset === pointB.offset; - }; - - /** - * returns whether point is visible (can set cursor) or not. - * - * @param {BoundaryPoint} point - * @return {Boolean} - */ - var isVisiblePoint = function (point) { - if (isText(point.node) || !hasChildren(point.node) || isEmpty(point.node)) { - return true; - } - - var leftNode = point.node.childNodes[point.offset - 1]; - var rightNode = point.node.childNodes[point.offset]; - if ((!leftNode || isVoid(leftNode)) && (!rightNode || isVoid(rightNode))) { - return true; - } - - return false; - }; - - /** - * @method prevPointUtil - * - * @param {BoundaryPoint} point - * @param {Function} pred - * @return {BoundaryPoint} - */ - var prevPointUntil = function (point, pred) { - while (point) { - if (pred(point)) { - return point; - } - - point = prevPoint(point); - } - - return null; - }; - - /** - * @method nextPointUntil - * - * @param {BoundaryPoint} point - * @param {Function} pred - * @return {BoundaryPoint} - */ - var nextPointUntil = function (point, pred) { - while (point) { - if (pred(point)) { - return point; - } - - point = nextPoint(point); - } - - return null; - }; - - /** - * 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 - * - * @param {BoundaryPoint} startPoint - * @param {BoundaryPoint} endPoint - * @param {Function} handler - * @param {Boolean} isSkipInnerOffset - */ - var walkPoint = function (startPoint, endPoint, handler, isSkipInnerOffset) { - var point = startPoint; - - while (point) { - handler(point); - - if (isSamePoint(point, endPoint)) { - break; - } - - var isSkipOffset = isSkipInnerOffset && - startPoint.node !== point.node && - endPoint.node !== point.node; - point = nextPoint(point, isSkipOffset); - } - }; - - /** - * @method makeOffsetPath - * - * return offsetPath(array of offset) from ancestor - * - * @param {Node} ancestor - ancestor node - * @param {Node} node - */ - var makeOffsetPath = function (ancestor, node) { - var ancestors = listAncestor(node, func.eq(ancestor)); - return ancestors.map(position).reverse(); - }; - - /** - * @method fromOffsetPath - * - * return element from offsetPath(array of offset) - * - * @param {Node} ancestor - ancestor node - * @param {array} offsets - offsetPath - */ - var fromOffsetPath = function (ancestor, offsets) { - var current = ancestor; - for (var i = 0, len = offsets.length; i < len; i++) { - if (current.childNodes.length <= offsets[i]) { - current = current.childNodes[current.childNodes.length - 1]; - } else { - current = current.childNodes[offsets[i]]; - } - } - return current; - }; - - /** - * @method splitNode - * - * split element or #text - * - * @param {BoundaryPoint} point - * @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, options) { - var isSkipPaddingBlankHTML = options && options.isSkipPaddingBlankHTML; - var isNotSplitEdgePoint = options && options.isNotSplitEdgePoint; - - // edge case - if (isEdgePoint(point) && (isText(point.node) || isNotSplitEdgePoint)) { - if (isLeftEdgePoint(point)) { - return point.node; - } else if (isRightEdgePoint(point)) { - return point.node.nextSibling; - } - } - - // 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)); - - if (!isSkipPaddingBlankHTML) { - paddingBlankHTML(point.node); - paddingBlankHTML(clone); - } - - return clone; - } - }; - - /** - * @method splitTree - * - * split tree by point - * - * @param {Node} root - split root - * @param {BoundaryPoint} point - * @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, options) { - // ex) [#text, ,] - var ancestors = listAncestor(point.node, func.eq(root)); - - if (!ancestors.length) { - return null; - } else if (ancestors.length === 1) { - return splitNode(point, options); - } - - return ancestors.reduce(function (node, parent) { - if (node === point.node) { - node = splitNode(point, options); - } - - return splitNode({ - node: parent, - offset: node ? dom.position(node) : nodeLength(parent) - }, options); - }); - }; - - /** - * split point - * - * @param {Point} point - * @param {Boolean} isInline - * @return {Object} - */ - var splitPoint = function (point, isInline) { - // find splitRoot, container - // - inline: splitRoot is a child of paragraph - // - block: splitRoot is a child of bodyContainer - var pred = isInline ? isPara : isBodyContainer; - var ancestors = listAncestor(point.node, pred); - var topAncestor = list.last(ancestors) || point.node; - - var splitRoot, container; - if (pred(topAncestor)) { - splitRoot = ancestors[ancestors.length - 2]; - container = topAncestor; - } else { - splitRoot = topAncestor; - container = splitRoot.parentNode; - } - - // 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 { - rightNode: pivot, - container: container - }; - }; - - var create = function (nodeName) { - return document.createElement(nodeName); - }; - - var createText = function (text) { - return document.createTextNode(text); - }; - - /** - * @method remove - * - * remove node, (isRemoveChild: remove child or not) - * - * @param {Node} node - * @param {Boolean} isRemoveChild - */ - var remove = function (node, isRemoveChild) { - if (!node || !node.parentNode) { return; } - if (node.removeNode) { return node.removeNode(isRemoveChild); } - - var parent = node.parentNode; - if (!isRemoveChild) { - var nodes = []; - var i, len; - for (i = 0, len = node.childNodes.length; i < len; i++) { - nodes.push(node.childNodes[i]); - } - - for (i = 0, len = nodes.length; i < len; i++) { - parent.insertBefore(nodes[i], node); - } - } - - parent.removeChild(node); - }; - - /** - * @method removeWhile - * - * @param {Node} node - * @param {Function} pred - */ - var removeWhile = function (node, pred) { - while (node) { - if (isEditable(node) || !pred(node)) { - break; - } - - var parent = node.parentNode; - remove(node); - node = parent; - } - }; - - /** - * @method replace - * - * replace node with provided nodeName - * - * @param {Node} node - * @param {String} nodeName - * @return {Node} - new node - */ - var replace = function (node, nodeName) { - if (node.nodeName.toUpperCase() === nodeName.toUpperCase()) { - return node; - } - - var newNode = create(nodeName); - - if (node.style.cssText) { - newNode.style.cssText = node.style.cssText; - } - - appendChildNodes(newNode, list.from(node.childNodes)); - insertAfter(newNode, node); - remove(node); - - return newNode; - }; - - var isTextarea = makePredByNodeName('TEXTAREA'); - - /** - * @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 - * - * get the HTML contents of node - * - * @param {jQuery} $node - * @param {Boolean} [isNewlineOnBlock] - */ - var html = function ($node, isNewlineOnBlock) { - var markup = value($node); - - if (isNewlineOnBlock) { - var regexTag = /<(\/?)(\b(?!!)[^>\s]*)(.*?)(\s*\/?>)/g; - markup = markup.replace(regexTag, function (match, endSlash, name) { - name = name.toUpperCase(); - var isEndOfInlineContainer = /^DIV|^TD|^TH|^P|^LI|^H[1-7]/.test(name) && - !!endSlash; - var isBlockNode = /^BLOCKQUOTE|^TABLE|^TBODY|^TR|^HR|^UL|^OL/.test(name); - - return match + ((isEndOfInlineContainer || isBlockNode) ? '\n' : ''); - }); - markup = $.trim(markup); - } - - return markup; - }; - - var posFromPlaceholder = function (placeholder) { - var $placeholder = $(placeholder); - var pos = $placeholder.offset(); - var height = $placeholder.outerHeight(true); // include margin - - return { - left: pos.left, - top: pos.top + height - }; - }; - - var attachEvents = function ($node, events) { - Object.keys(events).forEach(function (key) { - $node.on(key, events[key]); - }); - }; - - var detachEvents = function ($node, events) { - Object.keys(events).forEach(function (key) { - $node.off(key, events[key]); - }); - }; - - return { - /** @property {String} NBSP_CHAR */ - NBSP_CHAR: NBSP_CHAR, - /** @property {String} ZERO_WIDTH_NBSP_CHAR */ - ZERO_WIDTH_NBSP_CHAR: ZERO_WIDTH_NBSP_CHAR, - /** @property {String} blank */ - blank: blankHTML, - /** @property {String} emptyPara */ - emptyPara: '
' + blankHTML + '', - // emptyPara: '' + blankHTML + '
', - makePredByNodeName: makePredByNodeName, - isEditable: isEditable, - isControlSizing: isControlSizing, - isText: isText, - isElement: isElement, - isVoid: isVoid, - isPara: isPara, - isPurePara: isPurePara, - isHeading: isHeading, - isInline: isInline, - isBlock: func.not(isInline), - isBodyInline: isBodyInline, - isBody: isBody, - isParaInline: isParaInline, - isPre: isPre, - isList: isList, - isTable: isTable, - isData: isData, - isCell: isCell, - isBlockquote: isBlockquote, - isBodyContainer: isBodyContainer, - isAnchor: isAnchor, - isDiv: makePredByNodeName('DIV'), - isLi: isLi, - isBR: makePredByNodeName('BR'), - isSpan: makePredByNodeName('SPAN'), - isB: makePredByNodeName('B'), - isU: makePredByNodeName('U'), - isS: makePredByNodeName('S'), - isI: makePredByNodeName('I'), - isImg: makePredByNodeName('IMG'), - isTextarea: isTextarea, - isEmpty: isEmpty, - isEmptyAnchor: func.and(isAnchor, isEmpty), - isClosestSibling: isClosestSibling, - withClosestSiblings: withClosestSiblings, - nodeLength: nodeLength, - isLeftEdgePoint: isLeftEdgePoint, - isRightEdgePoint: isRightEdgePoint, - isEdgePoint: isEdgePoint, - isLeftEdgeOf: isLeftEdgeOf, - isRightEdgeOf: isRightEdgeOf, - isLeftEdgePointOf: isLeftEdgePointOf, - isRightEdgePointOf: isRightEdgePointOf, - prevPoint: prevPoint, - nextPoint: nextPoint, - isSamePoint: isSamePoint, - isVisiblePoint: isVisiblePoint, - prevPointUntil: prevPointUntil, - nextPointUntil: nextPointUntil, - isCharPoint: isCharPoint, - walkPoint: walkPoint, - ancestor: ancestor, - singleChildAncestor: singleChildAncestor, - listAncestor: listAncestor, - lastAncestor: lastAncestor, - listNext: listNext, - listPrev: listPrev, - listDescendant: listDescendant, - commonAncestor: commonAncestor, - wrap: wrap, - insertAfter: insertAfter, - appendChildNodes: appendChildNodes, - position: position, - hasChildren: hasChildren, - makeOffsetPath: makeOffsetPath, - fromOffsetPath: fromOffsetPath, - splitTree: splitTree, - splitPoint: splitPoint, - create: create, - createText: createText, - remove: remove, - removeWhile: removeWhile, - replace: replace, - html: html, - value: value, - posFromPlaceholder: posFromPlaceholder, - attachEvents: attachEvents, - detachEvents: detachEvents - }; - })(); - - /** - * @param {jQuery} $note - * @param {Object} options - * @return {Context} - */ - var Context = function ($note, options) { - var self = this; - - var ui = $.summernote.ui; - this.memos = {}; - this.modules = {}; - this.layoutInfo = {}; - this.options = options; - - /** - * create layout and initialize modules and other resources - */ - this.initialize = function () { - this.layoutInfo = ui.createLayout($note, options); - this._initialize(); - $note.hide(); - return this; - }; - - /** - * destroy modules and other resources and remove layout - */ - this.destroy = function () { - this._destroy(); - $note.removeData('summernote'); - ui.removeLayout($note, this.layoutInfo); - }; - - /** - * destory modules and other resources and initialize it again - */ - this.reset = function () { - var disabled = self.isDisabled(); - this.code(dom.emptyPara); - this._destroy(); - this._initialize(); - - if (disabled) { - self.disable(); - } - }; - - this._initialize = function () { - // add optional buttons - var buttons = $.extend({}, this.options.buttons); - Object.keys(buttons).forEach(function (key) { - self.memo('button.' + key, buttons[key]); - }); - - var modules = $.extend({}, this.options.modules, $.summernote.plugins || {}); - - // add and initialize modules - Object.keys(modules).forEach(function (key) { - self.module(key, modules[key], true); - }); - - Object.keys(this.modules).forEach(function (key) { - self.initializeModule(key); - }); - }; - - this._destroy = function () { - // destroy modules with reversed order - Object.keys(this.modules).reverse().forEach(function (key) { - self.removeModule(key); - }); - - Object.keys(this.memos).forEach(function (key) { - self.removeMemo(key); - }); - }; - - this.code = function (html) { - var isActivated = this.invoke('codeview.isActivated'); - - if (html === undefined) { - this.invoke('codeview.sync'); - return isActivated ? this.layoutInfo.codable.val() : this.layoutInfo.editable.html(); - } else { - if (isActivated) { - this.layoutInfo.codable.val(html); - } else { - this.layoutInfo.editable.html(html); - } - $note.val(html); - this.triggerEvent('change', html); - } - }; - - this.isDisabled = function () { - return this.layoutInfo.editable.attr('contenteditable') === 'false'; - }; - - this.enable = function () { - this.layoutInfo.editable.attr('contenteditable', true); - this.invoke('toolbar.activate', true); - }; - - this.disable = function () { - // close codeview if codeview is opend - if (this.invoke('codeview.isActivated')) { - this.invoke('codeview.deactivate'); - } - this.layoutInfo.editable.attr('contenteditable', false); - this.invoke('toolbar.deactivate', true); - }; - - this.triggerEvent = function () { - var namespace = list.head(arguments); - var args = list.tail(list.from(arguments)); - - var callback = this.options.callbacks[func.namespaceToCamel(namespace, 'on')]; - if (callback) { - callback.apply($note[0], args); - } - $note.trigger('summernote.' + namespace, args); - }; - - this.initializeModule = function (key) { - var module = this.modules[key]; - module.shouldInitialize = module.shouldInitialize || func.ok; - if (!module.shouldInitialize()) { - return; - } - - // initialize module - if (module.initialize) { - module.initialize(); - } - - // attach events - if (module.events) { - dom.attachEvents($note, module.events); - } - }; - - this.module = function (key, ModuleClass, withoutIntialize) { - if (arguments.length === 1) { - return this.modules[key]; - } - - this.modules[key] = new ModuleClass(this); - - if (!withoutIntialize) { - this.initializeModule(key); - } - }; - - this.removeModule = function (key) { - var module = this.modules[key]; - if (module.shouldInitialize()) { - if (module.events) { - dom.detachEvents($note, module.events); - } - - if (module.destroy) { - module.destroy(); - } - } - - delete this.modules[key]; - }; - - this.memo = function (key, obj) { - if (arguments.length === 1) { - return this.memos[key]; - } - this.memos[key] = obj; - }; - - this.removeMemo = function (key) { - if (this.memos[key] && this.memos[key].destroy) { - this.memos[key].destroy(); - } - - delete this.memos[key]; - }; - - this.createInvokeHandler = function (namespace, value) { - return function (event) { - event.preventDefault(); - self.invoke(namespace, value || $(event.target).closest('[data-value]').data('value')); - }; - }; - - this.invoke = function () { - var namespace = list.head(arguments); - var args = list.tail(list.from(arguments)); - - var splits = namespace.split('.'); - var hasSeparator = splits.length > 1; - var moduleName = hasSeparator && list.head(splits); - var methodName = hasSeparator ? list.last(splits) : list.head(splits); - - var module = this.modules[moduleName || 'editor']; - if (!moduleName && this[methodName]) { - return this[methodName].apply(this, args); - } else if (module && module[methodName] && module.shouldInitialize()) { - return module[methodName].apply(module, args); - } - }; - - return this.initialize(); - }; - - $.fn.extend({ - /** - * Summernote API - * - * @param {Object|String} - * @return {this} - */ - summernote: function () { - var type = $.type(list.head(arguments)); - var isExternalAPICalled = type === 'string'; - var hasInitOptions = type === 'object'; - - var options = hasInitOptions ? list.head(arguments) : {}; - - options = $.extend({}, $.summernote.options, options); - options.langInfo = $.extend(true, {}, $.summernote.lang['en-US'], $.summernote.lang[options.lang]); - options.icons = $.extend(true, {}, $.summernote.options.icons, options.icons); - - this.each(function (idx, note) { - var $note = $(note); - if (!$note.data('summernote')) { - var context = new Context($note, options); - $note.data('summernote', context); - $note.data('summernote').triggerEvent('init', context.layoutInfo); - } - }); - - var $note = this.first(); - if ($note.length) { - var context = $note.data('summernote'); - if (isExternalAPICalled) { - return context.invoke.apply(context, list.from(arguments)); - } else if (options.focus) { - context.invoke('editor.focus'); - } - } - - return this; - } - }); - - - var Renderer = function (markup, children, options, callback) { - this.render = function ($parent) { - var $node = $(markup); - - if (options && options.contents) { - $node.html(options.contents); - } - - if (options && options.className) { - $node.addClass(options.className); - } - - if (options && options.data) { - $.each(options.data, function (k, v) { - $node.attr('data-' + k, v); - }); - } - - if (options && options.click) { - $node.on('click', options.click); - } - - if (children) { - var $container = $node.find('.note-children-container'); - children.forEach(function (child) { - child.render($container.length ? $container : $node); - }); - } - - if (callback) { - callback($node, options); - } - - if (options && options.callback) { - options.callback($node); - } - - if ($parent) { - $parent.append($node); - } - - return $node; - }; - }; - - var renderer = { - create: function (markup, callback) { - return function () { - var children = $.isArray(arguments[0]) ? arguments[0] : []; - var options = typeof arguments[1] === 'object' ? arguments[1] : arguments[0]; - if (options && options.children) { - children = options.children; - } - return new Renderer(markup, children, options, callback); - }; - } - }; - - var editor = renderer.create(''); - var toolbar = renderer.create(''); - var editingArea = renderer.create(''); - var codable = renderer.create(''); - var editable = renderer.create(''); - var statusbar = renderer.create([ - '', - '' - ].join('')); - - var airEditor = renderer.create(''); - var airEditable = renderer.create(''); - - var buttonGroup = renderer.create('', - ' ', - ' ', - ' ', - '', - ''); - var button = renderer.create('