From 0aa0b7a3125c93abf40d039eb5d87d6d10ee0474 Mon Sep 17 00:00:00 2001 From: Oscar Godson Date: Sat, 16 Jun 2012 22:29:40 -0700 Subject: [PATCH] Ticket #102 - Fixed bug where filename would be [object HTMLDivElement] if the element didnt have an ID and no file name was given. Also added unloads where applicable in the spec which sped up the tests. --- epiceditor/js/epiceditor.js | 54 +++++++++++---- epiceditor/js/epiceditor.min.js | 2 +- spec/spec.js | 116 +++++++++++++++++++++++++++----- src/editor.js | 54 +++++++++++---- 4 files changed, 184 insertions(+), 42 deletions(-) diff --git a/epiceditor/js/epiceditor.js b/epiceditor/js/epiceditor.js index 983b648..ef010d2 100644 --- a/epiceditor/js/epiceditor.js +++ b/epiceditor/js/epiceditor.js @@ -280,8 +280,8 @@ , defaults = { container: 'epiceditor' , basePath: 'epiceditor' , localStorageName: 'epiceditor' - , file: { name: opts.container || 'epiceditor' // Use the container's ID for an unique persistent file name - will be overwritten if passed a file.name opt - , defaultContent: '' + , file: { name: null + , defaultContent: '' , autoSave: 100 // Set to false for no auto saving } , theme: { base: '/themes/base/epiceditor.css' @@ -306,9 +306,41 @@ } } + + // Grab the container element and save it to self.element + // if it's a string assume it's an ID and if it's an object + // assume it's a DOM element + if (typeof self.settings.container == 'string') { + self.element = document.getElementById(self.settings.container); + } + else if (typeof self.settings.container == 'object') { + self.element = self.settings.container; + } + + // Figure out the file name. If no file name is given we'll use the ID. + // If there's no ID either we'll use a namespaced file name that's incremented + // based on the calling order. As long as it doesn't change, drafts will be saved. + if (!self.settings.file.name) { + if (typeof self.settings.container == 'string') { + self.settings.file.name = self.settings.container; + } + else if (typeof self.settings.container == 'object') { + if (self.element.id) { + self.settings.file.name = self.element.id; + } + else { + if (!EpicEditor._data.unnamedEditors) { + EpicEditor._data.unnamedEditors = []; + } + EpicEditor._data.unnamedEditors.push(self); + self.settings.file.name = '__epiceditor-untitled-' + EpicEditor._data.unnamedEditors.length; + } + } + } + // Protect the id and overwrite if passed in as an option // TODO: Put underscrore to denote that this is private - self.instanceId = 'epiceditor-' + Math.round(Math.random() * 100000); + self._instanceId = 'epiceditor-' + Math.round(Math.random() * 100000); self._canSave = true; @@ -343,13 +375,6 @@ self.events = {}; } - if (typeof self.settings.container == 'string') { - self.element = document.getElementById(self.settings.container); - } - else if (typeof self.settings.container == 'object') { - self.element = self.settings.container; - } - return this; } @@ -428,8 +453,8 @@ } } // Write an iframe and then select it for the editor - self.element.innerHTML = ''; - iframeElement = document.getElementById(self.instanceId); + self.element.innerHTML = ''; + iframeElement = document.getElementById(self._instanceId); // Store a reference to the iframeElement itself self.iframeElement = iframeElement; @@ -839,7 +864,7 @@ } var self = this - , editor = window.parent.document.getElementById(self.instanceId); + , editor = window.parent.document.getElementById(self._instanceId); editor.parentNode.removeChild(editor); self.eeState.loaded = false; @@ -1173,6 +1198,9 @@ EpicEditor.version = '0.1.0'; + // Used to store information to be shared acrossed editors + EpicEditor._data = {}; + window.EpicEditor = EpicEditor; })(window); diff --git a/epiceditor/js/epiceditor.min.js b/epiceditor/js/epiceditor.min.js index 547c01e..37432a2 100644 --- a/epiceditor/js/epiceditor.min.js +++ b/epiceditor/js/epiceditor.min.js @@ -1,4 +1,4 @@ /** * EpicEditor - An Embeddable JavaScript Markdown Editor (https://github.com/OscarGodson/EpicEditor) * Copyright (c) 2011-2012, Oscar Godson. (MIT Licensed) - */(function(a,b){function c(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c])}function d(a,b){for(var c in b)b.hasOwnProperty(c)&&(a.style[c]=b[c])}function e(b,c){var d=b,e=null;return a.getComputedStyle?e=document.defaultView.getComputedStyle(d,null).getPropertyValue(c):d.currentStyle&&(e=d.currentStyle[c]),e}function f(a,b,c){var f={},g;if(b==="save"){for(g in c)c.hasOwnProperty(g)&&(f[g]=e(a,g));d(a,c)}else b==="apply"&&d(a,c);return f}function g(a){var b=parseInt(e(a,"border-left-width"),10)+parseInt(e(a,"border-right-width"),10),c=parseInt(e(a,"padding-left"),10)+parseInt(e(a,"padding-right"),10),d=a.offsetWidth,f;return isNaN(b)&&(b=0),f=b+c+d,f}function h(a){var b=parseInt(e(a,"border-top-width"),10)+parseInt(e(a,"border-bottom-width"),10),c=parseInt(e(a,"padding-top"),10)+parseInt(e(a,"padding-bottom"),10),d=a.offsetHeight,f;return isNaN(b)&&(b=0),f=b+c+d,f}function i(a,b,d){d=d||"";var e=b.getElementsByTagName("head")[0],f=b.createElement("link");c(f,{type:"text/css",id:d,rel:"stylesheet",href:a,name:a,media:"screen"}),e.appendChild(f)}function j(a,b,c){a.className=a.className.replace(b,c)}function k(a){return a.contentDocument||a.contentWindow.document}function l(a){var b;return document.body.innerText?b=a.innerText:(b=a.innerHTML.replace(/
/gi,"\n"),b=b.replace(/<(?:.|\n)*?>/gm,""),b=b.replace(/</gi,"<"),b=b.replace(/>/gi,">")),b}function m(a,b){return document.body.innerText?a.innerText=b:a.innerHTML=b.replace(/\n/g,"
"),!0}function n(){var a=-1,b=navigator.userAgent,c;return navigator.appName=="Microsoft Internet Explorer"&&(c=/MSIE ([0-9]{1,}[\.0-9]{0,})/,c.exec(b)!=null&&(a=parseFloat(RegExp.$1,10))),a}function o(a){var b={};return a&&b.toString.call(a)==="[object Function]"}function p(){var a=arguments[0]||{},c=1,d=arguments.length,e=!1,f,g,h,i;typeof a=="boolean"&&(e=a,a=arguments[1]||{},c=2),typeof a!="object"&&!o(a)&&(a={}),d===c&&(a=this,--c);for(;c=5||Math.abs(u.x-b.pageX)>=5)r.style.display="block",s&&clearTimeout(s),s=a.setTimeout(function(){r.style.display="none"},1e3);u={y:b.pageY,x:b.pageX}}function J(a){a.keyCode==c.settings.shortcut.modifier&&(C=!0),a.keyCode==17&&(D=!0),C===!0&&a.keyCode==c.settings.shortcut.preview&&!c.eeState.fullscreen&&(a.preventDefault(),c.preview(),c.previewerIframe.focus()),C===!0&&a.keyCode==c.settings.shortcut.edit&&(a.preventDefault(),c.eeState.fullscreen||(c.edit(),c.editorIframe.focus())),C===!0&&a.keyCode==c.settings.shortcut.fullscreen&&(a.preventDefault(),y(B)),a.keyCode==27&&c.eeState.fullscreen&&(document.body.webkitRequestFullScreen||z(B)),D===!0&&a.keyCode==83&&(c.save(),a.preventDefault()),a.metaKey&&a.keyCode==83&&(c.save(),a.preventDefault())}function K(a){a.keyCode==c.settings.shortcut.modifier&&(C=!1),a.keyCode==17&&(D=!1)}var c=this,j,l,m,o,p,q,r,s,t,u={y:-1,x:-1},v,w,x=document.body.webkitRequestFullScreen?!0:!1,y,z,A,B,C=!1,D=!1,E,F;b=b||function(){},c.eeState={fullscreen:!1,preview:!1,edit:!0,loaded:!1,unloaded:!1},j={chrome:'
'+' '+''+"
"+"
",previewer:'
'},c.element.innerHTML='',l=document.getElementById(c.instanceId),c.iframeElement=l,c.iframe=k(l),c.iframe.open(),c.iframe.write(j.chrome),c.editorIframe=c.iframe.getElementById("epiceditor-editor-frame"),c.previewerIframe=c.iframe.getElementById("epiceditor-previewer-frame"),c.editorIframeDocument=k(c.editorIframe),c.editorIframeDocument.open(),c.editorIframeDocument.write(""),c.editorIframeDocument.close(),c.previewerIframeDocument=k(c.previewerIframe),c.previewerIframeDocument.open(),c.previewerIframeDocument.write(j.previewer),m=c.previewerIframeDocument.createElement("base"),m.target="_blank",c.previewerIframeDocument.getElementsByTagName("head")[0].appendChild(m),c.previewerIframeDocument.close(),o=g(c.element)-c.element.offsetWidth,p=h(c.element)-c.element.offsetHeight,A=[c.iframeElement,c.editorIframe,c.previewerIframe],G(A),i(c.settings.basePath+c.settings.theme.base,c.iframe),i(c.settings.basePath+c.settings.theme.editor,c.editorIframeDocument),i(c.settings.basePath+c.settings.theme.preview,c.previewerIframeDocument),c.iframe.getElementById("epiceditor-wrapper").style.position="relative",c.editor=c.editorIframeDocument.body,c.previewer=c.previewerIframeDocument.getElementById("epiceditor-preview"),c.editor.contentEditable=!0,c.iframe.body.style.height=this.element.offsetHeight+"px",this.previewerIframe.style.display="none",n()>-1&&(this.previewer.style.height=parseInt(e(this.previewer,"height"),10)+2),i(c.settings.basePath+c.settings.theme.preview,c.previewerIframeDocument,"theme"),this.open(c.settings.file.name),c.settings.focusOnLoad&&c.iframe.addEventListener("readystatechange",function(){c.iframe.readyState=="complete"&&c.editorIframeDocument.body.focus()}),q=c.iframe.getElementById("epiceditor-utilbar"),v={},y=function(b){if(c.eeState.fullscreen){z(b);return}x&&b.webkitRequestFullScreen(),w=c.eeState.edit,c.eeState.fullscreen=!0,c.eeState.edit=!0,c.eeState.preview=!0;var d=a.innerWidth,g=a.innerHeight,h=a.outerWidth,i=a.outerHeight;x||(i=a.innerHeight),v.editorIframe=f(c.editorIframe,"save",{width:h/2+"px",height:i+"px","float":"left",cssFloat:"left",styleFloat:"left",display:"block"}),v.previewerIframe=f(c.previewerIframe,"save",{width:h/2+"px",height:i+"px","float":"right",cssFloat:"right",styleFloat:"right",display:"block"}),v.element=f(c.element,"save",{position:"fixed",top:"0",left:"0",width:"100%","z-index":"9999",zIndex:"9999",border:"none",margin:"0",background:e(c.editor,"background-color"),height:g+"px"}),v.iframeElement=f(c.iframeElement,"save",{width:h+"px",height:g+"px"}),q.style.visibility="hidden",x||(document.body.style.overflow="hidden"),c.preview(),c.editorIframeDocument.body.focus()},z=function(a){f(c.element,"apply",v.element),f(c.iframeElement,"apply",v.iframeElement),f(c.editorIframe,"apply",v.editorIframe),f(c.previewerIframe,"apply",v.previewerIframe),c.element.style.width="",c.element.style.height="",q.style.visibility="visible",x?document.webkitCancelFullScreen():document.body.style.overflow="auto",c.eeState.fullscreen=!1,w?c.edit():c.preview(),H(A)},c.editor.addEventListener("keyup",function(){t&&a.clearTimeout(t),t=a.setTimeout(function(){c.eeState.fullscreen&&c.preview()},250)}),B=c.iframeElement,q.addEventListener("click",function(a){var b=a.target.className;b.indexOf("epiceditor-toggle-preview-btn")>-1?c.preview():b.indexOf("epiceditor-toggle-edit-btn")>-1?c.edit():b.indexOf("epiceditor-fullscreen-btn")>-1&&y(B)}),document.body.webkitRequestFullScreen&&B.addEventListener("webkitfullscreenchange",function(){document.webkitIsFullScreen||z(B)},!1),r=c.iframe.getElementById("epiceditor-utilbar"),r.style.display="none",r.addEventListener("mouseover",function(){s&&clearTimeout(s)}),E=[c.previewerIframeDocument,c.editorIframeDocument];for(F=0;F"+b.lexer(a[1])+"":''+j(a[1])+'"}function f(){return e=d.pop()}function g(){switch(e.type){case"space":return"";case"hr":return"
\n";case"heading":return""+b.lexer(e.text)+"\n";case"code":return p.highlight&&(e.code=p.highlight(e.text,e.lang),e.code!=null&&e.code!==e.text&&(e.escaped=!0,e.text=e.code)),e.escaped||(e.text=j(e.text,!0)),"
"+e.text+"
\n";case"blockquote_start":var a="";while(f().type!=="blockquote_end")a+=g();return"
\n"+a+"
\n";case"list_start":var c=e.ordered?"ol":"ul",a="";while(f().type!=="list_end")a+=g();return"<"+c+">\n"+a+"\n";case"list_item_start":var a="";while(f().type!=="list_item_end")a+=e.type==="text"?h():g();return"
  • "+a+"
  • \n";case"loose_item_start":var a="";while(f().type!=="list_item_end")a+=g();return"
  • "+a+"
  • \n";case"html":return p.sanitize?b.lexer(e.text):!e.pre&&!p.pedantic?b.lexer(e.text):e.text;case"paragraph":return"

    "+b.lexer(e.text)+"

    \n";case"text":return"

    "+h()+"

    \n"}}function h(){var a=e.text,c;while((c=d[d.length-1])&&c.type==="text")a+="\n"+f().text;return b.lexer(a)}function i(a){d=a.reverse();var b="";while(f())b+=g();return d=null,e=null,b}function j(a,b){return a.replace(b?/&/g:/&(?!#?\w+;)/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function k(a){var b="",c=a.length,d=0,e;for(;d.5&&(e="x"+e.toString(16)),b+="&#"+e+";";return b}function l(){var a="(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+";return a}function m(a,b){return a=a.source,b=b||"",function c(d,e){return d?(a=a.replace(d,e.source||e),c):new RegExp(a,b)}}function n(){}function o(b,c){return r(c),i(a.lexer(b))}function r(c){c||(c=q);if(p===c)return;p=c,p.gfm?(a.fences=a.gfm.fences,a.paragraph=a.gfm.paragraph,b.text=b.gfm.text,b.url=b.gfm.url):(a.fences=a.normal.fences,a.paragraph=a.normal.paragraph,b.text=b.normal.text,b.url=b.normal.url),p.pedantic?(b.em=b.pedantic.em,b.strong=b.pedantic.strong):(b.em=b.normal.em,b.strong=b.normal.strong)}var a={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:n,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,lheading:/^([^\n]+)\n *(=|-){3,} *\n*/,blockquote:/^( *>[^\n]+(\n[^\n]+)*\n*)+/,list:/^( *)(bull) [^\0]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,def:/^ *\[([^\]]+)\]: *([^\s]+)(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,paragraph:/^([^\n]+\n?(?!body))+\n*/,text:/^[^\n]+/};a.bullet=/(?:[*+-]|\d+\.)/,a.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/,a.item=m(a.item,"gm")(/bull/g,a.bullet)(),a.list=m(a.list)(/bull/g,a.bullet)("hr",/\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/)(),a.html=m(a.html)("comment",//)("closed",/<(tag)[^\0]+?<\/\1>/)("closing",/])*?>/)(/tag/g,l())(),a.paragraph=function(){var b=a.paragraph.source,c=[];return function d(b){return b=a[b]?a[b].source:b,c.push(b.replace(/(^|[^\[])\^/g,"$1")),d}("hr")("heading")("lheading")("blockquote")("<"+l())("def"),new RegExp(b.replace("body",c.join("|")))}(),a.normal={fences:a.fences,paragraph:a.paragraph},a.gfm={fences:/^ *``` *(\w+)? *\n([^\0]+?)\s*``` *(?:\n+|$)/,paragraph:/^/},a.gfm.paragraph=m(a.paragraph)("(?!","(?!"+a.gfm.fences.source.replace(/(^|[^\[])\^/g,"$1")+"|")(),a.lexer=function(b){var c=[];return c.links={},b=b.replace(/\r\n|\r/g,"\n").replace(/\t/g," "),a.token(b,c,!0)},a.token=function(b,c,d){var b=b.replace(/^ +$/gm,""),e,f,g,h,i,j,k;while(b){if(g=a.newline.exec(b))b=b.substring(g[0].length),g[0].length>1&&c.push({type:"space"});if(g=a.code.exec(b)){b=b.substring(g[0].length),g=g[0].replace(/^ {4}/gm,""),c.push({type:"code",text:p.pedantic?g:g.replace(/\n+$/,"")});continue}if(g=a.fences.exec(b)){b=b.substring(g[0].length),c.push({type:"code",lang:g[1],text:g[2]});continue}if(g=a.heading.exec(b)){b=b.substring(g[0].length),c.push({type:"heading",depth:g[1].length,text:g[2]});continue}if(g=a.lheading.exec(b)){b=b.substring(g[0].length),c.push({type:"heading",depth:g[2]==="="?1:2,text:g[1]});continue}if(g=a.hr.exec(b)){b=b.substring(g[0].length),c.push({type:"hr"});continue}if(g=a.blockquote.exec(b)){b=b.substring(g[0].length),c.push({type:"blockquote_start"}),g=g[0].replace(/^ *> ?/gm,""),a.token(g,c,d),c.push({type:"blockquote_end"});continue}if(g=a.list.exec(b)){b=b.substring(g[0].length),c.push({type:"list_start",ordered:isFinite(g[2])}),g=g[0].match(a.item),e=!1,k=g.length,j=0;for(;j])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:n,tag:/^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([^\0]+?)__(?!_)|^\*\*([^\0]+?)\*\*(?!\*)/,em:/^\b_((?:__|[^\0])+?)_\b|^\*((?:\*\*|[^\0])+?)\*(?!\*)/,code:/^(`+)([^\0]*?[^`])\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,text:/^[^\0]+?(?=[\\?(?:\s+['"]([^\0]*?)['"])?\s*/,b.link=m(b.link)("inside",b._linkInside)("href",b._linkHref)(),b.reflink=m(b.reflink)("inside",b._linkInside)(),b.normal={url:b.url,strong:b.strong,em:b.em,text:b.text},b.pedantic={strong:/^__(?=\S)([^\0]*?\S)__(?!_)|^\*\*(?=\S)([^\0]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([^\0]*?\S)_(?!_)|^\*(?=\S)([^\0]*?\S)\*(?!\*)/},b.gfm={url:/^(https?:\/\/[^\s]+[^.,:;"')\]\s])/,text:/^[^\0]+?(?=[\\'+h+"";continue}if(l=b.url.exec(a)){a=a.substring(l[0].length),h=j(l[1]),i=h,e+=''+h+"";continue}if(l=b.tag.exec(a)){a=a.substring(l[0].length),e+=p.sanitize?j(l[0]):l[0];continue}if(l=b.link.exec(a)){a=a.substring(l[0].length),e+=c(l,{href:l[2],title:l[3]});continue}if((l=b.reflink.exec(a))||(l=b.nolink.exec(a))){a=a.substring(l[0].length),g=(l[2]||l[1]).replace(/\s+/g," "),g=f[g.toLowerCase()];if(!g||!g.href){e+=l[0][0],a=l[0].substring(1)+a;continue}e+=c(l,g);continue}if(l=b.strong.exec(a)){a=a.substring(l[0].length),e+=""+b.lexer(l[2]||l[1])+"";continue}if(l=b.em.exec(a)){a=a.substring(l[0].length),e+=""+b.lexer(l[2]||l[1])+"";continue}if(l=b.code.exec(a)){a=a.substring(l[0].length),e+=""+j(l[2],!0)+"";continue}if(l=b.br.exec(a)){a=a.substring(l[0].length),e+="
    ";continue}if(l=b.text.exec(a)){a=a.substring(l[0].length),e+=j(l[0]);continue}}return e};var d,e;n.exec=n;var p,q;o.options=o.setOptions=function(a){return q=a,r(a),o},o.setOptions({gfm:!0,pedantic:!1,sanitize:!1,highlight:null}),o.parser=function(a,b){return r(b),i(a)},o.lexer=function(b,c){return r(c),a.lexer(b)},o.parse=o,typeof module!="undefined"?module.exports=o:this.marked=o}.call(function(){return this||(typeof window!="undefined"?window:global)}()); \ No newline at end of file + */(function(a,b){function c(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c])}function d(a,b){for(var c in b)b.hasOwnProperty(c)&&(a.style[c]=b[c])}function e(b,c){var d=b,e=null;return a.getComputedStyle?e=document.defaultView.getComputedStyle(d,null).getPropertyValue(c):d.currentStyle&&(e=d.currentStyle[c]),e}function f(a,b,c){var f={},g;if(b==="save"){for(g in c)c.hasOwnProperty(g)&&(f[g]=e(a,g));d(a,c)}else b==="apply"&&d(a,c);return f}function g(a){var b=parseInt(e(a,"border-left-width"),10)+parseInt(e(a,"border-right-width"),10),c=parseInt(e(a,"padding-left"),10)+parseInt(e(a,"padding-right"),10),d=a.offsetWidth,f;return isNaN(b)&&(b=0),f=b+c+d,f}function h(a){var b=parseInt(e(a,"border-top-width"),10)+parseInt(e(a,"border-bottom-width"),10),c=parseInt(e(a,"padding-top"),10)+parseInt(e(a,"padding-bottom"),10),d=a.offsetHeight,f;return isNaN(b)&&(b=0),f=b+c+d,f}function i(a,b,d){d=d||"";var e=b.getElementsByTagName("head")[0],f=b.createElement("link");c(f,{type:"text/css",id:d,rel:"stylesheet",href:a,name:a,media:"screen"}),e.appendChild(f)}function j(a,b,c){a.className=a.className.replace(b,c)}function k(a){return a.contentDocument||a.contentWindow.document}function l(a){var b;return document.body.innerText?b=a.innerText:(b=a.innerHTML.replace(/
    /gi,"\n"),b=b.replace(/<(?:.|\n)*?>/gm,""),b=b.replace(/</gi,"<"),b=b.replace(/>/gi,">")),b}function m(a,b){return document.body.innerText?a.innerText=b:a.innerHTML=b.replace(/\n/g,"
    "),!0}function n(){var a=-1,b=navigator.userAgent,c;return navigator.appName=="Microsoft Internet Explorer"&&(c=/MSIE ([0-9]{1,}[\.0-9]{0,})/,c.exec(b)!=null&&(a=parseFloat(RegExp.$1,10))),a}function o(a){var b={};return a&&b.toString.call(a)==="[object Function]"}function p(){var a=arguments[0]||{},c=1,d=arguments.length,e=!1,f,g,h,i;typeof a=="boolean"&&(e=a,a=arguments[1]||{},c=2),typeof a!="object"&&!o(a)&&(a={}),d===c&&(a=this,--c);for(;c=5||Math.abs(u.x-b.pageX)>=5)r.style.display="block",s&&clearTimeout(s),s=a.setTimeout(function(){r.style.display="none"},1e3);u={y:b.pageY,x:b.pageX}}function J(a){a.keyCode==c.settings.shortcut.modifier&&(C=!0),a.keyCode==17&&(D=!0),C===!0&&a.keyCode==c.settings.shortcut.preview&&!c.eeState.fullscreen&&(a.preventDefault(),c.preview(),c.previewerIframe.focus()),C===!0&&a.keyCode==c.settings.shortcut.edit&&(a.preventDefault(),c.eeState.fullscreen||(c.edit(),c.editorIframe.focus())),C===!0&&a.keyCode==c.settings.shortcut.fullscreen&&(a.preventDefault(),y(B)),a.keyCode==27&&c.eeState.fullscreen&&(document.body.webkitRequestFullScreen||z(B)),D===!0&&a.keyCode==83&&(c.save(),a.preventDefault()),a.metaKey&&a.keyCode==83&&(c.save(),a.preventDefault())}function K(a){a.keyCode==c.settings.shortcut.modifier&&(C=!1),a.keyCode==17&&(D=!1)}var c=this,j,l,m,o,p,q,r,s,t,u={y:-1,x:-1},v,w,x=document.body.webkitRequestFullScreen?!0:!1,y,z,A,B,C=!1,D=!1,E,F;b=b||function(){},c.eeState={fullscreen:!1,preview:!1,edit:!0,loaded:!1,unloaded:!1},j={chrome:'
    '+' '+''+"
    "+"
    ",previewer:'
    '},c.element.innerHTML='',l=document.getElementById(c._instanceId),c.iframeElement=l,c.iframe=k(l),c.iframe.open(),c.iframe.write(j.chrome),c.editorIframe=c.iframe.getElementById("epiceditor-editor-frame"),c.previewerIframe=c.iframe.getElementById("epiceditor-previewer-frame"),c.editorIframeDocument=k(c.editorIframe),c.editorIframeDocument.open(),c.editorIframeDocument.write(""),c.editorIframeDocument.close(),c.previewerIframeDocument=k(c.previewerIframe),c.previewerIframeDocument.open(),c.previewerIframeDocument.write(j.previewer),m=c.previewerIframeDocument.createElement("base"),m.target="_blank",c.previewerIframeDocument.getElementsByTagName("head")[0].appendChild(m),c.previewerIframeDocument.close(),o=g(c.element)-c.element.offsetWidth,p=h(c.element)-c.element.offsetHeight,A=[c.iframeElement,c.editorIframe,c.previewerIframe],G(A),i(c.settings.basePath+c.settings.theme.base,c.iframe),i(c.settings.basePath+c.settings.theme.editor,c.editorIframeDocument),i(c.settings.basePath+c.settings.theme.preview,c.previewerIframeDocument),c.iframe.getElementById("epiceditor-wrapper").style.position="relative",c.editor=c.editorIframeDocument.body,c.previewer=c.previewerIframeDocument.getElementById("epiceditor-preview"),c.editor.contentEditable=!0,c.iframe.body.style.height=this.element.offsetHeight+"px",this.previewerIframe.style.display="none",n()>-1&&(this.previewer.style.height=parseInt(e(this.previewer,"height"),10)+2),i(c.settings.basePath+c.settings.theme.preview,c.previewerIframeDocument,"theme"),this.open(c.settings.file.name),c.settings.focusOnLoad&&c.iframe.addEventListener("readystatechange",function(){c.iframe.readyState=="complete"&&c.editorIframeDocument.body.focus()}),q=c.iframe.getElementById("epiceditor-utilbar"),v={},y=function(b){if(c.eeState.fullscreen){z(b);return}x&&b.webkitRequestFullScreen(),w=c.eeState.edit,c.eeState.fullscreen=!0,c.eeState.edit=!0,c.eeState.preview=!0;var d=a.innerWidth,g=a.innerHeight,h=a.outerWidth,i=a.outerHeight;x||(i=a.innerHeight),v.editorIframe=f(c.editorIframe,"save",{width:h/2+"px",height:i+"px","float":"left",cssFloat:"left",styleFloat:"left",display:"block"}),v.previewerIframe=f(c.previewerIframe,"save",{width:h/2+"px",height:i+"px","float":"right",cssFloat:"right",styleFloat:"right",display:"block"}),v.element=f(c.element,"save",{position:"fixed",top:"0",left:"0",width:"100%","z-index":"9999",zIndex:"9999",border:"none",margin:"0",background:e(c.editor,"background-color"),height:g+"px"}),v.iframeElement=f(c.iframeElement,"save",{width:h+"px",height:g+"px"}),q.style.visibility="hidden",x||(document.body.style.overflow="hidden"),c.preview(),c.editorIframeDocument.body.focus()},z=function(a){f(c.element,"apply",v.element),f(c.iframeElement,"apply",v.iframeElement),f(c.editorIframe,"apply",v.editorIframe),f(c.previewerIframe,"apply",v.previewerIframe),c.element.style.width="",c.element.style.height="",q.style.visibility="visible",x?document.webkitCancelFullScreen():document.body.style.overflow="auto",c.eeState.fullscreen=!1,w?c.edit():c.preview(),H(A)},c.editor.addEventListener("keyup",function(){t&&a.clearTimeout(t),t=a.setTimeout(function(){c.eeState.fullscreen&&c.preview()},250)}),B=c.iframeElement,q.addEventListener("click",function(a){var b=a.target.className;b.indexOf("epiceditor-toggle-preview-btn")>-1?c.preview():b.indexOf("epiceditor-toggle-edit-btn")>-1?c.edit():b.indexOf("epiceditor-fullscreen-btn")>-1&&y(B)}),document.body.webkitRequestFullScreen&&B.addEventListener("webkitfullscreenchange",function(){document.webkitIsFullScreen||z(B)},!1),r=c.iframe.getElementById("epiceditor-utilbar"),r.style.display="none",r.addEventListener("mouseover",function(){s&&clearTimeout(s)}),E=[c.previewerIframeDocument,c.editorIframeDocument];for(F=0;F"+b.lexer(a[1])+"":''+j(a[1])+'"}function f(){return e=d.pop()}function g(){switch(e.type){case"space":return"";case"hr":return"
    \n";case"heading":return""+b.lexer(e.text)+"\n";case"code":return p.highlight&&(e.code=p.highlight(e.text,e.lang),e.code!=null&&e.code!==e.text&&(e.escaped=!0,e.text=e.code)),e.escaped||(e.text=j(e.text,!0)),"
    "+e.text+"
    \n";case"blockquote_start":var a="";while(f().type!=="blockquote_end")a+=g();return"
    \n"+a+"
    \n";case"list_start":var c=e.ordered?"ol":"ul",a="";while(f().type!=="list_end")a+=g();return"<"+c+">\n"+a+"\n";case"list_item_start":var a="";while(f().type!=="list_item_end")a+=e.type==="text"?h():g();return"
  • "+a+"
  • \n";case"loose_item_start":var a="";while(f().type!=="list_item_end")a+=g();return"
  • "+a+"
  • \n";case"html":return p.sanitize?b.lexer(e.text):!e.pre&&!p.pedantic?b.lexer(e.text):e.text;case"paragraph":return"

    "+b.lexer(e.text)+"

    \n";case"text":return"

    "+h()+"

    \n"}}function h(){var a=e.text,c;while((c=d[d.length-1])&&c.type==="text")a+="\n"+f().text;return b.lexer(a)}function i(a){d=a.reverse();var b="";while(f())b+=g();return d=null,e=null,b}function j(a,b){return a.replace(b?/&/g:/&(?!#?\w+;)/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function k(a){var b="",c=a.length,d=0,e;for(;d.5&&(e="x"+e.toString(16)),b+="&#"+e+";";return b}function l(){var a="(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+";return a}function m(a,b){return a=a.source,b=b||"",function c(d,e){return d?(a=a.replace(d,e.source||e),c):new RegExp(a,b)}}function n(){}function o(b,c){return r(c),i(a.lexer(b))}function r(c){c||(c=q);if(p===c)return;p=c,p.gfm?(a.fences=a.gfm.fences,a.paragraph=a.gfm.paragraph,b.text=b.gfm.text,b.url=b.gfm.url):(a.fences=a.normal.fences,a.paragraph=a.normal.paragraph,b.text=b.normal.text,b.url=b.normal.url),p.pedantic?(b.em=b.pedantic.em,b.strong=b.pedantic.strong):(b.em=b.normal.em,b.strong=b.normal.strong)}var a={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:n,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,lheading:/^([^\n]+)\n *(=|-){3,} *\n*/,blockquote:/^( *>[^\n]+(\n[^\n]+)*\n*)+/,list:/^( *)(bull) [^\0]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,def:/^ *\[([^\]]+)\]: *([^\s]+)(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,paragraph:/^([^\n]+\n?(?!body))+\n*/,text:/^[^\n]+/};a.bullet=/(?:[*+-]|\d+\.)/,a.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/,a.item=m(a.item,"gm")(/bull/g,a.bullet)(),a.list=m(a.list)(/bull/g,a.bullet)("hr",/\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/)(),a.html=m(a.html)("comment",//)("closed",/<(tag)[^\0]+?<\/\1>/)("closing",/])*?>/)(/tag/g,l())(),a.paragraph=function(){var b=a.paragraph.source,c=[];return function d(b){return b=a[b]?a[b].source:b,c.push(b.replace(/(^|[^\[])\^/g,"$1")),d}("hr")("heading")("lheading")("blockquote")("<"+l())("def"),new RegExp(b.replace("body",c.join("|")))}(),a.normal={fences:a.fences,paragraph:a.paragraph},a.gfm={fences:/^ *``` *(\w+)? *\n([^\0]+?)\s*``` *(?:\n+|$)/,paragraph:/^/},a.gfm.paragraph=m(a.paragraph)("(?!","(?!"+a.gfm.fences.source.replace(/(^|[^\[])\^/g,"$1")+"|")(),a.lexer=function(b){var c=[];return c.links={},b=b.replace(/\r\n|\r/g,"\n").replace(/\t/g," "),a.token(b,c,!0)},a.token=function(b,c,d){var b=b.replace(/^ +$/gm,""),e,f,g,h,i,j,k;while(b){if(g=a.newline.exec(b))b=b.substring(g[0].length),g[0].length>1&&c.push({type:"space"});if(g=a.code.exec(b)){b=b.substring(g[0].length),g=g[0].replace(/^ {4}/gm,""),c.push({type:"code",text:p.pedantic?g:g.replace(/\n+$/,"")});continue}if(g=a.fences.exec(b)){b=b.substring(g[0].length),c.push({type:"code",lang:g[1],text:g[2]});continue}if(g=a.heading.exec(b)){b=b.substring(g[0].length),c.push({type:"heading",depth:g[1].length,text:g[2]});continue}if(g=a.lheading.exec(b)){b=b.substring(g[0].length),c.push({type:"heading",depth:g[2]==="="?1:2,text:g[1]});continue}if(g=a.hr.exec(b)){b=b.substring(g[0].length),c.push({type:"hr"});continue}if(g=a.blockquote.exec(b)){b=b.substring(g[0].length),c.push({type:"blockquote_start"}),g=g[0].replace(/^ *> ?/gm,""),a.token(g,c,d),c.push({type:"blockquote_end"});continue}if(g=a.list.exec(b)){b=b.substring(g[0].length),c.push({type:"list_start",ordered:isFinite(g[2])}),g=g[0].match(a.item),e=!1,k=g.length,j=0;for(;j])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:n,tag:/^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([^\0]+?)__(?!_)|^\*\*([^\0]+?)\*\*(?!\*)/,em:/^\b_((?:__|[^\0])+?)_\b|^\*((?:\*\*|[^\0])+?)\*(?!\*)/,code:/^(`+)([^\0]*?[^`])\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,text:/^[^\0]+?(?=[\\?(?:\s+['"]([^\0]*?)['"])?\s*/,b.link=m(b.link)("inside",b._linkInside)("href",b._linkHref)(),b.reflink=m(b.reflink)("inside",b._linkInside)(),b.normal={url:b.url,strong:b.strong,em:b.em,text:b.text},b.pedantic={strong:/^__(?=\S)([^\0]*?\S)__(?!_)|^\*\*(?=\S)([^\0]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([^\0]*?\S)_(?!_)|^\*(?=\S)([^\0]*?\S)\*(?!\*)/},b.gfm={url:/^(https?:\/\/[^\s]+[^.,:;"')\]\s])/,text:/^[^\0]+?(?=[\\'+h+"";continue}if(l=b.url.exec(a)){a=a.substring(l[0].length),h=j(l[1]),i=h,e+=''+h+"";continue}if(l=b.tag.exec(a)){a=a.substring(l[0].length),e+=p.sanitize?j(l[0]):l[0];continue}if(l=b.link.exec(a)){a=a.substring(l[0].length),e+=c(l,{href:l[2],title:l[3]});continue}if((l=b.reflink.exec(a))||(l=b.nolink.exec(a))){a=a.substring(l[0].length),g=(l[2]||l[1]).replace(/\s+/g," "),g=f[g.toLowerCase()];if(!g||!g.href){e+=l[0][0],a=l[0].substring(1)+a;continue}e+=c(l,g);continue}if(l=b.strong.exec(a)){a=a.substring(l[0].length),e+=""+b.lexer(l[2]||l[1])+"";continue}if(l=b.em.exec(a)){a=a.substring(l[0].length),e+=""+b.lexer(l[2]||l[1])+"";continue}if(l=b.code.exec(a)){a=a.substring(l[0].length),e+=""+j(l[2],!0)+"";continue}if(l=b.br.exec(a)){a=a.substring(l[0].length),e+="
    ";continue}if(l=b.text.exec(a)){a=a.substring(l[0].length),e+=j(l[0]);continue}}return e};var d,e;n.exec=n;var p,q;o.options=o.setOptions=function(a){return q=a,r(a),o},o.setOptions({gfm:!0,pedantic:!1,sanitize:!1,highlight:null}),o.parser=function(a,b){return r(b),i(a)},o.lexer=function(b,c){return r(c),a.lexer(b)},o.parse=o,typeof module!="undefined"?module.exports=o:this.marked=o}.call(function(){return this||(typeof window!="undefined"?window:global)}()); \ No newline at end of file diff --git a/spec/spec.js b/spec/spec.js index 974e696..3199d66 100644 --- a/spec/spec.js +++ b/spec/spec.js @@ -81,23 +81,79 @@ describe('EpicEditor.load.options', function () { testEl = _createTestElement(); }); - it('check that the container option can be a string of an ID of an element', function () { - editor = new EpicEditor( - { basePath: '/epiceditor/' - , container: testEl - } - ).load(); - - expect(document.getElementById(testEl).getElementsByTagName('iframe').length).to(be, 1); + after(function () { + editor.unload(); }); - it('check that the container option can be a DOM object an element', function () { - editor = new EpicEditor({ - basePath: '/epiceditor/' - , container: document.getElementById(testEl) - }).load(); + describe('when setting the container element', function () { - expect(document.getElementById(testEl).getElementsByTagName('iframe').length).to(be, 1); + it('allows the value to be a string of an ID to an element', function () { + editor = new EpicEditor( + { basePath: '/epiceditor/' + , container: testEl + } + ).load(); + + expect(document.getElementById(testEl).getElementsByTagName('iframe').length).to(be, 1); + }); + + it('allows the value to be a DOM object of an element', function () { + editor = new EpicEditor({ + basePath: '/epiceditor/' + , container: document.getElementById(testEl) + }).load(); + + expect(document.getElementById(testEl).getElementsByTagName('iframe').length).to(be, 1); + }); + + it('check that the localStorage key is correctly named for string values (IDs)', function () { + editor = new EpicEditor({ + basePath: '/epiceditor/' + , container: testEl + }).load(); + expect(JSON.parse(localStorage.epiceditor)[testEl]).to(beTruthy); + }); + + it('check that the localStorage key is correctly named for DOM elements by using the ID of the element', function () { + + // This is all for a one off test. Creates an element with a different class name and ID + // and we need to be able to get the name of the ID and class later + var tempEl = document.createElement('div') + , tempId = 'foo' + _randomNum() + , tempClassName = 'bar' + _randomNum(); + tempEl.id = tempId; + tempEl.className = tempClassName; + document.body.appendChild(tempEl); + + editor = new EpicEditor({ + basePath: '/epiceditor/' + , container: document.getElementsByClassName(tempClassName)[0] + }).load(); + expect(JSON.parse(localStorage.epiceditor)[tempId]).to(beTruthy); + }); + + it('check that the localStorage key is correctly named for manually set file names', function () { + var tempName = 'foo' + _randomNum(); + editor = new EpicEditor({ + basePath: '/epiceditor/' + , container: testEl + , file: { name: tempName } + }).load(); + expect(JSON.parse(localStorage.epiceditor)[testEl]).to(beFalsy); + }); + + it('check that the localStorage key is correctly named when there\'s no fallback name', function () { + var tempEl = document.createElement('div') + , tempClassName = 'foo' + _randomNum(); + tempEl.className = tempClassName; + document.body.appendChild(tempEl); + + editor = new EpicEditor({ + basePath: '/epiceditor/' + , container: document.getElementsByClassName(tempClassName)[0] + }).load(); + expect(JSON.parse(localStorage.epiceditor)['__epiceditor-untitled-1']).to(beTruthy); + }); }); }); @@ -164,6 +220,10 @@ describe('EpicEditor.open', function () { }); }); + after(function () { + editor.unload(); + }); + it('check that the openMe file was created successfully', function () { expect(editor.exportFile(openMeFile)).to(be, 'open this file'); }); @@ -233,6 +293,10 @@ describe('EpicEditor.importFile', function () { eventWasFired = false; }); + after(function () { + editor.unload(); + }); + it('check that the content is currently blank', function () { expect(editor.exportFile()).to(be, ''); }); @@ -294,6 +358,9 @@ describe('EpicEditor.exportFile', function () { }).load(); }); + after(function () { + editor.unload(); + }); it('check that exportFile will work without parameters by outputting the current file as raw text', function () { contents = editor.exportFile(); @@ -330,6 +397,10 @@ describe('EpicEditor.rename', function () { editor.importFile(oldName, 'testing...'); }); + after(function () { + editor.unload(); + }); + it('check to see if the foo file exists before trying to rename', function () { expect(editor.exportFile(oldName)).to(be, 'testing...'); }); @@ -357,7 +428,11 @@ describe('EpicEditor.remove', function () { dontRemoveMeFile = 'dontRemoveMe' + _randomNum(); editor.importFile(removeMeFile, 'hello world').importFile(dontRemoveMeFile, 'foo bar'); }); - + + after(function () { + editor.unload(); + }); + it('check that the foo file was imported', function () { expect(editor.exportFile(removeMeFile)).to(be, 'hello world'); }); @@ -406,6 +481,7 @@ describe('EpicEditor.preview and EpicEditor.edit', function () { after(function () { editor.removeListener('preview'); editor.removeListener('edit'); + editor.unload(); }); it('check that the editor is currently displayed and not the previewer', function () { @@ -514,6 +590,10 @@ describe('EpicEditor.save', function () { eventWasFired = false; }); + after(function () { + editor.unload(); + }); + it('check that foo is the default content in the editor', function () { expect(editor.getElement('editor').body.innerHTML).to(be, 'foo'); }); @@ -574,6 +654,7 @@ describe('EpicEditor.on', function () { after(function () { editor.removeListener('foo'); + editor.unload(); }); it('check that on fires on an EE event, preview', function () { @@ -606,6 +687,7 @@ describe('EpicEditor.emit', function () { after(function () { editor.removeListener('foo'); + editor.unload(); }); // We don't use events in EpicEditor so only custom events need to be checked @@ -644,6 +726,10 @@ describe('EpicEditor.removeListener', function () { editor.on('bar', qux); }); + after(function () { + editor.unload(); + }); + it('check that the foo event can be fired', function () { editor.emit('foo'); expect(hasBeenFired).to(beTrue); diff --git a/src/editor.js b/src/editor.js index 2bd75f0..fd8420a 100644 --- a/src/editor.js +++ b/src/editor.js @@ -280,8 +280,8 @@ , defaults = { container: 'epiceditor' , basePath: 'epiceditor' , localStorageName: 'epiceditor' - , file: { name: opts.container || 'epiceditor' // Use the container's ID for an unique persistent file name - will be overwritten if passed a file.name opt - , defaultContent: '' + , file: { name: null + , defaultContent: '' , autoSave: 100 // Set to false for no auto saving } , theme: { base: '/themes/base/epiceditor.css' @@ -306,9 +306,41 @@ } } + + // Grab the container element and save it to self.element + // if it's a string assume it's an ID and if it's an object + // assume it's a DOM element + if (typeof self.settings.container == 'string') { + self.element = document.getElementById(self.settings.container); + } + else if (typeof self.settings.container == 'object') { + self.element = self.settings.container; + } + + // Figure out the file name. If no file name is given we'll use the ID. + // If there's no ID either we'll use a namespaced file name that's incremented + // based on the calling order. As long as it doesn't change, drafts will be saved. + if (!self.settings.file.name) { + if (typeof self.settings.container == 'string') { + self.settings.file.name = self.settings.container; + } + else if (typeof self.settings.container == 'object') { + if (self.element.id) { + self.settings.file.name = self.element.id; + } + else { + if (!EpicEditor._data.unnamedEditors) { + EpicEditor._data.unnamedEditors = []; + } + EpicEditor._data.unnamedEditors.push(self); + self.settings.file.name = '__epiceditor-untitled-' + EpicEditor._data.unnamedEditors.length; + } + } + } + // Protect the id and overwrite if passed in as an option // TODO: Put underscrore to denote that this is private - self.instanceId = 'epiceditor-' + Math.round(Math.random() * 100000); + self._instanceId = 'epiceditor-' + Math.round(Math.random() * 100000); self._canSave = true; @@ -343,13 +375,6 @@ self.events = {}; } - if (typeof self.settings.container == 'string') { - self.element = document.getElementById(self.settings.container); - } - else if (typeof self.settings.container == 'object') { - self.element = self.settings.container; - } - return this; } @@ -428,8 +453,8 @@ } } // Write an iframe and then select it for the editor - self.element.innerHTML = ''; - iframeElement = document.getElementById(self.instanceId); + self.element.innerHTML = ''; + iframeElement = document.getElementById(self._instanceId); // Store a reference to the iframeElement itself self.iframeElement = iframeElement; @@ -839,7 +864,7 @@ } var self = this - , editor = window.parent.document.getElementById(self.instanceId); + , editor = window.parent.document.getElementById(self._instanceId); editor.parentNode.removeChild(editor); self.eeState.loaded = false; @@ -1173,5 +1198,8 @@ EpicEditor.version = '@VERSION'; + // Used to store information to be shared acrossed editors + EpicEditor._data = {}; + window.EpicEditor = EpicEditor; })(window);