From: Art Cancro Date: Sun, 26 Dec 2021 15:49:33 +0000 (-0500) Subject: Removed the epic editor from the tree. Why was it even there? It wasn't being used. X-Git-Tag: v943~18 X-Git-Url: https://code.citadel.org/?p=citadel.git;a=commitdiff_plain;h=855073983438f28a7672b39a679da6b5bac541e9 Removed the epic editor from the tree. Why was it even there? It wasn't being used. --- diff --git a/webcit/epic/js/epiceditor.js b/webcit/epic/js/epiceditor.js deleted file mode 100644 index befaf546a..000000000 --- a/webcit/epic/js/epiceditor.js +++ /dev/null @@ -1,2899 +0,0 @@ -/** - * EpicEditor - An Embeddable JavaScript Markdown Editor (https://github.com/OscarGodson/EpicEditor) - * Copyright (c) 2011-2012, Oscar Godson. (MIT Licensed) - */ - -(function (window, undefined) { - /** - * Applies attributes to a DOM object - * @param {object} context The DOM obj you want to apply the attributes to - * @param {object} attrs A key/value pair of attributes you want to apply - * @returns {undefined} - */ - function _applyAttrs(context, attrs) { - for (var attr in attrs) { - if (attrs.hasOwnProperty(attr)) { - context[attr] = attrs[attr]; - } - } - } - - /** - * Applies styles to a DOM object - * @param {object} context The DOM obj you want to apply the attributes to - * @param {object} attrs A key/value pair of attributes you want to apply - * @returns {undefined} - */ - function _applyStyles(context, attrs) { - for (var attr in attrs) { - if (attrs.hasOwnProperty(attr)) { - context.style[attr] = attrs[attr]; - } - } - } - - /** - * Returns a DOM objects computed style - * @param {object} el The element you want to get the style from - * @param {string} styleProp The property you want to get from the element - * @returns {string} Returns a string of the value. If property is not set it will return a blank string - */ - function _getStyle(el, styleProp) { - var x = el - , y = null; - if (window.getComputedStyle) { - y = document.defaultView.getComputedStyle(x, null).getPropertyValue(styleProp); - } - else if (x.currentStyle) { - y = x.currentStyle[styleProp]; - } - return y; - } - - /** - * Saves the current style state for the styles requested, then applies styles - * to overwrite the existing one. The old styles are returned as an object so - * you can pass it back in when you want to revert back to the old style - * @param {object} el The element to get the styles of - * @param {string} type Can be "save" or "apply". apply will just apply styles you give it. Save will write styles - * @param {object} styles Key/value style/property pairs - * @returns {object} - */ - function _saveStyleState(el, type, styles) { - var returnState = {} - , style; - if (type === 'save') { - for (style in styles) { - if (styles.hasOwnProperty(style)) { - returnState[style] = _getStyle(el, style); - } - } - // After it's all done saving all the previous states, change the styles - _applyStyles(el, styles); - } - else if (type === 'apply') { - _applyStyles(el, styles); - } - return returnState; - } - - /** - * Gets an elements total width including it's borders and padding - * @param {object} el The element to get the total width of - * @returns {int} - */ - function _outerWidth(el) { - var b = parseInt(_getStyle(el, 'border-left-width'), 10) + parseInt(_getStyle(el, 'border-right-width'), 10) - , p = parseInt(_getStyle(el, 'padding-left'), 10) + parseInt(_getStyle(el, 'padding-right'), 10) - , w = el.offsetWidth - , t; - // For IE in case no border is set and it defaults to "medium" - if (isNaN(b)) { b = 0; } - t = b + p + w; - return t; - } - - /** - * Gets an elements total height including it's borders and padding - * @param {object} el The element to get the total width of - * @returns {int} - */ - function _outerHeight(el) { - var b = parseInt(_getStyle(el, 'border-top-width'), 10) + parseInt(_getStyle(el, 'border-bottom-width'), 10) - , p = parseInt(_getStyle(el, 'padding-top'), 10) + parseInt(_getStyle(el, 'padding-bottom'), 10) - , w = parseInt(_getStyle(el, 'height'), 10) - , t; - // For IE in case no border is set and it defaults to "medium" - if (isNaN(b)) { b = 0; } - t = b + p + w; - return t; - } - - /** - * Inserts a tag specifically for CSS - * @param {string} path The path to the CSS file - * @param {object} context In what context you want to apply this to (document, iframe, etc) - * @param {string} id An id for you to reference later for changing properties of the - * @returns {undefined} - */ - function _insertCSSLink(path, context, id) { - id = id || ''; - var headID = context.getElementsByTagName("head")[0] - , cssNode = context.createElement('link'); - - _applyAttrs(cssNode, { - type: 'text/css' - , id: id - , rel: 'stylesheet' - , href: path - , name: path - , media: 'screen' - }); - - headID.appendChild(cssNode); - } - - // Simply replaces a class (o), to a new class (n) on an element provided (e) - function _replaceClass(e, o, n) { - e.className = e.className.replace(o, n); - } - - // Feature detects an iframe to get the inner document for writing to - function _getIframeInnards(el) { - return el.contentDocument || el.contentWindow.document; - } - - // Grabs the text from an element and preserves whitespace - function _getText(el) { - var theText; - // Make sure to check for type of string because if the body of the page - // doesn't have any text it'll be "" which is falsey and will go into - // the else which is meant for Firefox and shit will break - if (typeof document.body.innerText == 'string') { - theText = el.innerText; - } - else { - // First replace
s before replacing the rest of the HTML - theText = el.innerHTML.replace(/
/gi, "\n"); - // Now we can clean the HTML - theText = theText.replace(/<(?:.|\n)*?>/gm, ''); - // Now fix HTML entities - theText = theText.replace(/</gi, '<'); - theText = theText.replace(/>/gi, '>'); - } - return theText; - } - - function _setText(el, content) { - // Don't convert lt/gt characters as HTML when viewing the editor window - // TODO: Write a test to catch regressions for this - content = content.replace(//g, '>'); - content = content.replace(/\n/g, '
'); - - // Make sure to there aren't two spaces in a row (replace one with  ) - // If you find and replace every space with a   text will not wrap. - // Hence the name (Non-Breaking-SPace). - // TODO: Probably need to test this somehow... - content = content.replace(/
\s/g, '
 ') - content = content.replace(/\s\s\s/g, '   ') - content = content.replace(/\s\s/g, '  ') - content = content.replace(/^ /, ' ') - - el.innerHTML = content; - return true; - } - - /** - * Converts the 'raw' format of a file's contents into plaintext - * @param {string} content Contents of the file - * @returns {string} the sanitized content - */ - function _sanitizeRawContent(content) { - // Get this, 2 spaces in a content editable actually converts to: - // 0020 00a0, meaning, "space no-break space". So, manually convert - // no-break spaces to spaces again before handing to marked. - // Also, WebKit converts no-break to unicode equivalent and FF HTML. - return content.replace(/\u00a0/g, ' ').replace(/ /g, ' '); - } - - /** - * Will return the version number if the browser is IE. If not will return -1 - * TRY NEVER TO USE THIS AND USE FEATURE DETECTION IF POSSIBLE - * @returns {Number} -1 if false or the version number if true - */ - function _isIE() { - var rv = -1 // Return value assumes failure. - , ua = navigator.userAgent - , re; - if (navigator.appName == 'Microsoft Internet Explorer') { - re = /MSIE ([0-9]{1,}[\.0-9]{0,})/; - if (re.exec(ua) != null) { - rv = parseFloat(RegExp.$1, 10); - } - } - return rv; - } - - /** - * Same as the isIE(), but simply returns a boolean - * THIS IS TERRIBLE AND IS ONLY USED BECAUSE FULLSCREEN IN SAFARI IS BORKED - * If some other engine uses WebKit and has support for fullscreen they - * probably wont get native fullscreen until Safari's fullscreen is fixed - * @returns {Boolean} true if Safari - */ - function _isSafari() { - var n = window.navigator; - return n.userAgent.indexOf('Safari') > -1 && n.userAgent.indexOf('Chrome') == -1; - } - - /** - * Same as the isIE(), but simply returns a boolean - * THIS IS TERRIBLE ONLY USE IF ABSOLUTELY NEEDED - * @returns {Boolean} true if Safari - */ - function _isFirefox() { - var n = window.navigator; - return n.userAgent.indexOf('Firefox') > -1 && n.userAgent.indexOf('Seamonkey') == -1; - } - - /** - * Determines if supplied value is a function - * @param {object} object to determine type - */ - function _isFunction(functionToCheck) { - var getType = {}; - return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]'; - } - - /** - * Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1 - * @param {boolean} [deepMerge=false] If true, will deep merge meaning it will merge sub-objects like {obj:obj2{foo:'bar'}} - * @param {object} first object - * @param {object} second object - * @returnss {object} a new object based on obj1 and obj2 - */ - function _mergeObjs() { - // copy reference to target object - var target = arguments[0] || {} - , i = 1 - , length = arguments.length - , deep = false - , options - , name - , src - , copy - - // Handle a deep copy situation - if (typeof target === "boolean") { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if (typeof target !== "object" && !_isFunction(target)) { - target = {}; - } - // extend jQuery itself if only one argument is passed - if (length === i) { - target = this; - --i; - } - - for (; i < length; i++) { - // Only deal with non-null/undefined values - if ((options = arguments[i]) != null) { - // Extend the base object - for (name in options) { - // @NOTE: added hasOwnProperty check - if (options.hasOwnProperty(name)) { - src = target[name]; - copy = options[name]; - // Prevent never-ending loop - if (target === copy) { - continue; - } - // Recurse if we're merging object values - if (deep && copy && typeof copy === "object" && !copy.nodeType) { - target[name] = _mergeObjs(deep, - // Never move original objects, clone them - src || (copy.length != null ? [] : {}) - , copy); - } else if (copy !== undefined) { // Don't bring in undefined values - target[name] = copy; - } - } - } - } - } - - // Return the modified object - return target; - } - - /** - * Initiates the EpicEditor object and sets up offline storage as well - * @class Represents an EpicEditor instance - * @param {object} options An optional customization object - * @returns {object} EpicEditor will be returned - */ - function EpicEditor(options) { - // Default settings will be overwritten/extended by options arg - var self = this - , opts = options || {} - , _defaultFileSchema - , _defaultFile - , defaults = { container: 'epiceditor' - , basePath: 'epiceditor' - , textarea: undefined - , clientSideStorage: true - , localStorageName: 'epiceditor' - , useNativeFullscreen: true - , file: { name: null - , defaultContent: '' - , autoSave: 100 // Set to false for no auto saving - } - , theme: { base: '/themes/base/epiceditor.css' - , preview: '/themes/preview/github.css' - , editor: '/themes/editor/epic-dark.css' - } - , focusOnLoad: false - , shortcut: { modifier: 18 // alt keycode - , fullscreen: 70 // f keycode - , preview: 80 // p keycode - } - , string: { togglePreview: 'Toggle Preview Mode' - , toggleEdit: 'Toggle Edit Mode' - , toggleFullscreen: 'Enter Fullscreen' - } - , parser: typeof marked == 'function' ? marked : null - , autogrow: false - , button: { fullscreen: true - , preview: true - , bar: "auto" - } - } - , defaultStorage - , autogrowDefaults = { minHeight: 80 - , maxHeight: false - , scroll: true - }; - - self.settings = _mergeObjs(true, defaults, opts); - - var buttons = self.settings.button; - self._fullscreenEnabled = typeof(buttons) === 'object' ? typeof buttons.fullscreen === 'undefined' || buttons.fullscreen : buttons === true; - self._editEnabled = typeof(buttons) === 'object' ? typeof buttons.edit === 'undefined' || buttons.edit : buttons === true; - self._previewEnabled = typeof(buttons) === 'object' ? typeof buttons.preview === 'undefined' || buttons.preview : buttons === true; - - if (!(typeof self.settings.parser == 'function' && typeof self.settings.parser('TEST') == 'string')) { - self.settings.parser = function (str) { - return str; - } - } - - if (self.settings.autogrow) { - if (self.settings.autogrow === true) { - self.settings.autogrow = autogrowDefaults; - } - else { - self.settings.autogrow = _mergeObjs(true, autogrowDefaults, self.settings.autogrow); - } - self._oldHeight = -1; - } - - // If you put an absolute link as the path of any of the themes ignore the basePath - // preview theme - if (!self.settings.theme.preview.match(/^https?:\/\//)) { - self.settings.theme.preview = self.settings.basePath + self.settings.theme.preview; - } - // editor theme - if (!self.settings.theme.editor.match(/^https?:\/\//)) { - self.settings.theme.editor = self.settings.basePath + self.settings.theme.editor; - } - // base theme - if (!self.settings.theme.base.match(/^https?:\/\//)) { - self.settings.theme.base = self.settings.basePath + self.settings.theme.base; - } - - // 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; - } - } - } - - if (self.settings.button.bar === "show") { - self.settings.button.bar = true; - } - - if (self.settings.button.bar === "hide") { - self.settings.button.bar = false; - } - - // 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._storage = {}; - self._canSave = true; - - // Setup local storage of files - self._defaultFileSchema = function () { - return { - content: self.settings.file.defaultContent - , created: new Date() - , modified: new Date() - } - } - - if (localStorage && self.settings.clientSideStorage) { - this._storage = localStorage; - if (this._storage[self.settings.localStorageName] && self.getFiles(self.settings.file.name) === undefined) { - _defaultFile = self._defaultFileSchema(); - _defaultFile.content = self.settings.file.defaultContent; - } - } - - if (!this._storage[self.settings.localStorageName]) { - defaultStorage = {}; - defaultStorage[self.settings.file.name] = self._defaultFileSchema(); - defaultStorage = JSON.stringify(defaultStorage); - this._storage[self.settings.localStorageName] = defaultStorage; - } - - // A string to prepend files with to save draft versions of files - // and reset all preview drafts on each load! - self._previewDraftLocation = '__draft-'; - self._storage[self._previewDraftLocation + self.settings.localStorageName] = self._storage[self.settings.localStorageName]; - - // This needs to replace the use of classes to check the state of EE - self._eeState = { - fullscreen: false - , preview: false - , edit: false - , loaded: false - , unloaded: false - } - - // Now that it exists, allow binding of events if it doesn't exist yet - if (!self.events) { - self.events = {}; - } - - return this; - } - - /** - * Inserts the EpicEditor into the DOM via an iframe and gets it ready for editing and previewing - * @returns {object} EpicEditor will be returned - */ - EpicEditor.prototype.load = function (callback) { - - // Get out early if it's already loaded - if (this.is('loaded')) { return this; } - - // TODO: Gotta get the privates with underscores! - // TODO: Gotta document what these are for... - var self = this - , _HtmlTemplates - , iframeElement - , baseTag - , utilBtns - , utilBar - , utilBarTimer - , keypressTimer - , mousePos = { y: -1, x: -1 } - , _elementStates - , _isInEdit - , nativeFs = false - , nativeFsWebkit = false - , nativeFsMoz = false - , nativeFsW3C = false - , fsElement - , isMod = false - , isCtrl = false - , eventableIframes - , i // i is reused for loops - , boundAutogrow; - - // Startup is a way to check if this EpicEditor is starting up. Useful for - // checking and doing certain things before EpicEditor emits a load event. - self._eeState.startup = true; - - if (self.settings.useNativeFullscreen) { - nativeFsWebkit = document.body.webkitRequestFullScreen ? true : false; - nativeFsMoz = document.body.mozRequestFullScreen ? true : false; - nativeFsW3C = document.body.requestFullscreen ? true : false; - nativeFs = nativeFsWebkit || nativeFsMoz || nativeFsW3C; - } - - // Fucking Safari's native fullscreen works terribly - // REMOVE THIS IF SAFARI 7 WORKS BETTER - if (_isSafari()) { - nativeFs = false; - nativeFsWebkit = false; - } - - // It opens edit mode by default (for now); - if (!self.is('edit') && !self.is('preview')) { - self._eeState.edit = true; - } - - callback = callback || function () {}; - - // The editor HTML - // TODO: edit-mode class should be dynamically added - _HtmlTemplates = { - // This is wrapping iframe element. It contains the other two iframes and the utilbar - chrome: '
' + - '' + - '' + - '
' + - (self._previewEnabled ? ' ' : '') + - (self._editEnabled ? ' ' : '') + - (self._fullscreenEnabled ? '' : '') + - '
' + - '
' - - // The previewer is just an empty box for the generated HTML to go into - , previewer: '
' - , editor: '' - }; - - // Write an iframe and then select it for the editor - self.element.innerHTML = ''; - - // Because browsers add things like invisible padding and margins and stuff - // to iframes, we need to set manually set the height so that the height - // doesn't keep increasing (by 2px?) every time reflow() is called. - // FIXME: Figure out how to fix this without setting this - self.element.style.height = self.element.offsetHeight + 'px'; - - iframeElement = document.getElementById(self._instanceId); - - // Store a reference to the iframeElement itself - self.iframeElement = iframeElement; - - // Grab the innards of the iframe (returns the document.body) - // TODO: Change self.iframe to self.iframeDocument - self.iframe = _getIframeInnards(iframeElement); - self.iframe.open(); - self.iframe.write(_HtmlTemplates.chrome); - - // Now that we got the innards of the iframe, we can grab the other iframes - self.editorIframe = self.iframe.getElementById('epiceditor-editor-frame') - self.previewerIframe = self.iframe.getElementById('epiceditor-previewer-frame'); - - // Setup the editor iframe - self.editorIframeDocument = _getIframeInnards(self.editorIframe); - self.editorIframeDocument.open(); - // Need something for... you guessed it, Firefox - self.editorIframeDocument.write(_HtmlTemplates.editor); - self.editorIframeDocument.close(); - - // Setup the previewer iframe - self.previewerIframeDocument = _getIframeInnards(self.previewerIframe); - self.previewerIframeDocument.open(); - self.previewerIframeDocument.write(_HtmlTemplates.previewer); - - // Base tag is added so that links will open a new tab and not inside of the iframes - baseTag = self.previewerIframeDocument.createElement('base'); - baseTag.target = '_blank'; - self.previewerIframeDocument.getElementsByTagName('head')[0].appendChild(baseTag); - - self.previewerIframeDocument.close(); - - self.reflow(); - - // Insert Base Stylesheet - _insertCSSLink(self.settings.theme.base, self.iframe, 'theme'); - - // Insert Editor Stylesheet - _insertCSSLink(self.settings.theme.editor, self.editorIframeDocument, 'theme'); - - // Insert Previewer Stylesheet - _insertCSSLink(self.settings.theme.preview, self.previewerIframeDocument, 'theme'); - - // Add a relative style to the overall wrapper to keep CSS relative to the editor - self.iframe.getElementById('epiceditor-wrapper').style.position = 'relative'; - - // Set the position to relative so we hide them with left: -999999px - self.editorIframe.style.position = 'absolute'; - self.previewerIframe.style.position = 'absolute'; - - // Now grab the editor and previewer for later use - self.editor = self.editorIframeDocument.body; - self.previewer = self.previewerIframeDocument.getElementById('epiceditor-preview'); - - self.editor.contentEditable = true; - - // Firefox's gets all fucked up so, to be sure, we need to hardcode it - self.iframe.body.style.height = this.element.offsetHeight + 'px'; - - // Should actually check what mode it's in! - self.previewerIframe.style.left = '-999999px'; - - // Keep long lines from being longer than the editor - this.editorIframeDocument.body.style.wordWrap = 'break-word'; - - // FIXME figure out why it needs +2 px - if (_isIE() > -1) { - this.previewer.style.height = parseInt(_getStyle(this.previewer, 'height'), 10) + 2; - } - - // If there is a file to be opened with that filename and it has content... - this.open(self.settings.file.name); - - if (self.settings.focusOnLoad) { - // We need to wait until all three iframes are done loading by waiting until the parent - // iframe's ready state == complete, then we can focus on the contenteditable - self.iframe.addEventListener('readystatechange', function () { - if (self.iframe.readyState == 'complete') { - self.focus(); - } - }); - } - - // Because IE scrolls the whole window to hash links, we need our own - // method of scrolling the iframe to an ID from clicking a hash - self.previewerIframeDocument.addEventListener('click', function (e) { - var el = e.target - , body = self.previewerIframeDocument.body; - if (el.nodeName == 'A') { - // Make sure the link is a hash and the link is local to the iframe - if (el.hash && el.hostname == window.location.hostname) { - // Prevent the whole window from scrolling - e.preventDefault(); - // Prevent opening a new window - el.target = '_self'; - // Scroll to the matching element, if an element exists - if (body.querySelector(el.hash)) { - body.scrollTop = body.querySelector(el.hash).offsetTop; - } - } - } - }); - - utilBtns = self.iframe.getElementById('epiceditor-utilbar'); - - // TODO: Move into fullscreen setup function (_setupFullscreen) - _elementStates = {} - self._goFullscreen = function (el) { - this._fixScrollbars('auto'); - - if (self.is('fullscreen')) { - self._exitFullscreen(el); - return; - } - - if (nativeFs) { - if (nativeFsWebkit) { - el.webkitRequestFullScreen(); - } - else if (nativeFsMoz) { - el.mozRequestFullScreen(); - } - else if (nativeFsW3C) { - el.requestFullscreen(); - } - } - - _isInEdit = self.is('edit'); - - // Set the state of EE in fullscreen - // We set edit and preview to true also because they're visible - // we might want to allow fullscreen edit mode without preview (like a "zen" mode) - self._eeState.fullscreen = true; - self._eeState.edit = true; - self._eeState.preview = true; - - // Cache calculations - var windowInnerWidth = window.innerWidth - , windowInnerHeight = window.innerHeight - , windowOuterWidth = window.outerWidth - , windowOuterHeight = window.outerHeight; - - // Without this the scrollbars will get hidden when scrolled to the bottom in faux fullscreen (see #66) - if (!nativeFs) { - windowOuterHeight = window.innerHeight; - } - - // This MUST come first because the editor is 100% width so if we change the width of the iframe or wrapper - // the editor's width wont be the same as before - _elementStates.editorIframe = _saveStyleState(self.editorIframe, 'save', { - 'width': windowOuterWidth / 2 + 'px' - , 'height': windowOuterHeight + 'px' - , 'float': 'left' // Most browsers - , 'cssFloat': 'left' // FF - , 'styleFloat': 'left' // Older IEs - , 'display': 'block' - , 'position': 'static' - , 'left': '' - }); - - // the previewer - _elementStates.previewerIframe = _saveStyleState(self.previewerIframe, 'save', { - 'width': windowOuterWidth / 2 + 'px' - , 'height': windowOuterHeight + 'px' - , 'float': 'right' // Most browsers - , 'cssFloat': 'right' // FF - , 'styleFloat': 'right' // Older IEs - , 'display': 'block' - , 'position': 'static' - , 'left': '' - }); - - // Setup the containing element CSS for fullscreen - _elementStates.element = _saveStyleState(self.element, 'save', { - 'position': 'fixed' - , 'top': '0' - , 'left': '0' - , 'width': '100%' - , 'z-index': '9999' // Most browsers - , 'zIndex': '9999' // Firefox - , 'border': 'none' - , 'margin': '0' - // Should use the base styles background! - , 'background': _getStyle(self.editor, 'background-color') // Try to hide the site below - , 'height': windowInnerHeight + 'px' - }); - - // The iframe element - _elementStates.iframeElement = _saveStyleState(self.iframeElement, 'save', { - 'width': windowOuterWidth + 'px' - , 'height': windowInnerHeight + 'px' - }); - - // ...Oh, and hide the buttons and prevent scrolling - utilBtns.style.visibility = 'hidden'; - - if (!nativeFs) { - document.body.style.overflow = 'hidden'; - } - - self.preview(); - - self.focus(); - - self.emit('fullscreenenter'); - }; - - self._exitFullscreen = function (el) { - this._fixScrollbars(); - - _saveStyleState(self.element, 'apply', _elementStates.element); - _saveStyleState(self.iframeElement, 'apply', _elementStates.iframeElement); - _saveStyleState(self.editorIframe, 'apply', _elementStates.editorIframe); - _saveStyleState(self.previewerIframe, 'apply', _elementStates.previewerIframe); - - // We want to always revert back to the original styles in the CSS so, - // if it's a fluid width container it will expand on resize and not get - // stuck at a specific width after closing fullscreen. - self.element.style.width = self._eeState.reflowWidth ? self._eeState.reflowWidth : ''; - self.element.style.height = self._eeState.reflowHeight ? self._eeState.reflowHeight : ''; - - utilBtns.style.visibility = 'visible'; - - // Put the editor back in the right state - // TODO: This is ugly... how do we make this nicer? - // setting fullscreen to false here prevents the - // native fs callback from calling this function again - self._eeState.fullscreen = false; - - if (!nativeFs) { - document.body.style.overflow = 'auto'; - } - else { - if (nativeFsWebkit) { - document.webkitCancelFullScreen(); - } - else if (nativeFsMoz) { - document.mozCancelFullScreen(); - } - else if (nativeFsW3C) { - document.exitFullscreen(); - } - } - - if (_isInEdit) { - self.edit(); - } - else { - self.preview(); - } - - self.reflow(); - - self.emit('fullscreenexit'); - }; - - // This setups up live previews by triggering preview() IF in fullscreen on keyup - self.editor.addEventListener('keyup', function () { - if (keypressTimer) { - window.clearTimeout(keypressTimer); - } - keypressTimer = window.setTimeout(function () { - if (self.is('fullscreen')) { - self.preview(); - } - }, 250); - }); - - fsElement = self.iframeElement; - - // Sets up the onclick event on utility buttons - utilBtns.addEventListener('click', function (e) { - var targetClass = e.target.className; - if (targetClass.indexOf('epiceditor-toggle-preview-btn') > -1) { - self.preview(); - } - else if (targetClass.indexOf('epiceditor-toggle-edit-btn') > -1) { - self.edit(); - } - else if (targetClass.indexOf('epiceditor-fullscreen-btn') > -1) { - self._goFullscreen(fsElement); - } - }); - - // Sets up the NATIVE fullscreen editor/previewer for WebKit - if (nativeFsWebkit) { - document.addEventListener('webkitfullscreenchange', function () { - if (!document.webkitIsFullScreen && self._eeState.fullscreen) { - self._exitFullscreen(fsElement); - } - }, false); - } - else if (nativeFsMoz) { - document.addEventListener('mozfullscreenchange', function () { - if (!document.mozFullScreen && self._eeState.fullscreen) { - self._exitFullscreen(fsElement); - } - }, false); - } - else if (nativeFsW3C) { - document.addEventListener('fullscreenchange', function () { - if (document.fullscreenElement == null && self._eeState.fullscreen) { - self._exitFullscreen(fsElement); - } - }, false); - } - - // TODO: Move utilBar stuff into a utilBar setup function (_setupUtilBar) - utilBar = self.iframe.getElementById('epiceditor-utilbar'); - - // Hide it at first until they move their mouse - if (self.settings.button.bar !== true) { - utilBar.style.display = 'none'; - } - - utilBar.addEventListener('mouseover', function () { - if (utilBarTimer) { - clearTimeout(utilBarTimer); - } - }); - - function utilBarHandler(e) { - if (self.settings.button.bar !== "auto") { - return; - } - // Here we check if the mouse has moves more than 5px in any direction before triggering the mousemove code - // we do this for 2 reasons: - // 1. On Mac OS X lion when you scroll and it does the iOS like "jump" when it hits the top/bottom of the page itll fire off - // a mousemove of a few pixels depending on how hard you scroll - // 2. We give a slight buffer to the user in case he barely touches his touchpad or mouse and not trigger the UI - if (Math.abs(mousePos.y - e.pageY) >= 5 || Math.abs(mousePos.x - e.pageX) >= 5) { - utilBar.style.display = 'block'; - // if we have a timer already running, kill it out - if (utilBarTimer) { - clearTimeout(utilBarTimer); - } - - // begin a new timer that hides our object after 1000 ms - utilBarTimer = window.setTimeout(function () { - utilBar.style.display = 'none'; - }, 1000); - } - mousePos = { y: e.pageY, x: e.pageX }; - } - - // Add keyboard shortcuts for convenience. - function shortcutHandler(e) { - if (e.keyCode == self.settings.shortcut.modifier) { isMod = true } // check for modifier press(default is alt key), save to var - if (e.keyCode == 17) { isCtrl = true } // check for ctrl/cmnd press, in order to catch ctrl/cmnd + s - - // Check for alt+p and make sure were not in fullscreen - default shortcut to switch to preview - if (isMod === true && e.keyCode == self.settings.shortcut.preview && !self.is('fullscreen')) { - e.preventDefault(); - if (self.is('edit') && self._previewEnabled) { - self.preview(); - } - else if (self._editEnabled) { - self.edit(); - } - } - // Check for alt+f - default shortcut to make editor fullscreen - if (isMod === true && e.keyCode == self.settings.shortcut.fullscreen && self._fullscreenEnabled) { - e.preventDefault(); - self._goFullscreen(fsElement); - } - - // Set the modifier key to false once *any* key combo is completed - // or else, on Windows, hitting the alt key will lock the isMod state to true (ticket #133) - if (isMod === true && e.keyCode !== self.settings.shortcut.modifier) { - isMod = false; - } - - // When a user presses "esc", revert everything! - if (e.keyCode == 27 && self.is('fullscreen')) { - self._exitFullscreen(fsElement); - } - - // Check for ctrl + s (since a lot of people do it out of habit) and make it do nothing - if (isCtrl === true && e.keyCode == 83) { - self.save(); - e.preventDefault(); - isCtrl = false; - } - - // Do the same for Mac now (metaKey == cmd). - if (e.metaKey && e.keyCode == 83) { - self.save(); - e.preventDefault(); - } - - } - - function shortcutUpHandler(e) { - if (e.keyCode == self.settings.shortcut.modifier) { isMod = false } - if (e.keyCode == 17) { isCtrl = false } - } - - function pasteHandler(e) { - var content; - if (e.clipboardData) { - //FF 22, Webkit, "standards" - e.preventDefault(); - content = e.clipboardData.getData("text/plain"); - self.editorIframeDocument.execCommand("insertText", false, content); - } - else if (window.clipboardData) { - //IE, "nasty" - e.preventDefault(); - content = window.clipboardData.getData("Text"); - content = content.replace(//g, '>'); - content = content.replace(/\n/g, '
'); - content = content.replace(/\r/g, ''); //fuck you, ie! - content = content.replace(/
\s/g, '
 ') - content = content.replace(/\s\s\s/g, '   ') - content = content.replace(/\s\s/g, '  ') - self.editorIframeDocument.selection.createRange().pasteHTML(content); - } - } - - // Hide and show the util bar based on mouse movements - eventableIframes = [self.previewerIframeDocument, self.editorIframeDocument]; - - for (i = 0; i < eventableIframes.length; i++) { - eventableIframes[i].addEventListener('mousemove', function (e) { - utilBarHandler(e); - }); - eventableIframes[i].addEventListener('scroll', function (e) { - utilBarHandler(e); - }); - eventableIframes[i].addEventListener('keyup', function (e) { - shortcutUpHandler(e); - }); - eventableIframes[i].addEventListener('keydown', function (e) { - shortcutHandler(e); - }); - eventableIframes[i].addEventListener('paste', function (e) { - pasteHandler(e); - }); - } - - // Save the document every 100ms by default - // TODO: Move into autosave setup function (_setupAutoSave) - if (self.settings.file.autoSave) { - self._saveIntervalTimer = window.setInterval(function () { - if (!self._canSave) { - return; - } - self.save(false, true); - }, self.settings.file.autoSave); - } - - // Update a textarea automatically if a textarea is given so you don't need - // AJAX to submit a form and instead fall back to normal form behavior - if (self.settings.textarea) { - self._setupTextareaSync(); - } - - window.addEventListener('resize', function () { - // If NOT webkit, and in fullscreen, we need to account for browser resizing - // we don't care about webkit because you can't resize in webkit's fullscreen - if (self.is('fullscreen')) { - _applyStyles(self.iframeElement, { - 'width': window.outerWidth + 'px' - , 'height': window.innerHeight + 'px' - }); - - _applyStyles(self.element, { - 'height': window.innerHeight + 'px' - }); - - _applyStyles(self.previewerIframe, { - 'width': window.outerWidth / 2 + 'px' - , 'height': window.innerHeight + 'px' - }); - - _applyStyles(self.editorIframe, { - 'width': window.outerWidth / 2 + 'px' - , 'height': window.innerHeight + 'px' - }); - } - // Makes the editor support fluid width when not in fullscreen mode - else if (!self.is('fullscreen')) { - self.reflow(); - } - }); - - // Set states before flipping edit and preview modes - self._eeState.loaded = true; - self._eeState.unloaded = false; - - if (self.is('preview')) { - self.preview(); - } - else { - self.edit(); - } - - self.iframe.close(); - self._eeState.startup = false; - - if (self.settings.autogrow) { - self._fixScrollbars(); - - boundAutogrow = function () { - setTimeout(function () { - self._autogrow(); - }, 1); - }; - - //for if autosave is disabled or very slow - ['keydown', 'keyup', 'paste', 'cut'].forEach(function (ev) { - self.getElement('editor').addEventListener(ev, boundAutogrow); - }); - - self.on('__update', boundAutogrow); - self.on('edit', function () { - setTimeout(boundAutogrow, 50) - }); - self.on('preview', function () { - setTimeout(boundAutogrow, 50) - }); - - //for browsers that have rendering delays - setTimeout(boundAutogrow, 50); - boundAutogrow(); - } - - // The callback and call are the same thing, but different ways to access them - callback.call(this); - this.emit('load'); - return this; - } - - EpicEditor.prototype._setupTextareaSync = function () { - var self = this - , textareaFileName = self.settings.file.name - , _syncTextarea; - - // Even if autoSave is false, we want to make sure to keep the textarea synced - // with the editor's content. One bad thing about this tho is that we're - // creating two timers now in some configurations. We keep the textarea synced - // by saving and opening the textarea content from the draft file storage. - self._textareaSaveTimer = window.setInterval(function () { - if (!self._canSave) { - return; - } - self.save(true); - }, 100); - - _syncTextarea = function () { - // TODO: Figure out root cause for having to do this ||. - // This only happens for draft files. Probably has something to do with - // the fact draft files haven't been saved by the time this is called. - // TODO: Add test for this case. - self._textareaElement.value = self.exportFile(textareaFileName, 'text', true) || self.settings.file.defaultContent; - } - - if (typeof self.settings.textarea == 'string') { - self._textareaElement = document.getElementById(self.settings.textarea); - } - else if (typeof self.settings.textarea == 'object') { - self._textareaElement = self.settings.textarea; - } - - // On page load, if there's content in the textarea that means one of two - // different things: - // - // 1. The editor didn't load and the user was writing in the textarea and - // now he refreshed the page or the JS loaded and the textarea now has - // content. If this is the case the user probably expects his content is - // moved into the editor and not lose what he typed. - // - // 2. The developer put content in the textarea from some server side - // code. In this case, the textarea will take precedence. - // - // If the developer wants drafts to be recoverable they should check if - // the local file in localStorage's modified date is newer than the server. - if (self._textareaElement.value !== '') { - self.importFile(textareaFileName, self._textareaElement.value); - - // manually save draft after import so there is no delay between the - // import and exporting in _syncTextarea. Without this, _syncTextarea - // will pull the saved data from localStorage which will be <=100ms old. - self.save(true); - } - - // Update the textarea on load and pull from drafts - _syncTextarea(); - - // Make sure to keep it updated - self.on('__update', _syncTextarea); - } - - /** - * Will NOT focus the editor if the editor is still starting up AND - * focusOnLoad is set to false. This allows you to place this in code that - * gets fired during .load() without worrying about it overriding the user's - * option. For example use cases see preview() and edit(). - * @returns {undefined} - */ - - // Prevent focus when the user sets focusOnLoad to false by checking if the - // editor is starting up AND if focusOnLoad is true - EpicEditor.prototype._focusExceptOnLoad = function () { - var self = this; - if ((self._eeState.startup && self.settings.focusOnLoad) || !self._eeState.startup) { - self.focus(); - } - } - - /** - * Will remove the editor, but not offline files - * @returns {object} EpicEditor will be returned - */ - EpicEditor.prototype.unload = function (callback) { - - // Make sure the editor isn't already unloaded. - if (this.is('unloaded')) { - throw new Error('Editor isn\'t loaded'); - } - - var self = this - , editor = window.parent.document.getElementById(self._instanceId); - - editor.parentNode.removeChild(editor); - self._eeState.loaded = false; - self._eeState.unloaded = true; - callback = callback || function () {}; - - if (self.settings.textarea) { - self._textareaElement.value = ""; - self.removeListener('__update'); - } - - if (self._saveIntervalTimer) { - window.clearInterval(self._saveIntervalTimer); - } - if (self._textareaSaveTimer) { - window.clearInterval(self._textareaSaveTimer); - } - - callback.call(this); - self.emit('unload'); - return self; - } - - /** - * reflow allows you to dynamically re-fit the editor in the parent without - * having to unload and then reload the editor again. - * - * reflow will also emit a `reflow` event and will return the new dimensions. - * If it's called without params it'll return the new width and height and if - * it's called with just width or just height it'll just return the width or - * height. It's returned as an object like: { width: '100px', height: '1px' } - * - * @param {string|null} kind Can either be 'width' or 'height' or null - * if null, both the height and width will be resized - * @param {function} callback A function to fire after the reflow is finished. - * Will return the width / height in an obj as the first param of the callback. - * @returns {object} EpicEditor will be returned - */ - EpicEditor.prototype.reflow = function (kind, callback) { - var self = this - , widthDiff = _outerWidth(self.element) - self.element.offsetWidth - , heightDiff = _outerHeight(self.element) - self.element.offsetHeight - , elements = [self.iframeElement, self.editorIframe, self.previewerIframe] - , eventData = {} - , newWidth - , newHeight; - - if (typeof kind == 'function') { - callback = kind; - kind = null; - } - - if (!callback) { - callback = function () {}; - } - - for (var x = 0; x < elements.length; x++) { - if (!kind || kind == 'width') { - newWidth = self.element.offsetWidth - widthDiff + 'px'; - elements[x].style.width = newWidth; - self._eeState.reflowWidth = newWidth; - eventData.width = newWidth; - } - if (!kind || kind == 'height') { - newHeight = self.element.offsetHeight - heightDiff + 'px'; - elements[x].style.height = newHeight; - self._eeState.reflowHeight = newHeight - eventData.height = newHeight; - } - } - - self.emit('reflow', eventData); - callback.call(this, eventData); - return self; - } - - /** - * Will take the markdown and generate a preview view based on the theme - * @returns {object} EpicEditor will be returned - */ - EpicEditor.prototype.preview = function () { - var self = this - , x - , theme = self.settings.theme.preview - , anchors; - - _replaceClass(self.getElement('wrapper'), 'epiceditor-edit-mode', 'epiceditor-preview-mode'); - - // Check if no CSS theme link exists - if (!self.previewerIframeDocument.getElementById('theme')) { - _insertCSSLink(theme, self.previewerIframeDocument, 'theme'); - } - else if (self.previewerIframeDocument.getElementById('theme').name !== theme) { - self.previewerIframeDocument.getElementById('theme').href = theme; - } - - // Save a preview draft since it might not be saved to the real file yet - self.save(true); - - // Add the generated draft HTML into the previewer - self.previewer.innerHTML = self.exportFile(null, 'html', true); - - // Hide the editor and display the previewer - if (!self.is('fullscreen')) { - self.editorIframe.style.left = '-999999px'; - self.previewerIframe.style.left = ''; - self._eeState.preview = true; - self._eeState.edit = false; - self._focusExceptOnLoad(); - } - - self.emit('preview'); - return self; - } - - /** - * Helper to focus on the editor iframe. Will figure out which iframe to - * focus on based on which one is active and will handle the cross browser - * issues with focusing on the iframe vs the document body. - * @returns {object} EpicEditor will be returned - */ - EpicEditor.prototype.focus = function (pageload) { - var self = this - , isPreview = self.is('preview') - , focusElement = isPreview ? self.previewerIframeDocument.body - : self.editorIframeDocument.body; - - if (_isFirefox() && isPreview) { - focusElement = self.previewerIframe; - } - - focusElement.focus(); - return this; - } - - /** - * Puts the editor into fullscreen mode - * @returns {object} EpicEditor will be returned - */ - EpicEditor.prototype.enterFullscreen = function () { - if (this.is('fullscreen')) { return this; } - this._goFullscreen(this.iframeElement); - return this; - } - - /** - * Closes fullscreen mode if opened - * @returns {object} EpicEditor will be returned - */ - EpicEditor.prototype.exitFullscreen = function () { - if (!this.is('fullscreen')) { return this; } - this._exitFullscreen(this.iframeElement); - return this; - } - - /** - * Hides the preview and shows the editor again - * @returns {object} EpicEditor will be returned - */ - EpicEditor.prototype.edit = function () { - var self = this; - _replaceClass(self.getElement('wrapper'), 'epiceditor-preview-mode', 'epiceditor-edit-mode'); - self._eeState.preview = false; - self._eeState.edit = true; - self.editorIframe.style.left = ''; - self.previewerIframe.style.left = '-999999px'; - self._focusExceptOnLoad(); - self.emit('edit'); - return this; - } - - /** - * Grabs a specificed HTML node. Use it as a shortcut to getting the iframe contents - * @param {String} name The name of the node (can be document, body, editor, previewer, or wrapper) - * @returns {Object|Null} - */ - EpicEditor.prototype.getElement = function (name) { - var available = { - "container": this.element - , "wrapper": this.iframe.getElementById('epiceditor-wrapper') - , "wrapperIframe": this.iframeElement - , "editor": this.editorIframeDocument - , "editorIframe": this.editorIframe - , "previewer": this.previewerIframeDocument - , "previewerIframe": this.previewerIframe - } - - // Check that the given string is a possible option and verify the editor isn't unloaded - // without this, you'd be given a reference to an object that no longer exists in the DOM - if (!available[name] || this.is('unloaded')) { - return null; - } - else { - return available[name]; - } - } - - /** - * Returns a boolean of each "state" of the editor. For example "editor.is('loaded')" // returns true/false - * @param {String} what the state you want to check for - * @returns {Boolean} - */ - EpicEditor.prototype.is = function (what) { - var self = this; - switch (what) { - case 'loaded': - return self._eeState.loaded; - case 'unloaded': - return self._eeState.unloaded - case 'preview': - return self._eeState.preview - case 'edit': - return self._eeState.edit; - case 'fullscreen': - return self._eeState.fullscreen; - // TODO: This "works", but the tests are saying otherwise. Come back to this - // and figure out how to fix it. - // case 'focused': - // return document.activeElement == self.iframeElement; - default: - return false; - } - } - - /** - * Opens a file - * @param {string} name The name of the file you want to open - * @returns {object} EpicEditor will be returned - */ - EpicEditor.prototype.open = function (name) { - var self = this - , defaultContent = self.settings.file.defaultContent - , fileObj; - name = name || self.settings.file.name; - self.settings.file.name = name; - if (this._storage[self.settings.localStorageName]) { - fileObj = self.exportFile(name); - if (fileObj !== undefined) { - _setText(self.editor, fileObj); - self.emit('read'); - } - else { - _setText(self.editor, defaultContent); - self.save(); // ensure a save - self.emit('create'); - } - self.previewer.innerHTML = self.exportFile(null, 'html'); - self.emit('open'); - } - return this; - } - - /** - * Saves content for offline use - * @returns {object} EpicEditor will be returned - */ - EpicEditor.prototype.save = function (_isPreviewDraft, _isAuto) { - var self = this - , storage - , isUpdate = false - , file = self.settings.file.name - , previewDraftName = '' - , data = this._storage[previewDraftName + self.settings.localStorageName] - , content = _getText(this.editor); - - if (_isPreviewDraft) { - previewDraftName = self._previewDraftLocation; - } - - // This could have been false but since we're manually saving - // we know it's save to start autoSaving again - this._canSave = true; - - // Guard against storage being wiped out without EpicEditor knowing - // TODO: Emit saving error - storage seems to have been wiped - if (data) { - storage = JSON.parse(this._storage[previewDraftName + self.settings.localStorageName]); - - // If the file doesn't exist we need to create it - if (storage[file] === undefined) { - storage[file] = self._defaultFileSchema(); - } - - // If it does, we need to check if the content is different and - // if it is, send the update event and update the timestamp - else if (content !== storage[file].content) { - storage[file].modified = new Date(); - isUpdate = true; - } - //don't bother autosaving if the content hasn't actually changed - else if (_isAuto) { - return; - } - - storage[file].content = content; - this._storage[previewDraftName + self.settings.localStorageName] = JSON.stringify(storage); - - // After the content is actually changed, emit update so it emits the updated content - if (isUpdate) { - self.emit('update'); - // Emit a private update event so it can't get accidentally removed - self.emit('__update'); - } - - if (_isAuto) { - this.emit('autosave'); - } - else if (!_isPreviewDraft) { - this.emit('save'); - } - } - - return this; - } - - /** - * Removes a page - * @param {string} name The name of the file you want to remove from localStorage - * @returns {object} EpicEditor will be returned - */ - EpicEditor.prototype.remove = function (name) { - var self = this - , s; - name = name || self.settings.file.name; - - // If you're trying to delete a page you have open, block saving - if (name == self.settings.file.name) { - self._canSave = false; - } - - s = JSON.parse(this._storage[self.settings.localStorageName]); - delete s[name]; - this._storage[self.settings.localStorageName] = JSON.stringify(s); - this.emit('remove'); - return this; - }; - - /** - * Renames a file - * @param {string} oldName The old file name - * @param {string} newName The new file name - * @returns {object} EpicEditor will be returned - */ - EpicEditor.prototype.rename = function (oldName, newName) { - var self = this - , s = JSON.parse(this._storage[self.settings.localStorageName]); - s[newName] = s[oldName]; - delete s[oldName]; - this._storage[self.settings.localStorageName] = JSON.stringify(s); - self.open(newName); - return this; - }; - - /** - * Imports a file and it's contents and opens it - * @param {string} name The name of the file you want to import (will overwrite existing files!) - * @param {string} content Content of the file you want to import - * @param {string} kind The kind of file you want to import (TBI) - * @param {object} meta Meta data you want to save with your file. - * @returns {object} EpicEditor will be returned - */ - EpicEditor.prototype.importFile = function (name, content, kind, meta) { - var self = this - , isNew = false; - - name = name || self.settings.file.name; - content = content || ''; - kind = kind || 'md'; - meta = meta || {}; - - if (JSON.parse(this._storage[self.settings.localStorageName])[name] === undefined) { - isNew = true; - } - - // Set our current file to the new file and update the content - self.settings.file.name = name; - _setText(self.editor, content); - - if (isNew) { - self.emit('create'); - } - - self.save(); - - if (self.is('fullscreen')) { - self.preview(); - } - - //firefox has trouble with importing and working out the size right away - if (self.settings.autogrow) { - setTimeout(function () { - self._autogrow(); - }, 50); - } - - return this; - }; - - /** - * Gets the local filestore - * @param {string} name Name of the file in the store - * @returns {object|undefined} the local filestore, or a specific file in the store, if a name is given - */ - EpicEditor.prototype._getFileStore = function (name, _isPreviewDraft) { - var previewDraftName = '' - , store; - if (_isPreviewDraft) { - previewDraftName = this._previewDraftLocation; - } - store = JSON.parse(this._storage[previewDraftName + this.settings.localStorageName]); - if (name) { - return store[name]; - } - else { - return store; - } - } - - /** - * Exports a file as a string in a supported format - * @param {string} name Name of the file you want to export (case sensitive) - * @param {string} kind Kind of file you want the content in (currently supports html and text, default is the format the browser "wants") - * @returns {string|undefined} The content of the file in the content given or undefined if it doesn't exist - */ - EpicEditor.prototype.exportFile = function (name, kind, _isPreviewDraft) { - var self = this - , file - , content; - - name = name || self.settings.file.name; - kind = kind || 'text'; - - file = self._getFileStore(name, _isPreviewDraft); - - // If the file doesn't exist just return early with undefined - if (file === undefined) { - return; - } - - content = file.content; - - switch (kind) { - case 'html': - content = _sanitizeRawContent(content); - return self.settings.parser(content); - case 'text': - return _sanitizeRawContent(content); - case 'json': - file.content = _sanitizeRawContent(file.content); - return JSON.stringify(file); - case 'raw': - return content; - default: - return content; - } - } - - /** - * Gets the contents and metadata for files - * @param {string} name Name of the file whose data you want (case sensitive) - * @param {boolean} excludeContent whether the contents of files should be excluded - * @returns {object} An object with the names and data of every file, or just the data of one file if a name was given - */ - EpicEditor.prototype.getFiles = function (name, excludeContent) { - var file - , data = this._getFileStore(name); - - if (name) { - if (data !== undefined) { - if (excludeContent) { - delete data.content; - } - else { - data.content = _sanitizeRawContent(data.content); - } - } - return data; - } - else { - for (file in data) { - if (data.hasOwnProperty(file)) { - if (excludeContent) { - delete data[file].content; - } - else { - data[file].content = _sanitizeRawContent(data[file].content); - } - } - } - return data; - } - } - - // EVENTS - // TODO: Support for namespacing events like "preview.foo" - /** - * Sets up an event handler for a specified event - * @param {string} ev The event name - * @param {function} handler The callback to run when the event fires - * @returns {object} EpicEditor will be returned - */ - EpicEditor.prototype.on = function (ev, handler) { - var self = this; - if (!this.events[ev]) { - this.events[ev] = []; - } - this.events[ev].push(handler); - return self; - }; - - /** - * This will emit or "trigger" an event specified - * @param {string} ev The event name - * @param {any} data Any data you want to pass into the callback - * @returns {object} EpicEditor will be returned - */ - EpicEditor.prototype.emit = function (ev, data) { - var self = this - , x; - - data = data || self.getFiles(self.settings.file.name); - - if (!this.events[ev]) { - return; - } - - function invokeHandler(handler) { - handler.call(self, data); - } - - for (x = 0; x < self.events[ev].length; x++) { - invokeHandler(self.events[ev][x]); - } - - return self; - }; - - /** - * Will remove any listeners added from EpicEditor.on() - * @param {string} ev The event name - * @param {function} handler Handler to remove - * @returns {object} EpicEditor will be returned - */ - EpicEditor.prototype.removeListener = function (ev, handler) { - var self = this; - if (!handler) { - this.events[ev] = []; - return self; - } - if (!this.events[ev]) { - return self; - } - // Otherwise a handler and event exist, so take care of it - this.events[ev].splice(this.events[ev].indexOf(handler), 1); - return self; - } - - /** - * Handles autogrowing the editor - */ - EpicEditor.prototype._autogrow = function () { - var editorHeight - , newHeight - , minHeight - , maxHeight - , el - , style - , maxedOut = false; - - //autogrow in fullscreen is nonsensical - if (!this.is('fullscreen')) { - if (this.is('edit')) { - el = this.getElement('editor').documentElement; - } - else { - el = this.getElement('previewer').documentElement; - } - - editorHeight = _outerHeight(el); - newHeight = editorHeight; - - //handle minimum - minHeight = this.settings.autogrow.minHeight; - if (typeof minHeight === 'function') { - minHeight = minHeight(this); - } - - if (minHeight && newHeight < minHeight) { - newHeight = minHeight; - } - - //handle maximum - maxHeight = this.settings.autogrow.maxHeight; - if (typeof maxHeight === 'function') { - maxHeight = maxHeight(this); - } - - if (maxHeight && newHeight > maxHeight) { - newHeight = maxHeight; - maxedOut = true; - } - - if (maxedOut) { - this._fixScrollbars('auto'); - } else { - this._fixScrollbars('hidden'); - } - - //actual resize - if (newHeight != this.oldHeight) { - this.getElement('container').style.height = newHeight + 'px'; - this.reflow(); - if (this.settings.autogrow.scroll) { - window.scrollBy(0, newHeight - this.oldHeight); - } - this.oldHeight = newHeight; - } - } - } - - /** - * Shows or hides scrollbars based on the autogrow setting - * @param {string} forceSetting a value to force the overflow to - */ - EpicEditor.prototype._fixScrollbars = function (forceSetting) { - var setting; - if (this.settings.autogrow) { - setting = 'hidden'; - } - else { - setting = 'auto'; - } - setting = forceSetting || setting; - this.getElement('editor').documentElement.style.overflow = setting; - this.getElement('previewer').documentElement.style.overflow = setting; - } - - EpicEditor.version = '0.2.2'; - - // Used to store information to be shared across editors - EpicEditor._data = {}; - - window.EpicEditor = EpicEditor; -})(window); - -/** - * marked - a markdown parser - * Copyright (c) 2011-2013, Christopher Jeffrey. (MIT Licensed) - * https://github.com/chjj/marked - */ - -;(function() { - -/** - * Block-Level Grammar - */ - -var block = { - newline: /^\n+/, - code: /^( {4}[^\n]+\n*)+/, - fences: noop, - hr: /^( *[-*_]){3,} *(?:\n+|$)/, - heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/, - nptable: noop, - lheading: /^([^\n]+)\n *(=|-){3,} *\n*/, - blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/, - list: /^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/, - html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/, - def: /^ *\[([^\]]+)\]: *([^\s]+)(?: +["(]([^\n]+)[")])? *(?:\n+|$)/, - table: noop, - paragraph: /^([^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+\n*/, - text: /^[^\n]+/ -}; - -block.bullet = /(?:[*+-]|\d+\.)/; -block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/; -block.item = replace(block.item, 'gm') - (/bull/g, block.bullet) - (); - -block.list = replace(block.list) - (/bull/g, block.bullet) - ('hr', /\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/) - (); - -block._tag = '(?!(?:' - + '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+(?!:/|@)\\b'; - -block.html = replace(block.html) - ('comment', //) - ('closed', /<(tag)[\s\S]+?<\/\1>/) - ('closing', /])*?>/) - (/tag/g, block._tag) - (); - -block.paragraph = replace(block.paragraph) - ('hr', block.hr) - ('heading', block.heading) - ('lheading', block.lheading) - ('blockquote', block.blockquote) - ('tag', '<' + block._tag) - ('def', block.def) - (); - -/** - * Normal Block Grammar - */ - -block.normal = merge({}, block); - -/** - * GFM Block Grammar - */ - -block.gfm = merge({}, block.normal, { - fences: /^ *(`{3,}|~{3,}) *(\w+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/, - paragraph: /^/ -}); - -block.gfm.paragraph = replace(block.paragraph) - ('(?!', '(?!' + block.gfm.fences.source.replace('\\1', '\\2') + '|') - (); - -/** - * GFM + Tables Block Grammar - */ - -block.tables = merge({}, block.gfm, { - nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/, - table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/ -}); - -/** - * Block Lexer - */ - -function Lexer(options) { - this.tokens = []; - this.tokens.links = {}; - this.options = options || marked.defaults; - this.rules = block.normal; - - if (this.options.gfm) { - if (this.options.tables) { - this.rules = block.tables; - } else { - this.rules = block.gfm; - } - } -} - -/** - * Expose Block Rules - */ - -Lexer.rules = block; - -/** - * Static Lex Method - */ - -Lexer.lex = function(src, options) { - var lexer = new Lexer(options); - return lexer.lex(src); -}; - -/** - * Preprocessing - */ - -Lexer.prototype.lex = function(src) { - src = src - .replace(/\r\n|\r/g, '\n') - .replace(/\t/g, ' ') - .replace(/\u00a0/g, ' ') - .replace(/\u2424/g, '\n'); - - return this.token(src, true); -}; - -/** - * Lexing - */ - -Lexer.prototype.token = function(src, top) { - var src = src.replace(/^ +$/gm, '') - , next - , loose - , cap - , item - , space - , i - , l; - - while (src) { - // newline - if (cap = this.rules.newline.exec(src)) { - src = src.substring(cap[0].length); - if (cap[0].length > 1) { - this.tokens.push({ - type: 'space' - }); - } - } - - // code - if (cap = this.rules.code.exec(src)) { - src = src.substring(cap[0].length); - cap = cap[0].replace(/^ {4}/gm, ''); - this.tokens.push({ - type: 'code', - text: !this.options.pedantic - ? cap.replace(/\n+$/, '') - : cap - }); - continue; - } - - // fences (gfm) - if (cap = this.rules.fences.exec(src)) { - src = src.substring(cap[0].length); - this.tokens.push({ - type: 'code', - lang: cap[2], - text: cap[3] - }); - continue; - } - - // heading - if (cap = this.rules.heading.exec(src)) { - src = src.substring(cap[0].length); - this.tokens.push({ - type: 'heading', - depth: cap[1].length, - text: cap[2] - }); - continue; - } - - // table no leading pipe (gfm) - if (top && (cap = this.rules.nptable.exec(src))) { - src = src.substring(cap[0].length); - - item = { - type: 'table', - header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */), - align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), - cells: cap[3].replace(/\n$/, '').split('\n') - }; - - for (i = 0; i < item.align.length; i++) { - if (/^ *-+: *$/.test(item.align[i])) { - item.align[i] = 'right'; - } else if (/^ *:-+: *$/.test(item.align[i])) { - item.align[i] = 'center'; - } else if (/^ *:-+ *$/.test(item.align[i])) { - item.align[i] = 'left'; - } else { - item.align[i] = null; - } - } - - for (i = 0; i < item.cells.length; i++) { - item.cells[i] = item.cells[i].split(/ *\| */); - } - - this.tokens.push(item); - - continue; - } - - // lheading - if (cap = this.rules.lheading.exec(src)) { - src = src.substring(cap[0].length); - this.tokens.push({ - type: 'heading', - depth: cap[2] === '=' ? 1 : 2, - text: cap[1] - }); - continue; - } - - // hr - if (cap = this.rules.hr.exec(src)) { - src = src.substring(cap[0].length); - this.tokens.push({ - type: 'hr' - }); - continue; - } - - // blockquote - if (cap = this.rules.blockquote.exec(src)) { - src = src.substring(cap[0].length); - - this.tokens.push({ - type: 'blockquote_start' - }); - - cap = cap[0].replace(/^ *> ?/gm, ''); - - // Pass `top` to keep the current - // "toplevel" state. This is exactly - // how markdown.pl works. - this.token(cap, top); - - this.tokens.push({ - type: 'blockquote_end' - }); - - continue; - } - - // list - if (cap = this.rules.list.exec(src)) { - src = src.substring(cap[0].length); - - this.tokens.push({ - type: 'list_start', - ordered: isFinite(cap[2]) - }); - - // Get each top-level item. - cap = cap[0].match(this.rules.item); - - next = false; - l = cap.length; - i = 0; - - for (; i < l; i++) { - item = cap[i]; - - // Remove the list item's bullet - // so it is seen as the next token. - space = item.length; - item = item.replace(/^ *([*+-]|\d+\.) +/, ''); - - // Outdent whatever the - // list item contains. Hacky. - if (~item.indexOf('\n ')) { - space -= item.length; - item = !this.options.pedantic - ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') - : item.replace(/^ {1,4}/gm, ''); - } - - // Determine whether item is loose or not. - // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/ - // for discount behavior. - loose = next || /\n\n(?!\s*$)/.test(item); - if (i !== l - 1) { - next = item[item.length-1] === '\n'; - if (!loose) loose = next; - } - - this.tokens.push({ - type: loose - ? 'loose_item_start' - : 'list_item_start' - }); - - // Recurse. - this.token(item, false); - - this.tokens.push({ - type: 'list_item_end' - }); - } - - this.tokens.push({ - type: 'list_end' - }); - - continue; - } - - // html - if (cap = this.rules.html.exec(src)) { - src = src.substring(cap[0].length); - this.tokens.push({ - type: this.options.sanitize - ? 'paragraph' - : 'html', - pre: cap[1] === 'pre', - text: cap[0] - }); - continue; - } - - // def - if (top && (cap = this.rules.def.exec(src))) { - src = src.substring(cap[0].length); - this.tokens.links[cap[1].toLowerCase()] = { - href: cap[2], - title: cap[3] - }; - continue; - } - - // table (gfm) - if (top && (cap = this.rules.table.exec(src))) { - src = src.substring(cap[0].length); - - item = { - type: 'table', - header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */), - align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), - cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n') - }; - - for (i = 0; i < item.align.length; i++) { - if (/^ *-+: *$/.test(item.align[i])) { - item.align[i] = 'right'; - } else if (/^ *:-+: *$/.test(item.align[i])) { - item.align[i] = 'center'; - } else if (/^ *:-+ *$/.test(item.align[i])) { - item.align[i] = 'left'; - } else { - item.align[i] = null; - } - } - - for (i = 0; i < item.cells.length; i++) { - item.cells[i] = item.cells[i] - .replace(/^ *\| *| *\| *$/g, '') - .split(/ *\| */); - } - - this.tokens.push(item); - - continue; - } - - // top-level paragraph - if (top && (cap = this.rules.paragraph.exec(src))) { - src = src.substring(cap[0].length); - this.tokens.push({ - type: 'paragraph', - text: cap[0] - }); - continue; - } - - // text - if (cap = this.rules.text.exec(src)) { - // Top-level should never reach here. - src = src.substring(cap[0].length); - this.tokens.push({ - type: 'text', - text: cap[0] - }); - continue; - } - - if (src) { - throw new - Error('Infinite loop on byte: ' + src.charCodeAt(0)); - } - } - - return this.tokens; -}; - -/** - * Inline-Level Grammar - */ - -var inline = { - escape: /^\\([\\`*{}\[\]()#+\-.!_>|])/, - autolink: /^<([^ >]+(@|:\/)[^ >]+)>/, - url: noop, - tag: /^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/, - link: /^!?\[(inside)\]\(href\)/, - reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/, - nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/, - strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/, - em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/, - code: /^(`+)([\s\S]*?[^`])\1(?!`)/, - br: /^ {2,}\n(?!\s*$)/, - del: noop, - text: /^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/; - -inline.link = replace(inline.link) - ('inside', inline._inside) - ('href', inline._href) - (); - -inline.reflink = replace(inline.reflink) - ('inside', inline._inside) - (); - -/** - * Normal Inline Grammar - */ - -inline.normal = merge({}, inline); - -/** - * Pedantic Inline Grammar - */ - -inline.pedantic = merge({}, inline.normal, { - strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/, - em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/ -}); - -/** - * GFM Inline Grammar - */ - -inline.gfm = merge({}, inline.normal, { - escape: replace(inline.escape)('])', '~])')(), - url: /^(https?:\/\/[^\s]+[^.,:;"')\]\s])/, - del: /^~{2,}([\s\S]+?)~{2,}/, - text: replace(inline.text) - (']|', '~]|') - ('|', '|https?://|') - () -}); - -/** - * GFM + Line Breaks Inline Grammar - */ - -inline.breaks = merge({}, inline.gfm, { - br: replace(inline.br)('{2,}', '*')(), - text: replace(inline.gfm.text)('{2,}', '*')() -}); - -/** - * Inline Lexer & Compiler - */ - -function InlineLexer(links, options) { - this.options = options || marked.defaults; - this.links = links; - this.rules = inline.normal; - - if (!this.links) { - throw new - Error('Tokens array requires a `links` property.'); - } - - if (this.options.gfm) { - if (this.options.breaks) { - this.rules = inline.breaks; - } else { - this.rules = inline.gfm; - } - } else if (this.options.pedantic) { - this.rules = inline.pedantic; - } -} - -/** - * Expose Inline Rules - */ - -InlineLexer.rules = inline; - -/** - * Static Lexing/Compiling Method - */ - -InlineLexer.output = function(src, links, opt) { - var inline = new InlineLexer(links, opt); - return inline.output(src); -}; - -/** - * Lexing/Compiling - */ - -InlineLexer.prototype.output = function(src) { - var out = '' - , link - , text - , href - , cap; - - while (src) { - // escape - if (cap = this.rules.escape.exec(src)) { - src = src.substring(cap[0].length); - out += cap[1]; - continue; - } - - // autolink - if (cap = this.rules.autolink.exec(src)) { - src = src.substring(cap[0].length); - if (cap[2] === '@') { - text = cap[1][6] === ':' - ? this.mangle(cap[1].substring(7)) - : this.mangle(cap[1]); - href = this.mangle('mailto:') + text; - } else { - text = escape(cap[1]); - href = text; - } - out += '' - + text - + ''; - continue; - } - - // url (gfm) - if (cap = this.rules.url.exec(src)) { - src = src.substring(cap[0].length); - text = escape(cap[1]); - href = text; - out += '' - + text - + ''; - continue; - } - - // tag - if (cap = this.rules.tag.exec(src)) { - src = src.substring(cap[0].length); - out += this.options.sanitize - ? escape(cap[0]) - : cap[0]; - continue; - } - - // link - if (cap = this.rules.link.exec(src)) { - src = src.substring(cap[0].length); - out += this.outputLink(cap, { - href: cap[2], - title: cap[3] - }); - continue; - } - - // reflink, nolink - if ((cap = this.rules.reflink.exec(src)) - || (cap = this.rules.nolink.exec(src))) { - src = src.substring(cap[0].length); - link = (cap[2] || cap[1]).replace(/\s+/g, ' '); - link = this.links[link.toLowerCase()]; - if (!link || !link.href) { - out += cap[0][0]; - src = cap[0].substring(1) + src; - continue; - } - out += this.outputLink(cap, link); - continue; - } - - // strong - if (cap = this.rules.strong.exec(src)) { - src = src.substring(cap[0].length); - out += '' - + this.output(cap[2] || cap[1]) - + ''; - continue; - } - - // em - if (cap = this.rules.em.exec(src)) { - src = src.substring(cap[0].length); - out += '' - + this.output(cap[2] || cap[1]) - + ''; - continue; - } - - // code - if (cap = this.rules.code.exec(src)) { - src = src.substring(cap[0].length); - out += '' - + escape(cap[2], true) - + ''; - continue; - } - - // br - if (cap = this.rules.br.exec(src)) { - src = src.substring(cap[0].length); - out += '
'; - continue; - } - - // del (gfm) - if (cap = this.rules.del.exec(src)) { - src = src.substring(cap[0].length); - out += '' - + this.output(cap[1]) - + ''; - continue; - } - - // text - if (cap = this.rules.text.exec(src)) { - src = src.substring(cap[0].length); - out += escape(cap[0]); - continue; - } - - if (src) { - throw new - Error('Infinite loop on byte: ' + src.charCodeAt(0)); - } - } - - return out; -}; - -/** - * Compile Link - */ - -InlineLexer.prototype.outputLink = function(cap, link) { - if (cap[0][0] !== '!') { - return '' - + this.output(cap[1]) - + ''; - } else { - return ''
-      + escape(cap[1])
-      + ''; - } -}; - -/** - * Mangle Links - */ - -InlineLexer.prototype.mangle = function(text) { - var out = '' - , l = text.length - , i = 0 - , ch; - - for (; i < l; i++) { - ch = text.charCodeAt(i); - if (Math.random() > 0.5) { - ch = 'x' + ch.toString(16); - } - out += '&#' + ch + ';'; - } - - return out; -}; - -/** - * Parsing & Compiling - */ - -function Parser(options) { - this.tokens = []; - this.token = null; - this.options = options || marked.defaults; -} - -/** - * Static Parse Method - */ - -Parser.parse = function(src, options) { - var parser = new Parser(options); - return parser.parse(src); -}; - -/** - * Parse Loop - */ - -Parser.prototype.parse = function(src) { - this.inline = new InlineLexer(src.links, this.options); - this.tokens = src.reverse(); - - var out = ''; - while (this.next()) { - out += this.tok(); - } - - return out; -}; - -/** - * Next Token - */ - -Parser.prototype.next = function() { - return this.token = this.tokens.pop(); -}; - -/** - * Preview Next Token - */ - -Parser.prototype.peek = function() { - return this.tokens[this.tokens.length-1] || 0; -}; - -/** - * Parse Text Tokens - */ - -Parser.prototype.parseText = function() { - var body = this.token.text; - - while (this.peek().type === 'text') { - body += '\n' + this.next().text; - } - - return this.inline.output(body); -}; - -/** - * Parse Current Token - */ - -Parser.prototype.tok = function() { - switch (this.token.type) { - case 'space': { - return ''; - } - case 'hr': { - return '
\n'; - } - case 'heading': { - return '' - + this.inline.output(this.token.text) - + '\n'; - } - case 'code': { - if (this.options.highlight) { - var code = this.options.highlight(this.token.text, this.token.lang); - if (code != null && code !== this.token.text) { - this.token.escaped = true; - this.token.text = code; - } - } - - if (!this.token.escaped) { - this.token.text = escape(this.token.text, true); - } - - return '
'
-        + this.token.text
-        + '
\n'; - } - case 'table': { - var body = '' - , heading - , i - , row - , cell - , j; - - // header - body += '\n\n'; - for (i = 0; i < this.token.header.length; i++) { - heading = this.inline.output(this.token.header[i]); - body += this.token.align[i] - ? '' + heading + '\n' - : '' + heading + '\n'; - } - body += '\n\n'; - - // body - body += '\n' - for (i = 0; i < this.token.cells.length; i++) { - row = this.token.cells[i]; - body += '\n'; - for (j = 0; j < row.length; j++) { - cell = this.inline.output(row[j]); - body += this.token.align[j] - ? '' + cell + '\n' - : '' + cell + '\n'; - } - body += '\n'; - } - body += '\n'; - - return '\n' - + body - + '
\n'; - } - case 'blockquote_start': { - var body = ''; - - while (this.next().type !== 'blockquote_end') { - body += this.tok(); - } - - return '
\n' - + body - + '
\n'; - } - case 'list_start': { - var type = this.token.ordered ? 'ol' : 'ul' - , body = ''; - - while (this.next().type !== 'list_end') { - body += this.tok(); - } - - return '<' - + type - + '>\n' - + body - + '\n'; - } - case 'list_item_start': { - var body = ''; - - while (this.next().type !== 'list_item_end') { - body += this.token.type === 'text' - ? this.parseText() - : this.tok(); - } - - return '
  • ' - + body - + '
  • \n'; - } - case 'loose_item_start': { - var body = ''; - - while (this.next().type !== 'list_item_end') { - body += this.tok(); - } - - return '
  • ' - + body - + '
  • \n'; - } - case 'html': { - return !this.token.pre && !this.options.pedantic - ? this.inline.output(this.token.text) - : this.token.text; - } - case 'paragraph': { - return '

    ' - + this.inline.output(this.token.text) - + '

    \n'; - } - case 'text': { - return '

    ' - + this.parseText() - + '

    \n'; - } - } -}; - -/** - * Helpers - */ - -function escape(html, encode) { - return html - .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); -} - -function replace(regex, opt) { - regex = regex.source; - opt = opt || ''; - return function self(name, val) { - if (!name) return new RegExp(regex, opt); - val = val.source || val; - val = val.replace(/(^|[^\[])\^/g, '$1'); - regex = regex.replace(name, val); - return self; - }; -} - -function noop() {} -noop.exec = noop; - -function merge(obj) { - var i = 1 - , target - , key; - - for (; i < arguments.length; i++) { - target = arguments[i]; - for (key in target) { - if (Object.prototype.hasOwnProperty.call(target, key)) { - obj[key] = target[key]; - } - } - } - - return obj; -} - -/** - * Marked - */ - -function marked(src, opt) { - try { - return Parser.parse(Lexer.lex(src, opt), opt); - } catch (e) { - e.message += '\nPlease report this to https://github.com/chjj/marked.'; - if ((opt || marked.defaults).silent) { - return 'An error occured:\n' + e.message; - } - throw e; - } -} - -/** - * Options - */ - -marked.options = -marked.setOptions = function(opt) { - marked.defaults = opt; - return marked; -}; - -marked.defaults = { - gfm: true, - tables: true, - breaks: false, - pedantic: false, - sanitize: false, - silent: false, - highlight: null -}; - -/** - * Expose - */ - -marked.Parser = Parser; -marked.parser = Parser.parse; - -marked.Lexer = Lexer; -marked.lexer = Lexer.lex; - -marked.InlineLexer = InlineLexer; -marked.inlineLexer = InlineLexer.output; - -marked.parse = marked; - -if (typeof module !== 'undefined') { - module.exports = marked; -} else if (typeof define === 'function' && define.amd) { - define(function() { return marked; }); -} else { - this.marked = marked; -} - -}).call(function() { - return this || (typeof window !== 'undefined' ? window : global); -}()); diff --git a/webcit/epic/js/epiceditor.min.js b/webcit/epic/js/epiceditor.min.js deleted file mode 100644 index e66402565..000000000 --- a/webcit/epic/js/epiceditor.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/** - * EpicEditor - An Embeddable JavaScript Markdown Editor (https://github.com/OscarGodson/EpicEditor) - * Copyright (c) 2011-2012, Oscar Godson. (MIT Licensed) - */(function(e,t){function n(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])}function r(e,t){for(var n in t)t.hasOwnProperty(n)&&(e.style[n]=t[n])}function i(t,n){var r=t,i=null;return e.getComputedStyle?i=document.defaultView.getComputedStyle(r,null).getPropertyValue(n):r.currentStyle&&(i=r.currentStyle[n]),i}function s(e,t,n){var s={},o;if(t==="save"){for(o in n)n.hasOwnProperty(o)&&(s[o]=i(e,o));r(e,n)}else t==="apply"&&r(e,n);return s}function o(e){var t=parseInt(i(e,"border-left-width"),10)+parseInt(i(e,"border-right-width"),10),n=parseInt(i(e,"padding-left"),10)+parseInt(i(e,"padding-right"),10),r=e.offsetWidth,s;return isNaN(t)&&(t=0),s=t+n+r,s}function u(e){var t=parseInt(i(e,"border-top-width"),10)+parseInt(i(e,"border-bottom-width"),10),n=parseInt(i(e,"padding-top"),10)+parseInt(i(e,"padding-bottom"),10),r=parseInt(i(e,"height"),10),s;return isNaN(t)&&(t=0),s=t+n+r,s}function a(e,t,r){r=r||"";var i=t.getElementsByTagName("head")[0],s=t.createElement("link");n(s,{type:"text/css",id:r,rel:"stylesheet",href:e,name:e,media:"screen"}),i.appendChild(s)}function f(e,t,n){e.className=e.className.replace(t,n)}function l(e){return e.contentDocument||e.contentWindow.document}function c(e){var t;return typeof document.body.innerText=="string"?t=e.innerText:(t=e.innerHTML.replace(/
    /gi,"\n"),t=t.replace(/<(?:.|\n)*?>/gm,""),t=t.replace(/</gi,"<"),t=t.replace(/>/gi,">")),t}function h(e,t){return t=t.replace(//g,">"),t=t.replace(/\n/g,"
    "),t=t.replace(/
    \s/g,"
     "),t=t.replace(/\s\s\s/g,"   "),t=t.replace(/\s\s/g,"  "),t=t.replace(/^ /," "),e.innerHTML=t,!0}function p(e){return e.replace(/\u00a0/g," ").replace(/ /g," ")}function d(){var e=-1,t=navigator.userAgent,n;return navigator.appName=="Microsoft Internet Explorer"&&(n=/MSIE ([0-9]{1,}[\.0-9]{0,})/,n.exec(t)!=null&&(e=parseFloat(RegExp.$1,10))),e}function v(){var t=e.navigator;return t.userAgent.indexOf("Safari")>-1&&t.userAgent.indexOf("Chrome")==-1}function m(){var t=e.navigator;return t.userAgent.indexOf("Firefox")>-1&&t.userAgent.indexOf("Seamonkey")==-1}function g(e){var t={};return e&&t.toString.call(e)==="[object Function]"}function y(){var e=arguments[0]||{},n=1,r=arguments.length,i=!1,s,o,u,a;typeof e=="boolean"&&(i=e,e=arguments[1]||{},n=2),typeof e!="object"&&!g(e)&&(e={}),r===n&&(e=this,--n);for(;n=5||Math.abs(g.x-t.pageX)>=5)h.style.display="block",p&&clearTimeout(p),p=e.setTimeout(function(){h.style.display="none"},1e3);g={y:t.pageY,x:t.pageX}}function M(e){e.keyCode==n.settings.shortcut.modifier&&(N=!0),e.keyCode==17&&(C=!0),N===!0&&e.keyCode==n.settings.shortcut.preview&&!n.is("fullscreen")&&(e.preventDefault(),n.is("edit")&&n._previewEnabled?n.preview():n._editEnabled&&n.edit()),N===!0&&e.keyCode==n.settings.shortcut.fullscreen&&n._fullscreenEnabled&&(e.preventDefault(),n._goFullscreen(T)),N===!0&&e.keyCode!==n.settings.shortcut.modifier&&(N=!1),e.keyCode==27&&n.is("fullscreen")&&n._exitFullscreen(T),C===!0&&e.keyCode==83&&(n.save(),e.preventDefault(),C=!1),e.metaKey&&e.keyCode==83&&(n.save(),e.preventDefault())}function _(e){e.keyCode==n.settings.shortcut.modifier&&(N=!1),e.keyCode==17&&(C=!1)}function D(t){var r;t.clipboardData?(t.preventDefault(),r=t.clipboardData.getData("text/plain"),n.editorIframeDocument.execCommand("insertText",!1,r)):e.clipboardData&&(t.preventDefault(),r=e.clipboardData.getData("Text"),r=r.replace(//g,">"),r=r.replace(/\n/g,"
    "),r=r.replace(/\r/g,""),r=r.replace(/
    \s/g,"
     "),r=r.replace(/\s\s\s/g,"   "),r=r.replace(/\s\s/g,"  "),n.editorIframeDocument.selection.createRange().pasteHTML(r))}if(this.is("loaded"))return this;var n=this,o,u,f,c,h,p,m,g={y:-1,x:-1},y,b,w=!1,E=!1,S=!1,x=!1,T,N=!1,C=!1,k,L,A;n._eeState.startup=!0,n.settings.useNativeFullscreen&&(E=document.body.webkitRequestFullScreen?!0:!1,S=document.body.mozRequestFullScreen?!0:!1,x=document.body.requestFullscreen?!0:!1,w=E||S||x),v()&&(w=!1,E=!1),!n.is("edit")&&!n.is("preview")&&(n._eeState.edit=!0),t=t||function(){},o={chrome:'
    '+(n._previewEnabled?' ':"")+(n._editEnabled?' ':"")+(n._fullscreenEnabled?'':"")+"
    "+"
    ",previewer:'
    ',editor:""},n.element.innerHTML='',n.element.style.height=n.element.offsetHeight+"px",u=document.getElementById(n._instanceId),n.iframeElement=u,n.iframe=l(u),n.iframe.open(),n.iframe.write(o.chrome),n.editorIframe=n.iframe.getElementById("epiceditor-editor-frame"),n.previewerIframe=n.iframe.getElementById("epiceditor-previewer-frame"),n.editorIframeDocument=l(n.editorIframe),n.editorIframeDocument.open(),n.editorIframeDocument.write(o.editor),n.editorIframeDocument.close(),n.previewerIframeDocument=l(n.previewerIframe),n.previewerIframeDocument.open(),n.previewerIframeDocument.write(o.previewer),f=n.previewerIframeDocument.createElement("base"),f.target="_blank",n.previewerIframeDocument.getElementsByTagName("head")[0].appendChild(f),n.previewerIframeDocument.close(),n.reflow(),a(n.settings.theme.base,n.iframe,"theme"),a(n.settings.theme.editor,n.editorIframeDocument,"theme"),a(n.settings.theme.preview,n.previewerIframeDocument,"theme"),n.iframe.getElementById("epiceditor-wrapper").style.position="relative",n.editorIframe.style.position="absolute",n.previewerIframe.style.position="absolute",n.editor=n.editorIframeDocument.body,n.previewer=n.previewerIframeDocument.getElementById("epiceditor-preview"),n.editor.contentEditable=!0,n.iframe.body.style.height=this.element.offsetHeight+"px",n.previewerIframe.style.left="-999999px",this.editorIframeDocument.body.style.wordWrap="break-word",d()>-1&&(this.previewer.style.height=parseInt(i(this.previewer,"height"),10)+2),this.open(n.settings.file.name),n.settings.focusOnLoad&&n.iframe.addEventListener("readystatechange",function(){n.iframe.readyState=="complete"&&n.focus()}),n.previewerIframeDocument.addEventListener("click",function(t){var r=t.target,i=n.previewerIframeDocument.body;r.nodeName=="A"&&r.hash&&r.hostname==e.location.hostname&&(t.preventDefault(),r.target="_self",i.querySelector(r.hash)&&(i.scrollTop=i.querySelector(r.hash).offsetTop))}),c=n.iframe.getElementById("epiceditor-utilbar"),y={},n._goFullscreen=function(t){this._fixScrollbars("auto");if(n.is("fullscreen")){n._exitFullscreen(t);return}w&&(E?t.webkitRequestFullScreen():S?t.mozRequestFullScreen():x&&t.requestFullscreen()),b=n.is("edit"),n._eeState.fullscreen=!0,n._eeState.edit=!0,n._eeState.preview=!0;var r=e.innerWidth,o=e.innerHeight,u=e.outerWidth,a=e.outerHeight;w||(a=e.innerHeight),y.editorIframe=s(n.editorIframe,"save",{width:u/2+"px",height:a+"px","float":"left",cssFloat:"left",styleFloat:"left",display:"block",position:"static",left:""}),y.previewerIframe=s(n.previewerIframe,"save",{width:u/2+"px",height:a+"px","float":"right",cssFloat:"right",styleFloat:"right",display:"block",position:"static",left:""}),y.element=s(n.element,"save",{position:"fixed",top:"0",left:"0",width:"100%","z-index":"9999",zIndex:"9999",border:"none",margin:"0",background:i(n.editor,"background-color"),height:o+"px"}),y.iframeElement=s(n.iframeElement,"save",{width:u+"px",height:o+"px"}),c.style.visibility="hidden",w||(document.body.style.overflow="hidden"),n.preview(),n.focus(),n.emit("fullscreenenter")},n._exitFullscreen=function(e){this._fixScrollbars(),s(n.element,"apply",y.element),s(n.iframeElement,"apply",y.iframeElement),s(n.editorIframe,"apply",y.editorIframe),s(n.previewerIframe,"apply",y.previewerIframe),n.element.style.width=n._eeState.reflowWidth?n._eeState.reflowWidth:"",n.element.style.height=n._eeState.reflowHeight?n._eeState.reflowHeight:"",c.style.visibility="visible",n._eeState.fullscreen=!1,w?E?document.webkitCancelFullScreen():S?document.mozCancelFullScreen():x&&document.exitFullscreen():document.body.style.overflow="auto",b?n.edit():n.preview(),n.reflow(),n.emit("fullscreenexit")},n.editor.addEventListener("keyup",function(){m&&e.clearTimeout(m),m=e.setTimeout(function(){n.is("fullscreen")&&n.preview()},250)}),T=n.iframeElement,c.addEventListener("click",function(e){var t=e.target.className;t.indexOf("epiceditor-toggle-preview-btn")>-1?n.preview():t.indexOf("epiceditor-toggle-edit-btn")>-1?n.edit():t.indexOf("epiceditor-fullscreen-btn")>-1&&n._goFullscreen(T)}),E?document.addEventListener("webkitfullscreenchange",function(){!document.webkitIsFullScreen&&n._eeState.fullscreen&&n._exitFullscreen(T)},!1):S?document.addEventListener("mozfullscreenchange",function(){!document.mozFullScreen&&n._eeState.fullscreen&&n._exitFullscreen(T)},!1):x&&document.addEventListener("fullscreenchange",function(){document.fullscreenElement==null&&n._eeState.fullscreen&&n._exitFullscreen(T)},!1),h=n.iframe.getElementById("epiceditor-utilbar"),n.settings.button.bar!==!0&&(h.style.display="none"),h.addEventListener("mouseover",function(){p&&clearTimeout(p)}),k=[n.previewerIframeDocument,n.editorIframeDocument];for(L=0;Li&&(n=i,a=!0),a?this._fixScrollbars("auto"):this._fixScrollbars("hidden"),n!=this.oldHeight&&(this.getElement("container").style.height=n+"px",this.reflow(),this.settings.autogrow.scroll&&e.scrollBy(0,n-this.oldHeight),this.oldHeight=n))},b.prototype._fixScrollbars=function(e){var t;this.settings.autogrow?t="hidden":t="auto",t=e||t,this.getElement("editor").documentElement.style.overflow=t,this.getElement("previewer").documentElement.style.overflow=t},b.version="0.2.2",b._data={},e.EpicEditor=b})(window),function(){function t(t){this.tokens=[],this.tokens.links={},this.options=t||f.defaults,this.rules=e.normal,this.options.gfm&&(this.options.tables?this.rules=e.tables:this.rules=e.gfm)}function r(e,t){this.options=t||f.defaults,this.links=e,this.rules=n.normal;if(!this.links)throw new Error("Tokens array requires a `links` property.");this.options.gfm?this.options.breaks?this.rules=n.breaks:this.rules=n.gfm:this.options.pedantic&&(this.rules=n.pedantic)}function i(e){this.tokens=[],this.token=null,this.options=e||f.defaults}function s(e,t){return e.replace(t?/&/g:/&(?!#?\w+;)/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function o(e,t){return e=e.source,t=t||"",function n(r,i){return r?(i=i.source||i,i=i.replace(/(^|[^\[])\^/g,"$1"),e=e.replace(r,i),n):new RegExp(e,t)}}function u(){}function a(e){var t=1,n,r;for(;t[^\n]+(\n[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,def:/^ *\[([^\]]+)\]: *([^\s]+)(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:u,paragraph:/^([^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+\n*/,text:/^[^\n]+/};e.bullet=/(?:[*+-]|\d+\.)/,e.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/,e.item=o(e.item,"gm")(/bull/g,e.bullet)(),e.list=o(e.list)(/bull/g,e.bullet)("hr",/\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/)(),e._tag="(?!(?: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+(?!:/|@)\\b",e.html=o(e.html)("comment",//)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/])*?>/)(/tag/g,e._tag)(),e.paragraph=o(e.paragraph)("hr",e.hr)("heading",e.heading)("lheading",e.lheading)("blockquote",e.blockquote)("tag","<"+e._tag)("def",e.def)(),e.normal=a({},e),e.gfm=a({},e.normal,{fences:/^ *(`{3,}|~{3,}) *(\w+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,paragraph:/^/}),e.gfm.paragraph=o(e.paragraph)("(?!","(?!"+e.gfm.fences.source.replace("\\1","\\2")+"|")(),e.tables=a({},e.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/}),t.rules=e,t.lex=function(e,n){var r=new t(n);return r.lex(e)},t.prototype.lex=function(e){return e=e.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n"),this.token(e,!0)},t.prototype.token=function(e,t){var e=e.replace(/^ +$/gm,""),n,r,i,s,o,u,a;while(e){if(i=this.rules.newline.exec(e))e=e.substring(i[0].length),i[0].length>1&&this.tokens.push({type:"space"});if(i=this.rules.code.exec(e)){e=e.substring(i[0].length),i=i[0].replace(/^ {4}/gm,""),this.tokens.push({type:"code",text:this.options.pedantic?i:i.replace(/\n+$/,"")});continue}if(i=this.rules.fences.exec(e)){e=e.substring(i[0].length),this.tokens.push({type:"code",lang:i[2],text:i[3]});continue}if(i=this.rules.heading.exec(e)){e=e.substring(i[0].length),this.tokens.push({type:"heading",depth:i[1].length,text:i[2]});continue}if(t&&(i=this.rules.nptable.exec(e))){e=e.substring(i[0].length),s={type:"table",header:i[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:i[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:i[3].replace(/\n$/,"").split("\n")};for(u=0;u ?/gm,""),this.token(i,t),this.tokens.push({type:"blockquote_end"});continue}if(i=this.rules.list.exec(e)){e=e.substring(i[0].length),this.tokens.push({type:"list_start",ordered:isFinite(i[2])}),i=i[0].match(this.rules.item),n=!1,a=i.length,u=0;for(;u|])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:u,tag:/^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)([\s\S]*?[^`])\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:u,text:/^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/,n.link=o(n.link)("inside",n._inside)("href",n._href)(),n.reflink=o(n.reflink)("inside",n._inside)(),n.normal=a({},n),n.pedantic=a({},n.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/}),n.gfm=a({},n.normal,{escape:o(n.escape)("])","~])")(),url:/^(https?:\/\/[^\s]+[^.,:;"')\]\s])/,del:/^~{2,}([\s\S]+?)~{2,}/,text:o(n.text)("]|","~]|")("|","|https?://|")()}),n.breaks=a({},n.gfm,{br:o(n.br)("{2,}","*")(),text:o(n.gfm.text)("{2,}","*")()}),r.rules=n,r.output=function(e,t,n){var i=new r(t,n);return i.output(e)},r.prototype.output=function(e){var t="",n,r,i,o;while(e){if(o=this.rules.escape.exec(e)){e=e.substring(o[0].length),t+=o[1];continue}if(o=this.rules.autolink.exec(e)){e=e.substring(o[0].length),o[2]==="@"?(r=o[1][6]===":"?this.mangle(o[1].substring(7)):this.mangle(o[1]),i=this.mangle("mailto:")+r):(r=s(o[1]),i=r),t+=''+r+"";continue}if(o=this.rules.url.exec(e)){e=e.substring(o[0].length),r=s(o[1]),i=r,t+=''+r+"";continue}if(o=this.rules.tag.exec(e)){e=e.substring(o[0].length),t+=this.options.sanitize?s(o[0]):o[0];continue}if(o=this.rules.link.exec(e)){e=e.substring(o[0].length),t+=this.outputLink(o,{href:o[2],title:o[3]});continue}if((o=this.rules.reflink.exec(e))||(o=this.rules.nolink.exec(e))){e=e.substring(o[0].length),n=(o[2]||o[1]).replace(/\s+/g," "),n=this.links[n.toLowerCase()];if(!n||!n.href){t+=o[0][0],e=o[0].substring(1)+e;continue}t+=this.outputLink(o,n);continue}if(o=this.rules.strong.exec(e)){e=e.substring(o[0].length),t+=""+this.output(o[2]||o[1])+"";continue}if(o=this.rules.em.exec(e)){e=e.substring(o[0].length),t+=""+this.output(o[2]||o[1])+"";continue}if(o=this.rules.code.exec(e)){e=e.substring(o[0].length),t+=""+s(o[2],!0)+"";continue}if(o=this.rules.br.exec(e)){e=e.substring(o[0].length),t+="
    ";continue}if(o=this.rules.del.exec(e)){e=e.substring(o[0].length),t+=""+this.output(o[1])+"";continue}if(o=this.rules.text.exec(e)){e=e.substring(o[0].length),t+=s(o[0]);continue}if(e)throw new Error("Infinite loop on byte: "+e.charCodeAt(0))}return t},r.prototype.outputLink=function(e,t){return e[0][0]!=="!"?'"+this.output(e[1])+"":''+s(e[1])+'"},r.prototype.mangle=function(e){var t="",n=e.length,r=0,i;for(;r.5&&(i="x"+i.toString(16)),t+="&#"+i+";";return t},i.parse=function(e,t){var n=new i(t);return n.parse(e)},i.prototype.parse=function(e){this.inline=new r(e.links,this.options),this.tokens=e.reverse();var t="";while(this.next())t+=this.tok();return t},i.prototype.next=function(){return this.token=this.tokens.pop()},i.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0},i.prototype.parseText=function(){var e=this.token.text;while(this.peek().type==="text")e+="\n"+this.next().text;return this.inline.output(e)},i.prototype.tok=function(){switch(this.token.type){case"space":return"";case"hr":return"
    \n";case"heading":return""+this.inline.output(this.token.text)+"\n";case"code":if(this.options.highlight){var e=this.options.highlight(this.token.text,this.token.lang);e!=null&&e!==this.token.text&&(this.token.escaped=!0,this.token.text=e)}return this.token.escaped||(this.token.text=s(this.token.text,!0)),"
    "+this.token.text+"
    \n";case"table":var t="",n,r,i,o,u;t+="\n\n";for(r=0;r'+n+"\n":""+n+"\n";t+="\n\n",t+="\n";for(r=0;r\n";for(u=0;u'+o+"\n":""+o+"\n";t+="\n"}return t+="\n","\n"+t+"
    \n";case"blockquote_start":var t="";while(this.next().type!=="blockquote_end" -)t+=this.tok();return"
    \n"+t+"
    \n";case"list_start":var a=this.token.ordered?"ol":"ul",t="";while(this.next().type!=="list_end")t+=this.tok();return"<"+a+">\n"+t+"\n";case"list_item_start":var t="";while(this.next().type!=="list_item_end")t+=this.token.type==="text"?this.parseText():this.tok();return"
  • "+t+"
  • \n";case"loose_item_start":var t="";while(this.next().type!=="list_item_end")t+=this.tok();return"
  • "+t+"
  • \n";case"html":return!this.token.pre&&!this.options.pedantic?this.inline.output(this.token.text):this.token.text;case"paragraph":return"

    "+this.inline.output(this.token.text)+"

    \n";case"text":return"

    "+this.parseText()+"

    \n"}},u.exec=u,f.options=f.setOptions=function(e){return f.defaults=e,f},f.defaults={gfm:!0,tables:!0,breaks:!1,pedantic:!1,sanitize:!1,silent:!1,highlight:null},f.Parser=i,f.parser=i.parse,f.Lexer=t,f.lexer=t.lex,f.InlineLexer=r,f.inlineLexer=r.output,f.parse=f,typeof module!="undefined"?module.exports=f:typeof define=="function"&&define.amd?define(function(){return f}):this.marked=f}.call(function(){return this||(typeof window!="undefined"?window:global)}()); \ No newline at end of file diff --git a/webcit/epic/themes/base/epiceditor.css b/webcit/epic/themes/base/epiceditor.css deleted file mode 100644 index 76e58fc39..000000000 --- a/webcit/epic/themes/base/epiceditor.css +++ /dev/null @@ -1,70 +0,0 @@ -html, body, iframe, div { - margin:0; - padding:0; -} - -#epiceditor-utilbar { - position:fixed; - bottom:10px; - right:10px; -} - -#epiceditor-utilbar button { - display:block; - float:left; - width:30px; - height:30px; - border:none; - background:none; -} - -#epiceditor-utilbar button.epiceditor-toggle-preview-btn { - background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAf9JREFUeNrsVu1twjAQLZmAEcIGYYKGDWACkgkSkPiQ+CifAoEgyQTQDegEpROQDZoRMgH0HToj1yIglKr90Vg62T6f/e4d9gu50+n09BctlwFnwP8TOAgCA10VRr2ZELaHhbBXx3HCVMC+71voXmD6g4Qi2NB13e1DwAAkZhtmmKYRcxsJhHeBPc8bMMufbDU0PxF4vV4TSyth8477csI6lTV/a71er9tioonBarXaIAmLErliNWyqoM8nrJPpHFNLWLcI4xvj5XKpMo2ZgcvzIvs+75S0wKwPPB/CnpWXsG00Gra2WCwshekOVoC9Sb6IGN1ge2HNsWK+B0iJqxAL5oSpYeDJJW02mxVYLAWSGfDtebylA68Bc4wh+ahK5PcxLh6PR5GUpym/iTOfz89PqNVqhRI4iQf1/o174HNMVYDSGeTDmXQ3znogCGrtdpsYVBhER1aH2Wzm8iE7UR74DMTWGNxUQWmNYqTEzq8APoo9sJ8wKoR5eU7T6VQVjZAvx4YvDJWt1Ol0QsTqkppF8EW8/12OhTnSpT2LCe2/KiCTyUQVkJgPuwgb6XG32w05Xui4q0imLLNDxA/uSuZ4PNaZqZlSsejDYfd6veihj8RoNDK5XOUHAen3Dfr9/j7VZxEJ6AwuxCCvhMTM7oNAARhl/0Ay4Az419qXAAMAfBdK7281j6YAAAAASUVORK5CYII=); -} - -#epiceditor-utilbar button.epiceditor-toggle-edit-btn { - background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnVJREFUeNrsV+lt4lAQNtEWAB2QCtZ0ABWsqYB1BU5AgDgkQOISl9cV4FQQtgLYCuKtIN4K4gogM9H3pMmLTTh24c+O9An7+XnOb8aP1G63M64hN8aV5GqGvxyyyfO8Y3S6hDtc2wTfcZyLRPwdvxEbPSviIwjIRtO49s9ONSRLMIGvwkBI+EPYEEqyQmcZdl2Xo3BgcJ90xPUGDh1veLFYWCBK9oQ6P4BgiXVO6fUjg5zCJcE6kVxsLEN4QTlWzO5yuRwlGp7P55zOxz1RRqK2SfKD8BvOG4IHxUqlEnxop9lsZpITa0KWndGwIeQIXswzHbynpK2xzjXbeBfxdDrlhbUWjYyuiJS9fBJxgL3PItKsprNQrVaD1GQyYUVP2oYelDziPoPnT5+k2QajleEC3usI/exM7oYiXor0hpxS8qhLv5FIVVrcBwkp5ueclbS27qNMvkj7kg3nZX1qtVqAaSUN5OGUwn2M4RUb3263plh700E6I7wTKn1suCAW3PF4zL1r1Ov1SBhXZLEJFqGTQCq5N1BZIp3s+DOi5fXcG7lGo1Ea5DIFSWzcq7a4R6uYqJmlkSqHoeGKeq+w905MtGKj0Yje9TE5ID9pqictQQwmXTfh82cIJ0NML0d0QY8MdhMn13A4zENB0hAJEYn6EnGL3MZ0hsyG3Ww2g70jU8lgMOhqHicJz+KfovVkz3J5/FardfhBgDZzS90SeoJ8cXjQJlUAEmZUCx30kYiTfr9vgFRc72+ChCHSzNH+Qgk+fA7b7fZZJ5AAiIRhT4zUv3/Y07LiaPW9yPE2L5jrI/p/d7wVEZe0U8bJkvr/F+ZS8irAAIorRozUvI0gAAAAAElFTkSuQmCC); -} - -#epiceditor-utilbar button.epiceditor-fullscreen-btn { - background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAY5JREFUeNrsV8tthDAQhYgCtoV04BKghK2En5AQBw4IITjwq2RLgBJcwpawHZAxMpGDYGwTFPaQkUbG1sybj58NmNM0GVfIh3GRXBbYEid932N9d1zXHWWAGAb4m+9VsUA0H5SubKkKIGA4qyUC2qKBxSCe541HKln7dV2nVbHRtq0Nw7CXGNtz/jzwqjZ5odtqTOagQRC82KRpGkcS/L2Ok7lXZV3Xp7Q6DMNR2mqNthMhKXLqzcUCc6Wgn3wU1wlX1PboHs8tjaLoyVtLT7JFK2ZZM6CZvWyE+X1Voaj3la3DMA63epGqqm4wfyCBH8xmz1+Z1WVZ2vyqU2HvHtv9OI4PsRpjL91YV2a7pcB8onmOifYFUhSFLQCTnQtkDpokyYv73JBtcAQsA3zGTXJBEgNXgrF3CcrBZGwnC+4uqxHnH+zN8/ybvexZwvZNhlsHbrt5CyCgDtu1XosUe58K4kuOF9EKnKYp20eVrxDUJssyreM0bDg4kIw0EfCbftvqQ6KKYf7/wvyVfAkwAMjqoFSaWbrBAAAAAElFTkSuQmCC); -} - -@media -only screen and (-webkit-min-device-pixel-ratio: 2), -only screen and ( min--moz-device-pixel-ratio: 2), -only screen and ( -o-min-device-pixel-ratio: 2/1), -only screen and ( min-device-pixel-ratio: 2), -only screen and ( min-resolution: 192dpi), -only screen and ( min-resolution: 2dppx) { - #epiceditor-utilbar button.epiceditor-toggle-preview-btn { - background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAMAAAANIilAAAABrVBMVEWIiIiHh4eIiIiJiYmEhISEhISEhISMjIyNjY2MjIyNjY2MjIyFhYWDg4OFhYWKioqKioqBgYGJiYmJiYmJiYmKioqKioqFhYWIiIiJiYmIiIiJiYmIiIiGhoaIiIiGhoaIiIiHh4eHh4eGhoaFhYWKioqFhYWEhISFhYWEhISDg4ONjY2NjY2MjIyHh4eMjIyLi4uCgoKCgoKCgoKBgYGBgYGOjo6Ojo6BgYGPj4+Ojo6Hh4eNjY2Pj4+BgYGNjY2BgYGHh4eQkJCNjY2FhYWHh4eDg4OQkJCQkJCAgICCgoKAgICAgICQkJCQkJCQkJCAgICQkJCAgICQkJCFhYWHh4eHh4eGhoaKioqGhoaMjIyDg4OEhISDg4OEhISDg4OEhISKioqBgYGJiYmKioqKioqJiYmMjIyEhISCgoKGhoaLi4uPj4+Pj4+BgYGKioqDg4OGhoaGhoaMjIyHh4eEhISEhISDg4OIiIiJiYmGhoaHh4eJiYkAAACAgICFhYWQkJCIiIiEhISLi4uDg4OHh4eGhoaCgoKBgYGJiYmMjIyOjo6KioqNjY2Pj4+o6Lr0AAAAfnRSTlPfvxDPEL8gv5/Pr3AQ3++vn8+/cCCA34/vj8/vMJ+vgJ+vYN/fMIBAv4/v38/v39+PgBBg74DPgGAwMHDvrzBQj1AggJ8wIHC/IM9gjxBQgO+vv89Qz0C/70Bgz89ggIDvYN/fII8wIHDvMJ+/QBBAMBDPnxBgML9AEI/vQACT8cYwAAACXElEQVR42u2WV1caURRGJ73H9J7YW+y99957ARREURAFQRFEOFGMkybxN+eec2cWUwBnrTwli/1yvvnm7PvEuoMAf0FGzsj/nDwxOTUzdyoxNzM1OWFU7h0aPtUxPNRrQPZ0XKagw3OF7Nm9TMOuJ43cQmpavSWV3HRhgKakcmvjhSEaW/VyV/tvg7R3aeU+9ULZ/fLEQ/ndMvXbPrV88EvBvQdOMCsLMzjNd5TFgSTr3SpWOCuUTYWTVVV6m+Sdr0qqqVGxw6pqXUPyZlziFaU9Vi3HVSyzag+D/YlcbXLZLm+85AsOgMK4hkIABz/YkSVVdpS3fnKevQCIYgCcGqKslGd0g3dbIIR5fP8cZCkMdOANWeSLEJZklt5StxEWcmLIuw+AHGE+YiEWE67jGxnlO8xv8OGTEBGRRSACmNtYyBUjgcCCKJPLqjYMAeD04ENEGIjQ7AGikuUFNhdF8Vogj0T5bDyqEjh55AwI4N7/hmRTe4zRxEM+ZuKYFSYeEP9HzPtuEFjm9pKf9W5KQLbKhSVMbkymfHL90i+s/wR5PM9iCaYiLOcLTogCrKEIYwkLD19T25/4bR+unSG3bkOQwiG1QZfV6gryBaqL5c01XCCZ9lbOCOvNUpouUOGishSK+dpKUHMZ2M6Jz7ZHNEO+hOoLUWVZZROx6a8hn+VcRWh1EOtBUuhcPiy+pBdg3fZ3DaOj2ma7LtXVW1uj0XVqTW2aS9/bUP8jJfUN3is+N97mp8nV9Wavka9kZ/e6zuzuNP59Hhkbn53+QkzPjo+NZP6TZOSM/L/LfwAJ69Ba3fXmtwAAAABJRU5ErkJggg==); - background-size: 30px 30px; - } - - #epiceditor-utilbar button.epiceditor-toggle-edit-btn { - background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAMAAAANIilAAAACNFBMVEWIiIiHh4eIiIiGhoaEhISDg4OCgoKDg4OMjIyNjY2MjIyMjIyLi4uMjIyKioqCgoKNjY2Ojo6Dg4ONjY2FhYWFhYWCgoKKioqKioqLi4uLi4uMjIyLi4uFhYWKioqKioqEhISJiYmJiYmEhISEhISFhYWEhISGhoaHh4eJiYmNjY2Hh4eKioqDg4ODg4OCgoKOjo6Ojo6Dg4OOjo6BgYGOjo6AgICCgoKNjY2Dg4OPj4+BgYGBgYGAgICOjo6BgYGOjo6AgICOjo6BgYGBgYGAgICPj4+QkJCQkJCQkJCQkJCPj4+NjY2IiIiIiIiFhYWFhYWEhISEhISGhoaDg4OGhoaDg4OHh4eDg4OCgoKMjIyLi4uLi4uKioqNjY2KioqNjY2NjY2NjY2Dg4OKioqGhoaJiYmIiIiGhoaFhYWEhISFhYWFhYWOjo6Pj4+FhYWGhoaPj4+Hh4eMjIyMjIyMjIyJiYmIiIiIiIiOjo6Ojo6CgoKBgYGPj4+QkJCHh4eHh4eEhISIiIiDg4OEhISDg4ODg4OLi4uHh4eEhISMjIyFhYWGhoaHh4eOjo6IiIiKioqKioqMjIyGhoaIiIiJiYmIiIiFhYWGhoaGhoaHh4eKioqJiYmLi4uIiIiGhoaJiYmHh4eGhoaGhoaJiYmFhYWKioqPj4+IiIiGhoYAAACAgICCgoKQkJCPj4+BgYGDg4OFhYWHh4eOjo6JiYmGhoaLi4uEhISIiIiNjY2MjIyKioqRGRgVAAAAq3RSTlNQz7+Pz4AQr4/vIK+Av99QICBQzyCv37/PcM+f378QgHAwgIBgnxBQMK+PgFCf34Bwn0BQv2Ag7zBwEFDvj4CAv1DvYK/f398gUICA39+fYHAwQHAQn78gz0DfYO8wgO+/YECPIK9gz89Av8/f31AwgK9A72AwIGCAMM+PICCvrxCfr+/fYCAgYO9QgGBQjyCPYM8QcM8wEEAgn58Qn+8w7+/fv0DvQEBA7wCxres+AAAC50lEQVR42u2XVUMbQRSFU3d3d3d3d8EpUKRoKbS40+LuDsEtQOFQKA2FEvhz3XsnS5IlJLB9a/s95J49M99sXpJsNPgD/st/oZwxJJGhTn4+RLxQJ78k9xnUyU+HJV6pk6OGiXR1ciy5sZizfPMrwzl9mIiak5x6/sLnUZmH9+9eqqAQCftyakXkqFUq7MpX6JbW2WBHDnxtmJUAIMiGfD3AYINArDdsCppNfmewxQqx4aRVObFm0ibLAW+aNYkz5ZL4SdusRIkI8SVKOcFyp/cu5ftYA6ySc4Kl3DZuxs4dhfAZV+CDQtNFm0lWuLsBFPoqXF9g9bjSZrlqypwqAC1TClqAtYprIVfLjT+f0gfAXyn7oY9GNZ/KiWVumX17OYYAIUp3O+AnDu7bZqxOk5zU+ZOpPwD0UABNBaEAaPYACBVCZ5Ik14vlg5ClVjFpC0NZ6lplGa0nxN2gSZkg2vtB9FOmKDUNCyemcTStMXXcpmh4yGUl5ToAORMOaGiflhtkoRKCfq41yTw+GFsHKeeIRUfwwbwKOo/eIATi3GQNivREVxyIZsqeADL1+swuvZEiAJ4UmsEUsVEODRAnNp2iulzekrVAbyJLPrYctJTJ7nGQjI7uMULXBIBjIyQWUWLeAGik0E39sQGKYU0QMmp1vGnADSjj0EFtk5uOjuKzOtgok8r34rxasMzEjDFhjdDJNsE7u2VXh9oYDgNllp/n8IgfzJbwXhq9zlRu5soZWtFFl/Zy8SkaljK0R6inJTEinLQo5aSFE889kkqUWvsCdM37ZcnHYnrNBhably5QyoJDtFuJK1xMF3mHgVlkHM2e4eYB02Xxfts/NwXBuSMWLIG7sTmbb/+Hzj3fy1wuQD6N3DMX5/g0VHDDQ3aXAR4jXsEb5/co9fbLN2KdlJbO/zmM5a0qH+KukXxOnfzoO5GmTr5M7mOoktP4xrfUyffIvQ118pNBiTvq5AeDxNV//W+CFX4Doxg1lHC8FNUAAAAASUVORK5CYII=); - background-size: 30px 30px; - } - - #epiceditor-utilbar button.epiceditor-fullscreen-btn { - background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAMAAAANIilAAAAA5FBMVEWPj4+JiYmJiYmCgoKGhoaPj4+Li4uEhISAgICNjY2Li4uNjY2QkJCFhYWEhISLi4uHh4eHh4eIiIiHh4eGhoaHh4eEhISOjo6EhISJiYmFhYWJiYmFhYWNjY2NjY2Hh4eOjo6CgoKGhoaKioqKioqJiYmKioqDg4ODg4OBgYGGhoaKioqKioqLi4uMjIyMjIyIiIiIiIiMjIyOjo6GhoaDg4ONjY2EhISPj4+CgoIAAACJiYmHh4eIiIiFhYWCgoKPj4+Li4uAgICKioqEhISGhoaBgYGOjo6MjIyQkJCNjY2Dg4O2Jy/OAAAAO3RSTlMQz0DPEHDPz0DvMDBAQBBAQBAQz88wMM/v7zAw788Q7xAQQM9AEBDPEEAwMO/v7zDvMEBA70BAQEBAAAENmbYAAAG1SURBVHja7dftM0JREMdxD5GkEEqKpBJRSc8rQq7Q////2Dnm3t85jtkTmmGG75t7Z3c/t9fN0Tf6x1/Dz0ZrZGZf/BJ8a9QjM/vCwks9Px5aBcslC+P3nPVmi8dcczrcHHM2flug1CHRYcoYNd0YFlrAL1yHqPOC9g9IdbAfjHAjYFjoT+FI1MfRiAM/cZdEl0+oVidVvRaMcAOMgJWGBUYSVhrWjdfvjKqrq1Vzsu7Cy1Vo7XXZhYuj0ahwfHY+sjo/Oy7woyhitkTQsESsZawstG6VlvDCfIlUmfSVVjpDqtL8goBLbKFhsRcwalxcB100CDkxLLQbJxKwpvb3At7Y2iRuJzd4V26HuM2tDQkPWMOamu1Awkeetx2qtDy/lvZaCW173pGIWetA/xBbF+ZgiVgjGcdutLJ7xO1l9VnMiWGhJdzl4vx4CNpN+ifJXUy7RPEuZ2C1AIY1NG5kHI4Dx8MynnBtovYkqHzi25OyP8ONiKFh3djQsCIecn2i/lBvMU+UXxwi3HyE832jvD0RsLuP8CN3Oh0+feRmixE+g7CdLb43WiEz++Jb+M//x/gB/ArCl0G4nsFuEQAAAABJRU5ErkJggg==); - background-size: 30px 30px; - } -} - -#epiceditor-utilbar button:last-child { - margin-left:15px; -} - -#epiceditor-utilbar button:hover { - cursor:pointer; -} - -.epiceditor-edit-mode #epiceditor-utilbar button.epiceditor-toggle-edit-btn { - display:none; -} - -.epiceditor-preview-mode #epiceditor-utilbar button.epiceditor-toggle-preview-btn { - display:none; -} diff --git a/webcit/epic/themes/editor/epic-dark.css b/webcit/epic/themes/editor/epic-dark.css deleted file mode 100644 index 058ace614..000000000 --- a/webcit/epic/themes/editor/epic-dark.css +++ /dev/null @@ -1,13 +0,0 @@ -html { padding:10px; } - -body { - border:0; - background:rgb(41,41,41); - font-family:monospace; - font-size:14px; - padding:10px; - color:#ddd; - line-height:1.35em; - margin:0; - padding:0; -} diff --git a/webcit/epic/themes/editor/epic-light.css b/webcit/epic/themes/editor/epic-light.css deleted file mode 100644 index 9411cec52..000000000 --- a/webcit/epic/themes/editor/epic-light.css +++ /dev/null @@ -1,12 +0,0 @@ -html { padding:10px; } - -body { - border:0; - background:#fcfcfc; - font-family:monospace; - font-size:14px; - padding:10px; - line-height:1.35em; - margin:0; - padding:0; -} diff --git a/webcit/epic/themes/preview/bartik.css b/webcit/epic/themes/preview/bartik.css deleted file mode 100644 index 2ffb6d520..000000000 --- a/webcit/epic/themes/preview/bartik.css +++ /dev/null @@ -1,167 +0,0 @@ -body { - font-family: Georgia, "Times New Roman", Times, serif; - line-height: 1.5; - font-size: 87.5%; - word-wrap: break-word; - margin: 2em; - padding: 0; - border: 0; - outline: 0; - background: #fff; -} - -h1, -h2, -h3, -h4, -h5, -h6 { - margin: 1.0em 0 0.5em; - font-weight: inherit; -} - -h1 { - font-size: 1.357em; - color: #000; -} - -h2 { - font-size: 1.143em; -} - -p { - margin: 0 0 1.2em; -} - -del { - text-decoration: line-through; -} - -tr:nth-child(odd) { - background-color: #dddddd; -} - -img { - outline: 0; -} - -code { - background-color: #f2f2f2; - background-color: rgba(40, 40, 0, 0.06); -} - -pre { - background-color: #f2f2f2; - background-color: rgba(40, 40, 0, 0.06); - margin: 10px 0; - overflow: hidden; - padding: 15px; - white-space: pre-wrap; -} - -pre code { - font-size: 100%; - background-color: transparent; -} - -blockquote { - background: #f7f7f7; - border-left: 1px solid #bbb; - font-style: italic; - margin: 1.5em 10px; - padding: 0.5em 10px; -} - -blockquote:before { - color: #bbb; - content: "\201C"; - font-size: 3em; - line-height: 0.1em; - margin-right: 0.2em; - vertical-align: -.4em; -} - -blockquote:after { - color: #bbb; - content: "\201D"; - font-size: 3em; - line-height: 0.1em; - vertical-align: -.45em; -} - -blockquote > p:first-child { - display: inline; -} - -table { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - border: 0; - border-spacing: 0; - font-size: 0.857em; - margin: 10px 0; - width: 100%; -} - -table table { - font-size: 1em; -} - -table tr th { - background: #757575; - background: rgba(0, 0, 0, 0.51); - border-bottom-style: none; -} - -table tr th, -table tr th a, -table tr th a:hover { - color: #FFF; - font-weight: bold; -} - -table tbody tr th { - vertical-align: top; -} - -tr td, -tr th { - padding: 4px 9px; - border: 1px solid #fff; - text-align: left; /* LTR */ -} - -tr:nth-child(odd) { - background: #e4e4e4; - background: rgba(0, 0, 0, 0.105); -} - -tr, -tr:nth-child(even) { - background: #efefef; - background: rgba(0, 0, 0, 0.063); -} - -a { - color: #0071B3; -} - -a:hover, -a:focus { - color: #018fe2; -} - -a:active { - color: #23aeff; -} - -a:link, -a:visited { - text-decoration: none; -} - -a:hover, -a:active, -a:focus { - text-decoration: underline; -} - diff --git a/webcit/epic/themes/preview/github.css b/webcit/epic/themes/preview/github.css deleted file mode 100644 index 4c78db4a1..000000000 --- a/webcit/epic/themes/preview/github.css +++ /dev/null @@ -1,368 +0,0 @@ -html { padding:0 10px; } - -body { - margin:0; - padding:0; - background:#fff; -} - -#epiceditor-wrapper{ - background:white; -} - -#epiceditor-preview{ - padding-top:10px; - padding-bottom:10px; - font-family: Helvetica,arial,freesans,clean,sans-serif; - font-size:13px; - line-height:1.6; -} - -#epiceditor-preview>*:first-child{ - margin-top:0!important; -} - -#epiceditor-preview>*:last-child{ - margin-bottom:0!important; -} - -#epiceditor-preview a{ - color:#4183C4; - text-decoration:none; -} - -#epiceditor-preview a:hover{ - text-decoration:underline; -} - -#epiceditor-preview h1, -#epiceditor-preview h2, -#epiceditor-preview h3, -#epiceditor-preview h4, -#epiceditor-preview h5, -#epiceditor-preview h6{ - margin:20px 0 10px; - padding:0; - font-weight:bold; - -webkit-font-smoothing:antialiased; -} - -#epiceditor-preview h1 tt, -#epiceditor-preview h1 code, -#epiceditor-preview h2 tt, -#epiceditor-preview h2 code, -#epiceditor-preview h3 tt, -#epiceditor-preview h3 code, -#epiceditor-preview h4 tt, -#epiceditor-preview h4 code, -#epiceditor-preview h5 tt, -#epiceditor-preview h5 code, -#epiceditor-preview h6 tt, -#epiceditor-preview h6 code{ - font-size:inherit; -} - -#epiceditor-preview h1{ - font-size:28px; - color:#000; -} - -#epiceditor-preview h2{ - font-size:24px; - border-bottom:1px solid #ccc; - color:#000; -} - -#epiceditor-preview h3{ - font-size:18px; -} - -#epiceditor-preview h4{ - font-size:16px; -} - -#epiceditor-preview h5{ - font-size:14px; -} - -#epiceditor-preview h6{ - color:#777; - font-size:14px; -} - -#epiceditor-preview p, -#epiceditor-preview blockquote, -#epiceditor-preview ul, -#epiceditor-preview ol, -#epiceditor-preview dl, -#epiceditor-preview li, -#epiceditor-preview table, -#epiceditor-preview pre{ - margin:15px 0; -} - -#epiceditor-preview hr{ - background:transparent url('../../images/modules/pulls/dirty-shade.png') repeat-x 0 0; - border:0 none; - color:#ccc; - height:4px; - padding:0; -} - -#epiceditor-preview>h2:first-child, -#epiceditor-preview>h1:first-child, -#epiceditor-preview>h1:first-child+h2, -#epiceditor-preview>h3:first-child, -#epiceditor-preview>h4:first-child, -#epiceditor-preview>h5:first-child, -#epiceditor-preview>h6:first-child{ - margin-top:0; - padding-top:0; -} - -#epiceditor-preview h1+p, -#epiceditor-preview h2+p, -#epiceditor-preview h3+p, -#epiceditor-preview h4+p, -#epiceditor-preview h5+p, -#epiceditor-preview h6+p{ - margin-top:0; -} - -#epiceditor-preview li p.first{ - display:inline-block; -} - -#epiceditor-preview ul, -#epiceditor-preview ol{ - padding-left:30px; -} - -#epiceditor-preview ul li>:first-child, -#epiceditor-preview ol li>:first-child{ - margin-top:0; -} - -#epiceditor-preview ul li>:last-child, -#epiceditor-preview ol li>:last-child{ - margin-bottom:0; -} - -#epiceditor-preview dl{ - padding:0; -} - -#epiceditor-preview dl dt{ - font-size:14px; - font-weight:bold; - font-style:italic; - padding:0; - margin:15px 0 5px; -} - -#epiceditor-preview dl dt:first-child{ - padding:0; -} - -#epiceditor-preview dl dt>:first-child{ - margin-top:0; -} - -#epiceditor-preview dl dt>:last-child{ - margin-bottom:0; -} - -#epiceditor-preview dl dd{ - margin:0 0 15px; - padding:0 15px; -} - -#epiceditor-preview dl dd>:first-child{ - margin-top:0; -} - -#epiceditor-preview dl dd>:last-child{ - margin-bottom:0; -} - -#epiceditor-preview blockquote{ - border-left:4px solid #DDD; - padding:0 15px; - color:#777; -} - -#epiceditor-preview blockquote>:first-child{ - margin-top:0; -} - -#epiceditor-preview blockquote>:last-child{ - margin-bottom:0; -} - -#epiceditor-preview table{ - padding:0; - border-collapse: collapse; - border-spacing: 0; - font-size: 100%; - font: inherit; -} - -#epiceditor-preview table tr{ - border-top:1px solid #ccc; - background-color:#fff; - margin:0; - padding:0; -} - -#epiceditor-preview table tr:nth-child(2n){ - background-color:#f8f8f8; -} - -#epiceditor-preview table tr th{ - font-weight:bold; -} - -#epiceditor-preview table tr th, -#epiceditor-preview table tr td{ - border:1px solid #ccc; - text-align:left; - margin:0; - padding:6px 13px; -} - -#epiceditor-preview table tr th>:first-child, -#epiceditor-preview table tr td>:first-child{ - margin-top:0; -} - -#epiceditor-preview table tr th>:last-child, -#epiceditor-preview table tr td>:last-child{ - margin-bottom:0; -} - -#epiceditor-preview img{ - max-width:100%; -} - -#epiceditor-preview span.frame{ - display:block; - overflow:hidden; -} - -#epiceditor-preview span.frame>span{ - border:1px solid #ddd; - display:block; - float:left; - overflow:hidden; - margin:13px 0 0; - padding:7px; - width:auto; -} - -#epiceditor-preview span.frame span img{ - display:block; - float:left; -} - -#epiceditor-preview span.frame span span{ - clear:both; - color:#333; - display:block; - padding:5px 0 0; -} - -#epiceditor-preview span.align-center{ - display:block; - overflow:hidden; - clear:both; -} - -#epiceditor-preview span.align-center>span{ - display:block; - overflow:hidden; - margin:13px auto 0; - text-align:center; -} - -#epiceditor-preview span.align-center span img{ - margin:0 auto; - text-align:center; -} - -#epiceditor-preview span.align-right{ - display:block; - overflow:hidden; - clear:both; -} - -#epiceditor-preview span.align-right>span{ - display:block; - overflow:hidden; - margin:13px 0 0; - text-align:right; -} - -#epiceditor-preview span.align-right span img{ - margin:0; - text-align:right; -} - -#epiceditor-preview span.float-left{ - display:block; - margin-right:13px; - overflow:hidden; - float:left; -} - -#epiceditor-preview span.float-left span{ - margin:13px 0 0; -} - -#epiceditor-preview span.float-right{ - display:block; - margin-left:13px; - overflow:hidden; - float:right; -} - -#epiceditor-preview span.float-right>span{ - display:block; - overflow:hidden; - margin:13px auto 0; - text-align:right; -} - -#epiceditor-preview code, -#epiceditor-preview tt{ - margin:0 2px; - padding:0 5px; - white-space:nowrap; - border:1px solid #eaeaea; - background-color:#f8f8f8; - border-radius:3px; -} - -#epiceditor-preview pre>code{ - margin:0; - padding:0; - white-space:pre; - border:none; - background:transparent; -} - -#epiceditor-preview .highlight pre, -#epiceditor-preview pre{ - background-color:#f8f8f8; - border:1px solid #ccc; - font-size:13px; - line-height:19px; - overflow:auto; - padding:6px 10px; - border-radius:3px; -} - -#epiceditor-preview pre code, -#epiceditor-preview pre tt{ - background-color:transparent; - border:none; -} diff --git a/webcit/epic/themes/preview/preview-dark.css b/webcit/epic/themes/preview/preview-dark.css deleted file mode 100644 index 620c1935c..000000000 --- a/webcit/epic/themes/preview/preview-dark.css +++ /dev/null @@ -1,121 +0,0 @@ -html { padding:0 10px; } - -body { - margin:0; - padding:10px 0; - background:#000; -} - -#epiceditor-preview h1, -#epiceditor-preview h2, -#epiceditor-preview h3, -#epiceditor-preview h4, -#epiceditor-preview h5, -#epiceditor-preview h6, -#epiceditor-preview p, -#epiceditor-preview blockquote { - margin: 0; - padding: 0; -} -#epiceditor-preview { - background:#000; - font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif; - font-size: 13px; - line-height: 18px; - color: #ccc; -} -#epiceditor-preview a { - color: #fff; -} -#epiceditor-preview a:hover { - color: #00ff00; - text-decoration: none; -} -#epiceditor-preview a img { - border: none; -} -#epiceditor-preview p { - margin-bottom: 9px; -} -#epiceditor-preview h1, -#epiceditor-preview h2, -#epiceditor-preview h3, -#epiceditor-preview h4, -#epiceditor-preview h5, -#epiceditor-preview h6 { - color: #cdcdcd; - line-height: 36px; -} -#epiceditor-preview h1 { - margin-bottom: 18px; - font-size: 30px; -} -#epiceditor-preview h2 { - font-size: 24px; -} -#epiceditor-preview h3 { - font-size: 18px; -} -#epiceditor-preview h4 { - font-size: 16px; -} -#epiceditor-preview h5 { - font-size: 14px; -} -#epiceditor-preview h6 { - font-size: 13px; -} -#epiceditor-preview hr { - margin: 0 0 19px; - border: 0; - border-bottom: 1px solid #ccc; -} -#epiceditor-preview blockquote { - padding: 13px 13px 21px 15px; - margin-bottom: 18px; - font-family:georgia,serif; - font-style: italic; -} -#epiceditor-preview blockquote:before { - content:"\201C"; - font-size:40px; - margin-left:-10px; - font-family:georgia,serif; - color:#eee; -} -#epiceditor-preview blockquote p { - font-size: 14px; - font-weight: 300; - line-height: 18px; - margin-bottom: 0; - font-style: italic; -} -#epiceditor-preview code, #epiceditor-preview pre { - font-family: Monaco, Andale Mono, Courier New, monospace; -} -#epiceditor-preview code { - background-color: #000; - color: #f92672; - padding: 1px 3px; - font-size: 12px; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; -} -#epiceditor-preview pre { - display: block; - padding: 14px; - color:#66d9ef; - margin: 0 0 18px; - line-height: 16px; - font-size: 11px; - border: 1px solid #d9d9d9; - white-space: pre-wrap; - word-wrap: break-word; -} -#epiceditor-preview pre code { - background-color: #000; - color:#ccc; - font-size: 11px; - padding: 0; -} diff --git a/webcit/static.c b/webcit/static.c index 650db18f0..3110da191 100644 --- a/webcit/static.c +++ b/webcit/static.c @@ -61,7 +61,7 @@ void output_static(const char *what) { } else { if (fstat(fd, &statbuf) == -1) { - syslog(LOG_INFO, "output_static('%s') -- FSTAT FAILED --\n", what); + syslog(LOG_INFO, "output_static('%s') : %s", what, strerror(errno)); if (strstr(content_type, "image/") != NULL) { output_error_pic("Stat failed!", strerror(errno)); } diff --git a/webcit/subst.c b/webcit/subst.c index a3063e6f3..0cd7615f2 100644 --- a/webcit/subst.c +++ b/webcit/subst.c @@ -1,5 +1,6 @@ -// Spaghetti, technical debt, and an unmaintainable big mess. -// No one knows how this works. This is why we started over with WebCit-NG. +// This is a template substitution engine, which began with good intentions, but ended up becoming +// more complex and unmaintainable than what it replaced. We are barely hanging on with this until +// webcit-ng replaces webcit classic. #include "sysdep.h" #include @@ -1587,22 +1588,16 @@ void InitTemplateCache(void) /* Primary Template set... */ StrBufPrintf(Dir, "%s/t", static_dirs[0]); - LoadTemplateDir(Dir, - TemplateCache, - Key); + LoadTemplateDir(Dir, TemplateCache, Key); /* User local Template set */ StrBufPrintf(Dir, "%s/t", static_dirs[1]); - LoadTemplateDir(Dir, - LocalTemplateCache, - Key); + LoadTemplateDir(Dir, LocalTemplateCache, Key); /* Debug Templates, just to be loaded while debugging. */ StrBufPrintf(Dir, "%s/dbg", static_dirs[0]); - LoadTemplateDir(Dir, - TemplateCache, - Key); + LoadTemplateDir(Dir, TemplateCache, Key); Templates[0] = TemplateCache; Templates[1] = LocalTemplateCache; @@ -1615,13 +1610,7 @@ void InitTemplateCache(void) void *vTemplate; At = GetNewHashPos(Templates[i], 0); - while (GetNextHashPos(Templates[i], - At, - &KLen, - &Key, - &vTemplate) && - (vTemplate != NULL)) - { + while (GetNextHashPos(Templates[i], At, &KLen, &Key, &vTemplate) && (vTemplate != NULL)) { load_template(NULL, (WCTemplate *)vTemplate); } DeleteHashPos(&At); @@ -1684,17 +1673,11 @@ int EvaluateToken(StrBuf *Target, int state, WCTemplputParams **TPP) if (TP->Tokens->nParameters >= 6) { if (EvaluateConditional(Target, 0, state, TPP)) { GetTemplateTokenString(Target, TP, 5, &AppendMe, &AppendMeLen); - StrBufAppendBufPlain(Target, - AppendMe, - AppendMeLen, - 0); + StrBufAppendBufPlain(Target, AppendMe, AppendMeLen, 0); } else{ GetTemplateTokenString(Target, TP, 4, &AppendMe, &AppendMeLen); - StrBufAppendBufPlain(Target, - AppendMe, - AppendMeLen, - 0); + StrBufAppendBufPlain(Target, AppendMe, AppendMeLen, 0); } if (*TPP != TP) { @@ -1702,9 +1685,7 @@ int EvaluateToken(StrBuf *Target, int state, WCTemplputParams **TPP) } } else { - LogTemplateError( - Target, "Conditional", ERR_NAME, TP, - "needs at least 6 Params!"); + LogTemplateError( Target, "Conditional", ERR_NAME, TP, "needs at least 6 Params!"); } break; case SV_SUBTEMPL: @@ -1764,8 +1745,7 @@ const StrBuf *ProcessTemplate(WCTemplate *Tmpl, StrBuf *Target, WCTemplputParams ChrPtr(Tmpl->FileName)); pTmpl = duplicate_template(Tmpl); if(load_template(Target, pTmpl) == NULL) { - StrBufAppendPrintf( - Target, + StrBufAppendPrintf( Target, "
    \nError loading Template [%s]\n See Logfile for details\n
    \n", ChrPtr(Tmpl->FileName)); FreeWCTemplate(pTmpl); @@ -1780,30 +1760,22 @@ const StrBuf *ProcessTemplate(WCTemplate *Tmpl, StrBuf *Target, WCTemplputParams state = eNext; while (!done) { if (i >= pTmpl->nTokensUsed) { - StrBufAppendBufPlain(Target, - pData, - len - (pData - pS), 0); + StrBufAppendBufPlain(Target, pData, len - (pData - pS), 0); done = 1; } else { int TokenRc = 0; - StrBufAppendBufPlain( - Target, pData, - pTmpl->Tokens[i]->pTokenStart - pData, 0); + StrBufAppendBufPlain( Target, pData, pTmpl->Tokens[i]->pTokenStart - pData, 0); TPtr->Tokens = pTmpl->Tokens[i]; TPtr->nArgs = pTmpl->Tokens[i]->nParameters; TokenRc = EvaluateToken(Target, TokenRc, &TPtr); - if (TokenRc > 0) - { + if (TokenRc > 0) { state = eSkipTilEnd; } - else if (TokenRc < 0) - { - if ((TPtr != &TP) && - (TPtr->ExitCTXID == -TokenRc)) - { + else if (TokenRc < 0) { + if ((TPtr != &TP) && (TPtr->ExitCTXID == -TokenRc)) { UnStackDynamicContext(Target, &TPtr); } TokenRc = 0; @@ -1823,13 +1795,10 @@ const StrBuf *ProcessTemplate(WCTemplate *Tmpl, StrBuf *Target, WCTemplputParams pTmpl->Tokens[i]->Flags, TokenRc, &TPtr); - if (-rc == TokenRc) - { + if (-rc == TokenRc) { TokenRc = 0; state = eNext; - if ((TPtr != &TP) && - (TPtr->ExitCTXID == - rc)) - { + if ((TPtr != &TP) && (TPtr->ExitCTXID == - rc)) { UnStackDynamicContext(Target, &TPtr); } } @@ -1872,8 +1841,7 @@ const StrBuf *DoTemplate(const char *templatename, long len, StrBuf *Target, WCT Static = TemplateCache; StaticLocal = LocalTemplateCache; - if (len == 0) - { + if (len == 0) { syslog(LOG_WARNING, "Can't to load a template with empty name!\n"); StrBufAppendPrintf(Target, "
    \nCan't to load a template with empty name!\n
    "); return textPlainType;