diff --git a/Uservoice bugs.txt b/Uservoice bugs.txt
deleted file mode 100644
index 4d5335db..00000000
--- a/Uservoice bugs.txt
+++ /dev/null
@@ -1,66 +0,0 @@
-Opera post preview bug
-
-I can't seem to get to the cause of this bug, so here is the complete post:
-
-
-Here's an idea: - Just before you create the alert window, stop the DragEvent
-....event.stopImmediatePropagation();
-store the event so we can resume if the user clicks the Yes button
-....queuedEvent = event as DragEvent;
-show the alert window
-if the user clicks the yes button, resume the queued event
-....dispatchEvent(queuedEvent);
-
-
-(dots are spaces)
-The problem here is that only the first indented piece of text is converted to code and has syntax highlighting. The other 2 are just indented, but no formatting applied to them.
-
-I'm using Opera 9.61, XP SP3.
-
-
---------------------------------------------------------------------------
-
-List button
-
-Highlighting multiple lines of text and clicking the list button should
-create multiple list items instead of one item.
-
---------------------------------------------------------------------------
-
-More AltGr issues
-
-Bug: Can't type '@' in answer
-
-I just found that AltGr+Q (=@) toggles Blockquote mode., which makes TSQL code in Markups extremely uncomfortable. ALT+064 works though.
-
-Guess this must be new behavior, as I never noticed it before
-
- sztyopek
-
-The same problem occurs for me: it is impossible to enter some essential characters on my keyboard layout: \ ] l L > {
-since these can only be accessed by pressing AltGr + Q, U, G, K, L, Y and B, respectively.
-
-
- devio
-
-AltGr = right ALT key.
-I am referring to German keyboard layout.
-
---------------------------------------------------------------------------
-
-Help button link is off.
-
-If you look at the help button image and link in Firebug they are a little
-bit offset.
-
---------------------------------------------------------------------------
-
-Fix Markdown to allow underscores in picture URLs
-
-Underscores in image URLs get interpreted as Markdown and then don't show the picture properly.
-
-BUT they do show the picture properly in the post preview.
-
-
-Read more: "fix Markdown to allow underscores in picture URLs" - http://stackoverflow.uservoice.com/pages/general/suggestions/131034-fix-markdown-to-allow-underscores-in-picture-urls#ixzz08aKPzrOv
-
diff --git a/django/markedit/__init__.py b/django/markedit/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/django/markedit/admin.py b/django/markedit/admin.py
new file mode 100644
index 00000000..d1cfc539
--- /dev/null
+++ b/django/markedit/admin.py
@@ -0,0 +1,22 @@
+from django.contrib import admin
+from markedit.widgets import AdminMarkEdit
+
+class MarkEditAdmin(admin.ModelAdmin):
+
+ class MarkEdit:
+ fields = ['text',]
+ options = {}
+
+ class Media:
+ from markedit import settings
+ css = getattr(settings, 'MARKEDIT_CSS', {})
+ js = getattr(settings, 'MARKEDIT_JS', [])
+
+ def formfield_for_dbfield(self, db_field, **kwargs):
+ formfield = super(MarkEditAdmin, self).formfield_for_dbfield(db_field, **kwargs)
+ if db_field.name in self.MarkEdit.fields:
+ formfield.widget = AdminMarkEdit(attrs = {
+ 'options': self.MarkEdit.options,
+ })
+ return formfield
+
diff --git a/django/markedit/settings.py b/django/markedit/settings.py
new file mode 100644
index 00000000..25c95767
--- /dev/null
+++ b/django/markedit/settings.py
@@ -0,0 +1,12 @@
+from django.conf import settings
+media_url = getattr(settings, 'MEDIA_URL', '/media/')
+
+# Default settings (as python dict)
+MARKEDIT_DEFAULT_SETTINGS = { }
+
+# Media
+MARKEDIT_CSS = { 'all': (media_url + '/js/jquery-markedit/jquery.markedit.css',) }
+MARKEDIT_JS = (
+ media_url + '/js/jquery-markedit/showdown.js',
+ media_url + '/js/jquery-markedit/jquery.markedit.js',
+)
\ No newline at end of file
diff --git a/django/markedit/templates/markedit/ui.html b/django/markedit/templates/markedit/ui.html
new file mode 100644
index 00000000..743cbc8b
--- /dev/null
+++ b/django/markedit/templates/markedit/ui.html
@@ -0,0 +1,4 @@
+
+
diff --git a/django/markedit/views.py b/django/markedit/views.py
new file mode 100644
index 00000000..60f00ef0
--- /dev/null
+++ b/django/markedit/views.py
@@ -0,0 +1 @@
+# Create your views here.
diff --git a/django/markedit/widgets.py b/django/markedit/widgets.py
new file mode 100644
index 00000000..cdad9dc6
--- /dev/null
+++ b/django/markedit/widgets.py
@@ -0,0 +1,52 @@
+from django import forms
+from django.contrib.admin import widgets as admin_widgets
+from django.template import loader, Context
+from django.utils.html import conditional_escape
+from django.utils.encoding import force_unicode
+
+class MarkEdit(forms.Textarea):
+
+ def render(self, name, value, attrs=None):
+
+ # Prepare values
+ attrs = self.build_attrs(attrs, name=name)
+ if not value:
+ value = ''
+
+ # Extract or load options
+ from markedit import settings
+ options = getattr(settings, 'MARKEDIT_DEFAULT_SETTINGS', {})
+
+ if 'options' in attrs:
+ options = self._eval_value(attrs['options'], {})
+ del attrs['options']
+
+ # Render widget to HTML
+ t = loader.get_template('markedit/ui.html')
+ c = Context({
+ 'attributes' : self._render_attrs(attrs),
+ 'value' : conditional_escape(force_unicode(value)),
+ 'id' : attrs['id'],
+ 'options': options,
+ })
+
+ return t.render(c)
+
+ def _eval_value(self, value, default_value):
+ v = None
+ try:
+ v = value()
+ except:
+ v = value
+ if v == None:
+ v = default_value
+ return v
+
+ def _render_attrs(self, attrs):
+ atts = u''
+ for key,value in attrs.items():
+ atts += u'%s="%s" ' % (key, value)
+ return atts[:-1]
+
+class AdminMarkEdit(admin_widgets.AdminTextareaWidget, MarkEdit):
+ pass
diff --git a/examples/basic.html b/examples/basic.html
new file mode 100644
index 00000000..61482b7c
--- /dev/null
+++ b/examples/basic.html
@@ -0,0 +1,48 @@
+
+
+
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
+ +It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Whatever
+ +It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.
+ + + diff --git a/examples/in-place-editing.html b/examples/in-place-editing.html new file mode 100644 index 00000000..5d93e135 --- /dev/null +++ b/examples/in-place-editing.html @@ -0,0 +1,71 @@ + + + +Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
+ +It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Whatever
+ +It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.
+ + + diff --git a/examples/multiple-editors.html b/examples/multiple-editors.html new file mode 100644 index 00000000..3f7757de --- /dev/null +++ b/examples/multiple-editors.html @@ -0,0 +1,60 @@ + + + +To test that page up/down and arrow keys work, copy this above the WMD - control.
- -
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
- Scroll Down!
-
Enter the image URL.
You can also add a title, which will be displayed as a tool tip.
Example:
http://wmd-editor.com/images/cloud1.jpg \"Optional title\"
Enter the web address.
You can also add a title, which will be displayed as a tool tip.
Example:
http://wmd-editor.com/ \"Optional title\"
Ctrl+Q"; - quoteButton.XShift = "-60px"; - quoteButton.textOp = command.doBlockquote; - setupButton(quoteButton, true); - buttonRow.appendChild(quoteButton); - - var codeButton = document.createElement("li"); - codeButton.className = "wmd-button"; - codeButton.id = "wmd-code-button"; - codeButton.title = "Code SampleCtrl+K"; - codeButton.XShift = "-80px"; - codeButton.textOp = command.doCode; - setupButton(codeButton, true); - buttonRow.appendChild(codeButton); - - var imageButton = document.createElement("li"); - imageButton.className = "wmd-button"; - imageButton.id = "wmd-image-button"; - imageButton.title = "ImageCtrl+G"; - imageButton.XShift = "-100px"; - imageButton.textOp = function(chunk, postProcessing, useDefaultText){ - return command.doLinkOrImage(chunk, postProcessing, true); - }; - setupButton(imageButton, true); - buttonRow.appendChild(imageButton); - - var spacer2 = document.createElement("li"); - spacer2.className = "wmd-spacer"; - spacer2.id = "wmd-spacer2"; - buttonRow.appendChild(spacer2); - - var olistButton = document.createElement("li"); - olistButton.className = "wmd-button"; - olistButton.id = "wmd-olist-button"; - olistButton.title = "Numbered List
Ctrl+O"; - olistButton.XShift = "-120px"; - olistButton.textOp = function(chunk, postProcessing, useDefaultText){ - command.doList(chunk, postProcessing, true, useDefaultText); - }; - setupButton(olistButton, true); - buttonRow.appendChild(olistButton); - - var ulistButton = document.createElement("li"); - ulistButton.className = "wmd-button"; - ulistButton.id = "wmd-ulist-button"; - ulistButton.title = "Bulleted List
Ctrl+U"; - ulistButton.XShift = "-140px"; - ulistButton.textOp = function(chunk, postProcessing, useDefaultText){ - command.doList(chunk, postProcessing, false, useDefaultText); - }; - setupButton(ulistButton, true); - buttonRow.appendChild(ulistButton); - - var headingButton = document.createElement("li"); - headingButton.className = "wmd-button"; - headingButton.id = "wmd-heading-button"; - headingButton.title = "Heading
/
Ctrl+H"; - headingButton.XShift = "-160px"; - headingButton.textOp = command.doHeading; - setupButton(headingButton, true); - buttonRow.appendChild(headingButton); - - var hrButton = document.createElement("li"); - hrButton.className = "wmd-button"; - hrButton.id = "wmd-hr-button"; - hrButton.title = "Horizontal Rule
Ctrl+R"; - hrButton.XShift = "-180px"; - hrButton.textOp = command.doHorizontalRule; - setupButton(hrButton, true); - buttonRow.appendChild(hrButton); - - var spacer3 = document.createElement("li"); - spacer3.className = "wmd-spacer"; - spacer3.id = "wmd-spacer3"; - buttonRow.appendChild(spacer3); - - var undoButton = document.createElement("li"); - undoButton.className = "wmd-button"; - undoButton.id = "wmd-undo-button"; - undoButton.title = "Undo - Ctrl+Z"; - undoButton.XShift = "-200px"; - undoButton.execute = function(manager){ - manager.undo(); - }; - setupButton(undoButton, true); - buttonRow.appendChild(undoButton); - - var redoButton = document.createElement("li"); - redoButton.className = "wmd-button"; - redoButton.id = "wmd-redo-button"; - redoButton.title = "Redo - Ctrl+Y"; - if (/win/.test(nav.platform.toLowerCase())) { - redoButton.title = "Redo - Ctrl+Y"; - } - else { - // mac and other non-Windows platforms - redoButton.title = "Redo - Ctrl+Shift+Z"; - } - redoButton.XShift = "-220px"; - redoButton.execute = function(manager){ - manager.redo(); - }; - setupButton(redoButton, true); - buttonRow.appendChild(redoButton); - - var helpButton = document.createElement("li"); - helpButton.className = "wmd-button"; - helpButton.id = "wmd-help-button"; - helpButton.XShift = "-240px"; - helpButton.isHelp = true; - - var helpAnchor = document.createElement("a"); - helpAnchor.href = helpLink; - helpAnchor.target = helpTarget - helpAnchor.title = helpHoverTitle; - helpButton.appendChild(helpAnchor); - - setupButton(helpButton, true); - buttonRow.appendChild(helpButton); - - setUndoRedoButtonStates(); - } - - var setupEditor = function(){ - - if (/\?noundo/.test(doc.location.href)) { - wmd.nativeUndo = true; - } - - if (!wmd.nativeUndo) { - undoMgr = new wmd.undoManager(function(){ - previewRefreshCallback(); - setUndoRedoButtonStates(); - }); - } - - makeSpritedButtonRow(); - - - var keyEvent = "keydown"; - if (global.isOpera) { - keyEvent = "keypress"; - } - - util.addEvent(inputBox, keyEvent, function(key){ - - // Check to see if we have a button key and, if so execute the callback. - if (key.ctrlKey || key.metaKey) { - - var keyCode = key.charCode || key.keyCode; - var keyCodeStr = String.fromCharCode(keyCode).toLowerCase(); - - switch(keyCodeStr) { - case "b": - doClick(document.getElementById("wmd-bold-button")); - break; - case "i": - doClick(document.getElementById("wmd-italic-button")); - break; - case "l": - doClick(document.getElementById("wmd-link-button")); - break; - case "q": - doClick(document.getElementById("wmd-quote-button")); - break; - case "k": - doClick(document.getElementById("wmd-code-button")); - break; - case "g": - doClick(document.getElementById("wmd-image-button")); - break; - case "o": - doClick(document.getElementById("wmd-olist-button")); - break; - case "u": - doClick(document.getElementById("wmd-ulist-button")); - break; - case "h": - doClick(document.getElementById("wmd-heading-button")); - break; - case "r": - doClick(document.getElementById("wmd-hr-button")); - break; - case "y": - doClick(document.getElementById("wmd-redo-button")); - break; - case "z": - if(key.shiftKey) { - doClick(document.getElementById("wmd-redo-button")); - } - else { - doClick(document.getElementById("wmd-undo-button")); - } - break; - default: - return; - } - - - if (key.preventDefault) { - key.preventDefault(); - } - - if (top.event) { - top.event.returnValue = false; - } - } - }); - - // Auto-continue lists, code blocks and block quotes when - // the enter key is pressed. - util.addEvent(inputBox, "keyup", function(key){ - if (!key.shiftKey && !key.ctrlKey && !key.metaKey) { - var keyCode = key.charCode || key.keyCode; - // Key code 13 is Enter - if (keyCode === 13) { - fakeButton = {}; - fakeButton.textOp = command.doAutoindent; - doClick(fakeButton); - } - } - }); - - // Disable ESC clearing the input textarea on IE - if (global.isIE) { - util.addEvent(inputBox, "keydown", function(key){ - var code = key.keyCode; - // Key code 27 is ESC - if (code === 27) { - return false; - } - }); - } - - if (inputBox.form) { - var submitCallback = inputBox.form.onsubmit; - inputBox.form.onsubmit = function(){ - convertToHtml(); - if (submitCallback) { - return submitCallback.apply(this, arguments); - } - }; - } - }; - - // Convert the contents of the input textarea to HTML in the output/preview panels. - var convertToHtml = function(){ - - if (wmd.showdown) { - var markdownConverter = new wmd.showdown.converter(); - } - var text = inputBox.value; - - var callback = function(){ - inputBox.value = text; - }; - - if (!/markdown/.test(wmd.wmd_env.output.toLowerCase())) { - if (markdownConverter) { - inputBox.value = markdownConverter.makeHtml(text); - top.setTimeout(callback, 0); - } - } - return true; - }; - - - this.undo = function(){ - if (undoMgr) { - undoMgr.undo(); - } - }; - - this.redo = function(){ - if (undoMgr) { - undoMgr.redo(); - } - }; - - // This is pretty useless. The setupEditor function contents - // should just be copied here. - var init = function(){ - setupEditor(); - }; - - this.destroy = function(){ - if (undoMgr) { - undoMgr.destroy(); - } - if (div.parentNode) { - div.parentNode.removeChild(div); - } - if (inputBox) { - inputBox.style.marginTop = ""; - } - top.clearInterval(creationHandle); - }; - - init(); - }; - - // The input textarea state/contents. - // This is used to implement undo/redo by the undo manager. - wmd.TextareaState = function(){ - - // Aliases - var stateObj = this; - var inputArea = wmd.panels.input; - - this.init = function() { - - if (!util.isVisible(inputArea)) { - return; - } - - this.setInputAreaSelectionStartEnd(); - this.scrollTop = inputArea.scrollTop; - if (!this.text && inputArea.selectionStart || inputArea.selectionStart === 0) { - this.text = inputArea.value; - } - - } - - // Sets the selected text in the input box after we've performed an - // operation. - this.setInputAreaSelection = function(){ - - if (!util.isVisible(inputArea)) { - return; - } - - if (inputArea.selectionStart !== undefined && !global.isOpera) { - - inputArea.focus(); - inputArea.selectionStart = stateObj.start; - inputArea.selectionEnd = stateObj.end; - inputArea.scrollTop = stateObj.scrollTop; - } - else if (doc.selection) { - - if (doc.activeElement && doc.activeElement !== inputArea) { - return; - } - - inputArea.focus(); - var range = inputArea.createTextRange(); - range.moveStart("character", -inputArea.value.length); - range.moveEnd("character", -inputArea.value.length); - range.moveEnd("character", stateObj.end); - range.moveStart("character", stateObj.start); - range.select(); - } - }; - - this.setInputAreaSelectionStartEnd = function(){ - - if (inputArea.selectionStart || inputArea.selectionStart === 0) { - - stateObj.start = inputArea.selectionStart; - stateObj.end = inputArea.selectionEnd; - } - else if (doc.selection) { - - stateObj.text = util.fixEolChars(inputArea.value); - - // IE loses the selection in the textarea when buttons are - // clicked. On IE we cache the selection and set a flag - // which we check for here. - var range; - if(wmd.ieRetardedClick && wmd.ieCachedRange) { - range = wmd.ieCachedRange; - wmd.ieRetardedClick = false; - } - else { - range = doc.selection.createRange(); - } - - var fixedRange = util.fixEolChars(range.text); - var marker = "\x07"; - var markedRange = marker + fixedRange + marker; - range.text = markedRange; - var inputText = util.fixEolChars(inputArea.value); - - range.moveStart("character", -markedRange.length); - range.text = fixedRange; - - stateObj.start = inputText.indexOf(marker); - stateObj.end = inputText.lastIndexOf(marker) - marker.length; - - var len = stateObj.text.length - util.fixEolChars(inputArea.value).length; - - if (len) { - range.moveStart("character", -fixedRange.length); - while (len--) { - fixedRange += "\n"; - stateObj.end += 1; - } - range.text = fixedRange; - } - - this.setInputAreaSelection(); - } - }; - - // Restore this state into the input area. - this.restore = function(){ - - if (stateObj.text != undefined && stateObj.text != inputArea.value) { - inputArea.value = stateObj.text; - } - this.setInputAreaSelection(); - inputArea.scrollTop = stateObj.scrollTop; - }; - - // Gets a collection of HTML chunks from the inptut textarea. - this.getChunks = function(){ - - var chunk = new wmd.Chunks(); - - chunk.before = util.fixEolChars(stateObj.text.substring(0, stateObj.start)); - chunk.startTag = ""; - chunk.selection = util.fixEolChars(stateObj.text.substring(stateObj.start, stateObj.end)); - chunk.endTag = ""; - chunk.after = util.fixEolChars(stateObj.text.substring(stateObj.end)); - chunk.scrollTop = stateObj.scrollTop; - - return chunk; - }; - - // Sets the TextareaState properties given a chunk of markdown. - this.setChunks = function(chunk){ - - chunk.before = chunk.before + chunk.startTag; - chunk.after = chunk.endTag + chunk.after; - - if (global.isOpera) { - chunk.before = chunk.before.replace(/\n/g, "\r\n"); - chunk.selection = chunk.selection.replace(/\n/g, "\r\n"); - chunk.after = chunk.after.replace(/\n/g, "\r\n"); - } - - this.start = chunk.before.length; - this.end = chunk.before.length + chunk.selection.length; - this.text = chunk.before + chunk.selection + chunk.after; - this.scrollTop = chunk.scrollTop; - }; - - this.init(); - }; - - // before: contains all the text in the input box BEFORE the selection. - // after: contains all the text in the input box AFTER the selection. - wmd.Chunks = function(){ - }; - - // startRegex: a regular expression to find the start tag - // endRegex: a regular expresssion to find the end tag - wmd.Chunks.prototype.findTags = function(startRegex, endRegex){ - - var chunkObj = this; - var regex; - - if (startRegex) { - - regex = util.extendRegExp(startRegex, "", "$"); - - this.before = this.before.replace(regex, - function(match){ - chunkObj.startTag = chunkObj.startTag + match; - return ""; - }); - - regex = util.extendRegExp(startRegex, "^", ""); - - this.selection = this.selection.replace(regex, - function(match){ - chunkObj.startTag = chunkObj.startTag + match; - return ""; - }); - } - - if (endRegex) { - - regex = util.extendRegExp(endRegex, "", "$"); - - this.selection = this.selection.replace(regex, - function(match){ - chunkObj.endTag = match + chunkObj.endTag; - return ""; - }); - - regex = util.extendRegExp(endRegex, "^", ""); - - this.after = this.after.replace(regex, - function(match){ - chunkObj.endTag = match + chunkObj.endTag; - return ""; - }); - } - }; - - // If remove is false, the whitespace is transferred - // to the before/after regions. - // - // If remove is true, the whitespace disappears. - wmd.Chunks.prototype.trimWhitespace = function(remove){ - - this.selection = this.selection.replace(/^(\s*)/, ""); - - if (!remove) { - this.before += re.$1; - } - - this.selection = this.selection.replace(/(\s*)$/, ""); - - if (!remove) { - this.after = re.$1 + this.after; - } - }; - - - wmd.Chunks.prototype.addBlankLines = function(nLinesBefore, nLinesAfter, findExtraNewlines){ - - if (nLinesBefore === undefined) { - nLinesBefore = 1; - } - - if (nLinesAfter === undefined) { - nLinesAfter = 1; - } - - nLinesBefore++; - nLinesAfter++; - - var regexText; - var replacementText; - - this.selection = this.selection.replace(/(^\n*)/, ""); - this.startTag = this.startTag + re.$1; - this.selection = this.selection.replace(/(\n*$)/, ""); - this.endTag = this.endTag + re.$1; - this.startTag = this.startTag.replace(/(^\n*)/, ""); - this.before = this.before + re.$1; - this.endTag = this.endTag.replace(/(\n*$)/, ""); - this.after = this.after + re.$1; - - if (this.before) { - - regexText = replacementText = ""; - - while (nLinesBefore--) { - regexText += "\\n?"; - replacementText += "\n"; - } - - if (findExtraNewlines) { - regexText = "\\n*"; - } - this.before = this.before.replace(new re(regexText + "$", ""), replacementText); - } - - if (this.after) { - - regexText = replacementText = ""; - - while (nLinesAfter--) { - regexText += "\\n?"; - replacementText += "\n"; - } - if (findExtraNewlines) { - regexText = "\\n*"; - } - - this.after = this.after.replace(new re(regexText, ""), replacementText); - } - }; - - // The markdown symbols - 4 spaces = code, > = blockquote, etc. - command.prefixes = "(?:\\s{4,}|\\s*>|\\s*-\\s+|\\s*\\d+\\.|=|\\+|-|_|\\*|#|\\s*\\[[^\n]]+\\]:)"; - - // Remove markdown symbols from the chunk selection. - command.unwrap = function(chunk){ - var txt = new re("([^\\n])\\n(?!(\\n|" + command.prefixes + "))", "g"); - chunk.selection = chunk.selection.replace(txt, "$1 $2"); - }; - - command.wrap = function(chunk, len){ - command.unwrap(chunk); - var regex = new re("(.{1," + len + "})( +|$\\n?)", "gm"); - - chunk.selection = chunk.selection.replace(regex, function(line, marked){ - if (new re("^" + command.prefixes, "").test(line)) { - return line; - } - return marked + "\n"; - }); - - chunk.selection = chunk.selection.replace(/\s+$/, ""); - }; - - command.doBold = function(chunk, postProcessing, useDefaultText){ - return command.doBorI(chunk, 2, "strong text"); - }; - - command.doItalic = function(chunk, postProcessing, useDefaultText){ - return command.doBorI(chunk, 1, "emphasized text"); - }; - - // chunk: The selected region that will be enclosed with */** - // nStars: 1 for italics, 2 for bold - // insertText: If you just click the button without highlighting text, this gets inserted - command.doBorI = function(chunk, nStars, insertText){ - - // Get rid of whitespace and fixup newlines. - chunk.trimWhitespace(); - chunk.selection = chunk.selection.replace(/\n{2,}/g, "\n"); - - // Look for stars before and after. Is the chunk already marked up? - chunk.before.search(/(\**$)/); - var starsBefore = re.$1; - - chunk.after.search(/(^\**)/); - var starsAfter = re.$1; - - var prevStars = Math.min(starsBefore.length, starsAfter.length); - - // Remove stars if we have to since the button acts as a toggle. - if ((prevStars >= nStars) && (prevStars != 2 || nStars != 1)) { - chunk.before = chunk.before.replace(re("[*]{" + nStars + "}$", ""), ""); - chunk.after = chunk.after.replace(re("^[*]{" + nStars + "}", ""), ""); - } - else if (!chunk.selection && starsAfter) { - // It's not really clear why this code is necessary. It just moves - // some arbitrary stuff around. - chunk.after = chunk.after.replace(/^([*_]*)/, ""); - chunk.before = chunk.before.replace(/(\s?)$/, ""); - var whitespace = re.$1; - chunk.before = chunk.before + starsAfter + whitespace; - } - else { - - // In most cases, if you don't have any selected text and click the button - // you'll get a selected, marked up region with the default text inserted. - if (!chunk.selection && !starsAfter) { - chunk.selection = insertText; - } - - // Add the true markup. - var markup = nStars <= 1 ? "*" : "**"; // shouldn't the test be = ? - chunk.before = chunk.before + markup; - chunk.after = markup + chunk.after; - } - - return; - }; - - command.stripLinkDefs = function(text, defsToAdd){ - - text = text.replace(/^[ ]{0,3}\[(\d+)\]:[ \t]*\n?[ \t]*(\S+?)>?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|$)/gm, - function(totalMatch, id, link, newlines, title){ - defsToAdd[id] = totalMatch.replace(/\s*$/, ""); - if (newlines) { - // Strip the title and return that separately. - defsToAdd[id] = totalMatch.replace(/["(](.+?)[")]$/, ""); - return newlines + title; - } - return ""; - }); - - return text; - }; - - command.addLinkDef = function(chunk, linkDef){ - - var refNumber = 0; // The current reference number - var defsToAdd = {}; // - // Start with a clean slate by removing all previous link definitions. - chunk.before = command.stripLinkDefs(chunk.before, defsToAdd); - chunk.selection = command.stripLinkDefs(chunk.selection, defsToAdd); - chunk.after = command.stripLinkDefs(chunk.after, defsToAdd); - - var defs = ""; - var regex = /(\[(?:\[[^\]]*\]|[^\[\]])*\][ ]?(?:\n[ ]*)?\[)(\d+)(\])/g; - - var addDefNumber = function(def){ - refNumber++; - def = def.replace(/^[ ]{0,3}\[(\d+)\]:/, " [" + refNumber + "]:"); - defs += "\n" + def; - }; - - var getLink = function(wholeMatch, link, id, end){ - - if (defsToAdd[id]) { - addDefNumber(defsToAdd[id]); - return link + refNumber + end; - - } - return wholeMatch; - }; - - chunk.before = chunk.before.replace(regex, getLink); - - if (linkDef) { - addDefNumber(linkDef); - } - else { - chunk.selection = chunk.selection.replace(regex, getLink); - } - - var refOut = refNumber; - - chunk.after = chunk.after.replace(regex, getLink); - - if (chunk.after) { - chunk.after = chunk.after.replace(/\n*$/, ""); - } - if (!chunk.after) { - chunk.selection = chunk.selection.replace(/\n*$/, ""); - } - - chunk.after += "\n\n" + defs; - - return refOut; - }; - - command.doLinkOrImage = function(chunk, postProcessing, isImage){ - - chunk.trimWhitespace(); - chunk.findTags(/\s*!?\[/, /\][ ]?(?:\n[ ]*)?(\[.*?\])?/); - - if (chunk.endTag.length > 1) { - - chunk.startTag = chunk.startTag.replace(/!?\[/, ""); - chunk.endTag = ""; - command.addLinkDef(chunk, null); - - } - else { - - if (/\n\n/.test(chunk.selection)) { - command.addLinkDef(chunk, null); - return; - } - - // The function to be executed when you enter a link and press OK or Cancel. - // Marks up the link and adds the ref. - var makeLinkMarkdown = function(link){ - - if (link !== null) { - - chunk.startTag = chunk.endTag = ""; - var linkDef = " [999]: " + link; - - var num = command.addLinkDef(chunk, linkDef); - chunk.startTag = isImage ? "![" : "["; - chunk.endTag = "][" + num + "]"; - - if (!chunk.selection) { - if (isImage) { - chunk.selection = "alt text"; - } - else { - chunk.selection = "link text"; - } - } - } - postProcessing(); - }; - - if (isImage) { - util.prompt(imageDialogText, imageDefaultText, makeLinkMarkdown); - } - else { - util.prompt(linkDialogText, linkDefaultText, makeLinkMarkdown); - } - return true; - } - }; - - util.makeAPI = function(){ - wmd.wmd = {}; - wmd.wmd.editor = wmd.editor; - wmd.wmd.previewManager = wmd.previewManager; - }; - - util.startEditor = function(){ - - if (wmd.wmd_env.autostart === false) { - util.makeAPI(); - return; - } - - var edit; // The editor (buttons + input + outputs) - the main object. - var previewMgr; // The preview manager. - - // Fired after the page has fully loaded. - var loadListener = function(){ - - wmd.panels = new wmd.PanelCollection(); - - previewMgr = new wmd.previewManager(); - var previewRefreshCallback = previewMgr.refresh; - - edit = new wmd.editor(previewRefreshCallback); - - previewMgr.refresh(true); - - }; - - util.addEvent(top, "load", loadListener); - }; - - wmd.previewManager = function(){ - - var managerObj = this; - var converter; - var poller; - var timeout; - var elapsedTime; - var oldInputText; - var htmlOut; - var maxDelay = 3000; - var startType = "delayed"; // The other legal value is "manual" - - // Adds event listeners to elements and creates the input poller. - var setupEvents = function(inputElem, listener){ - - util.addEvent(inputElem, "input", listener); - inputElem.onpaste = listener; - inputElem.ondrop = listener; - - util.addEvent(inputElem, "keypress", listener); - util.addEvent(inputElem, "keydown", listener); - // previewPollInterval is set at the top of this file. - poller = new wmd.inputPoller(listener, previewPollInterval); - }; - - var getDocScrollTop = function(){ - - var result = 0; - - if (top.innerHeight) { - result = top.pageYOffset; - } - else - if (doc.documentElement && doc.documentElement.scrollTop) { - result = doc.documentElement.scrollTop; - } - else - if (doc.body) { - result = doc.body.scrollTop; - } - - return result; - }; - - var makePreviewHtml = function(){ - - // If there are no registered preview and output panels - // there is nothing to do. - if (!wmd.panels.preview && !wmd.panels.output) { - return; - } - - var text = wmd.panels.input.value; - if (text && text == oldInputText) { - return; // Input text hasn't changed. - } - else { - oldInputText = text; - } - - var prevTime = new Date().getTime(); - - if (!converter && wmd.showdown) { - converter = new wmd.showdown.converter(); - } - - if (converter) { - text = converter.makeHtml(text); - } - - // Calculate the processing time of the HTML creation. - // It's used as the delay time in the event listener. - var currTime = new Date().getTime(); - elapsedTime = currTime - prevTime; - - pushPreviewHtml(text); - htmlOut = text; - }; - - // setTimeout is already used. Used as an event listener. - var applyTimeout = function(){ - - if (timeout) { - top.clearTimeout(timeout); - timeout = undefined; - } - - if (startType !== "manual") { - - var delay = 0; - - if (startType === "delayed") { - delay = elapsedTime; - } - - if (delay > maxDelay) { - delay = maxDelay; - } - timeout = top.setTimeout(makePreviewHtml, delay); - } - }; - - var getScaleFactor = function(panel){ - if (panel.scrollHeight <= panel.clientHeight) { - return 1; - } - return panel.scrollTop / (panel.scrollHeight - panel.clientHeight); - }; - - var setPanelScrollTops = function(){ - - if (wmd.panels.preview) { - wmd.panels.preview.scrollTop = (wmd.panels.preview.scrollHeight - wmd.panels.preview.clientHeight) * getScaleFactor(wmd.panels.preview); - ; - } - - if (wmd.panels.output) { - wmd.panels.output.scrollTop = (wmd.panels.output.scrollHeight - wmd.panels.output.clientHeight) * getScaleFactor(wmd.panels.output); - ; - } - }; - - this.refresh = function(requiresRefresh){ - - if (requiresRefresh) { - oldInputText = ""; - makePreviewHtml(); - } - else { - applyTimeout(); - } - }; - - this.processingTime = function(){ - return elapsedTime; - }; - - // The output HTML - this.output = function(){ - return htmlOut; - }; - - // The mode can be "manual" or "delayed" - this.setUpdateMode = function(mode){ - startType = mode; - managerObj.refresh(); - }; - - var isFirstTimeFilled = true; - - var pushPreviewHtml = function(text){ - - var emptyTop = position.getTop(wmd.panels.input) - getDocScrollTop(); - - // Send the encoded HTML to the output textarea/div. - if (wmd.panels.output) { - // The value property is only defined if the output is a textarea. - if (wmd.panels.output.value !== undefined) { - wmd.panels.output.value = text; - wmd.panels.output.readOnly = true; - } - // Otherwise we are just replacing the text in a div. - // Send the HTML wrapped in"; - } - } - - if (wmd.panels.preview) { - wmd.panels.preview.innerHTML = text; - } - - setPanelScrollTops(); - - if (isFirstTimeFilled) { - isFirstTimeFilled = false; - return; - } - - var fullTop = position.getTop(wmd.panels.input) - getDocScrollTop(); - - if (global.isIE) { - top.setTimeout(function(){ - top.scrollBy(0, fullTop - emptyTop); - }, 0); - } - else { - top.scrollBy(0, fullTop - emptyTop); - } - }; - - var init = function(){ - - setupEvents(wmd.panels.input, applyTimeout); - makePreviewHtml(); - - if (wmd.panels.preview) { - wmd.panels.preview.scrollTop = 0; - } - if (wmd.panels.output) { - wmd.panels.output.scrollTop = 0; - } - }; - - this.destroy = function(){ - if (poller) { - poller.destroy(); - } - }; - - init(); - }; - - // Moves the cursor to the next line and continues lists, quotes and code. - command.doAutoindent = function(chunk, postProcessing, useDefaultText){ - - chunk.before = chunk.before.replace(/(\n|^)[ ]{0,3}([*+-]|\d+[.])[ \t]*\n$/, "\n\n"); - chunk.before = chunk.before.replace(/(\n|^)[ ]{0,3}>[ \t]*\n$/, "\n\n"); - chunk.before = chunk.before.replace(/(\n|^)[ \t]+\n$/, "\n\n"); - - useDefaultText = false; - - if(/(\n|^)[ ]{0,3}([*+-])[ \t]+.*\n$/.test(chunk.before)){ - if(command.doList){ - command.doList(chunk, postProcessing, false, true); - } - } - if(/(\n|^)[ ]{0,3}(\d+[.])[ \t]+.*\n$/.test(chunk.before)){ - if(command.doList){ - command.doList(chunk, postProcessing, true, true); - } - } - if(/(\n|^)[ ]{0,3}>[ \t]+.*\n$/.test(chunk.before)){ - if(command.doBlockquote){ - command.doBlockquote(chunk, postProcessing, useDefaultText); - } - } - if(/(\n|^)(\t|[ ]{4,}).*\n$/.test(chunk.before)){ - if(command.doCode){ - command.doCode(chunk, postProcessing, useDefaultText); - } - } - }; - - command.doBlockquote = function(chunk, postProcessing, useDefaultText){ - - chunk.selection = chunk.selection.replace(/^(\n*)([^\r]+?)(\n*)$/, - function(totalMatch, newlinesBefore, text, newlinesAfter){ - chunk.before += newlinesBefore; - chunk.after = newlinesAfter + chunk.after; - return text; - }); - - chunk.before = chunk.before.replace(/(>[ \t]*)$/, - function(totalMatch, blankLine){ - chunk.selection = blankLine + chunk.selection; - return ""; - }); - - var defaultText = useDefaultText ? "Blockquote" : ""; - chunk.selection = chunk.selection.replace(/^(\s|>)+$/ ,""); - chunk.selection = chunk.selection || defaultText; - - if(chunk.before){ - chunk.before = chunk.before.replace(/\n?$/,"\n"); - } - if(chunk.after){ - chunk.after = chunk.after.replace(/^\n?/,"\n"); - } - - chunk.before = chunk.before.replace(/(((\n|^)(\n[ \t]*)*>(.+\n)*.*)+(\n[ \t]*)*$)/, - function(totalMatch){ - chunk.startTag = totalMatch; - return ""; - }); - - chunk.after = chunk.after.replace(/^(((\n|^)(\n[ \t]*)*>(.+\n)*.*)+(\n[ \t]*)*)/, - function(totalMatch){ - chunk.endTag = totalMatch; - return ""; - }); - - var replaceBlanksInTags = function(useBracket){ - - var replacement = useBracket ? "> " : ""; - - if(chunk.startTag){ - chunk.startTag = chunk.startTag.replace(/\n((>|\s)*)\n$/, - function(totalMatch, markdown){ - return "\n" + markdown.replace(/^[ ]{0,3}>?[ \t]*$/gm, replacement) + "\n"; - }); - } - if(chunk.endTag){ - chunk.endTag = chunk.endTag.replace(/^\n((>|\s)*)\n/, - function(totalMatch, markdown){ - return "\n" + markdown.replace(/^[ ]{0,3}>?[ \t]*$/gm, replacement) + "\n"; - }); - } - }; - - if(/^(?![ ]{0,3}>)/m.test(chunk.selection)){ - command.wrap(chunk, wmd.wmd_env.lineLength - 2); - chunk.selection = chunk.selection.replace(/^/gm, "> "); - replaceBlanksInTags(true); - chunk.addBlankLines(); - } - else{ - chunk.selection = chunk.selection.replace(/^[ ]{0,3}> ?/gm, ""); - command.unwrap(chunk); - replaceBlanksInTags(false); - - if(!/^(\n|^)[ ]{0,3}>/.test(chunk.selection) && chunk.startTag){ - chunk.startTag = chunk.startTag.replace(/\n{0,2}$/, "\n\n"); - } - - if(!/(\n|^)[ ]{0,3}>.*$/.test(chunk.selection) && chunk.endTag){ - chunk.endTag=chunk.endTag.replace(/^\n{0,2}/, "\n\n"); - } - } - - if(!/\n/.test(chunk.selection)){ - chunk.selection = chunk.selection.replace(/^(> *)/, - function(wholeMatch, blanks){ - chunk.startTag += blanks; - return ""; - }); - } - }; - - command.doCode = function(chunk, postProcessing, useDefaultText){ - - var hasTextBefore = /\S[ ]*$/.test(chunk.before); - var hasTextAfter = /^[ ]*\S/.test(chunk.after); - - // Use 'four space' markdown if the selection is on its own - // line or is multiline. - if((!hasTextAfter && !hasTextBefore) || /\n/.test(chunk.selection)){ - - chunk.before = chunk.before.replace(/[ ]{4}$/, - function(totalMatch){ - chunk.selection = totalMatch + chunk.selection; - return ""; - }); - - var nLinesBefore = 1; - var nLinesAfter = 1; - - - if(/\n(\t|[ ]{4,}).*\n$/.test(chunk.before) || chunk.after === ""){ - nLinesBefore = 0; - } - if(/^\n(\t|[ ]{4,})/.test(chunk.after)){ - nLinesAfter = 0; // This needs to happen on line 1 - } - - chunk.addBlankLines(nLinesBefore, nLinesAfter); - - if(!chunk.selection){ - chunk.startTag = " "; - chunk.selection = useDefaultText ? "enter code here" : ""; - } - else { - if(/^[ ]{0,3}\S/m.test(chunk.selection)){ - chunk.selection = chunk.selection.replace(/^/gm, " "); - } - else{ - chunk.selection = chunk.selection.replace(/^[ ]{4}/gm, ""); - } - } - } - else{ - // Use backticks (`) to delimit the code block. - - chunk.trimWhitespace(); - chunk.findTags(/`/, /`/); - - if(!chunk.startTag && !chunk.endTag){ - chunk.startTag = chunk.endTag="`"; - if(!chunk.selection){ - chunk.selection = useDefaultText ? "enter code here" : ""; - } - } - else if(chunk.endTag && !chunk.startTag){ - chunk.before += chunk.endTag; - chunk.endTag = ""; - } - else{ - chunk.startTag = chunk.endTag=""; - } - } - }; - - command.doList = function(chunk, postProcessing, isNumberedList, useDefaultText){ - - // These are identical except at the very beginning and end. - // Should probably use the regex extension function to make this clearer. - var previousItemsRegex = /(\n|^)(([ ]{0,3}([*+-]|\d+[.])[ \t]+.*)(\n.+|\n{2,}([*+-].*|\d+[.])[ \t]+.*|\n{2,}[ \t]+\S.*)*)\n*$/; - var nextItemsRegex = /^\n*(([ ]{0,3}([*+-]|\d+[.])[ \t]+.*)(\n.+|\n{2,}([*+-].*|\d+[.])[ \t]+.*|\n{2,}[ \t]+\S.*)*)\n*/; - - // The default bullet is a dash but others are possible. - // This has nothing to do with the particular HTML bullet, - // it's just a markdown bullet. - var bullet = "-"; - - // The number in a numbered list. - var num = 1; - - // Get the item prefix - e.g. " 1. " for a numbered list, " - " for a bulleted list. - var getItemPrefix = function(){ - var prefix; - if(isNumberedList){ - prefix = " " + num + ". "; - num++; - } - else{ - prefix = " " + bullet + " "; - } - return prefix; - }; - - // Fixes the prefixes of the other list items. - var getPrefixedItem = function(itemText){ - - // The numbering flag is unset when called by autoindent. - if(isNumberedList === undefined){ - isNumberedList = /^\s*\d/.test(itemText); - } - - // Renumber/bullet the list element. - itemText = itemText.replace(/^[ ]{0,3}([*+-]|\d+[.])\s/gm, - function( _ ){ - return getItemPrefix(); - }); - - return itemText; - }; - - chunk.findTags(/(\n|^)*[ ]{0,3}([*+-]|\d+[.])\s+/, null); - - if(chunk.before && !/\n$/.test(chunk.before) && !/^\n/.test(chunk.startTag)){ - chunk.before += chunk.startTag; - chunk.startTag = ""; - } - - if(chunk.startTag){ - - var hasDigits = /\d+[.]/.test(chunk.startTag); - chunk.startTag = ""; - chunk.selection = chunk.selection.replace(/\n[ ]{4}/g, "\n"); - command.unwrap(chunk); - chunk.addBlankLines(); - - if(hasDigits){ - // Have to renumber the bullet points if this is a numbered list. - chunk.after = chunk.after.replace(nextItemsRegex, getPrefixedItem); - } - if(isNumberedList == hasDigits){ - return; - } - } - - var nLinesBefore = 1; - - chunk.before = chunk.before.replace(previousItemsRegex, - function(itemText){ - if(/^\s*([*+-])/.test(itemText)){ - bullet = re.$1; - } - nLinesBefore = /[^\n]\n\n[^\n]/.test(itemText) ? 1 : 0; - return getPrefixedItem(itemText); - }); - - if(!chunk.selection){ - chunk.selection = useDefaultText ? "List item" : " "; - } - - var prefix = getItemPrefix(); - - var nLinesAfter = 1; - - chunk.after = chunk.after.replace(nextItemsRegex, - function(itemText){ - nLinesAfter = /[^\n]\n\n[^\n]/.test(itemText) ? 1 : 0; - return getPrefixedItem(itemText); - }); - - chunk.trimWhitespace(true); - chunk.addBlankLines(nLinesBefore, nLinesAfter, true); - chunk.startTag = prefix; - var spaces = prefix.replace(/./g, " "); - command.wrap(chunk, wmd.wmd_env.lineLength - spaces.length); - chunk.selection = chunk.selection.replace(/\n/g, "\n" + spaces); - - }; - - command.doHeading = function(chunk, postProcessing, useDefaultText){ - - // Remove leading/trailing whitespace and reduce internal spaces to single spaces. - chunk.selection = chunk.selection.replace(/\s+/g, " "); - chunk.selection = chunk.selection.replace(/(^\s+|\s+$)/g, ""); - - // If we clicked the button with no selected text, we just - // make a level 2 hash header around some default text. - if(!chunk.selection){ - chunk.startTag = "## "; - chunk.selection = "Heading"; - chunk.endTag = " ##"; - return; - } - - var headerLevel = 0; // The existing header level of the selected text. - - // Remove any existing hash heading markdown and save the header level. - chunk.findTags(/#+[ ]*/, /[ ]*#+/); - if(/#+/.test(chunk.startTag)){ - headerLevel = re.lastMatch.length; - } - chunk.startTag = chunk.endTag = ""; - - // Try to get the current header level by looking for - and = in the line - // below the selection. - chunk.findTags(null, /\s?(-+|=+)/); - if(/=+/.test(chunk.endTag)){ - headerLevel = 1; - } - if(/-+/.test(chunk.endTag)){ - headerLevel = 2; - } - - // Skip to the next line so we can create the header markdown. - chunk.startTag = chunk.endTag = ""; - chunk.addBlankLines(1, 1); - - // We make a level 2 header if there is no current header. - // If there is a header level, we substract one from the header level. - // If it's already a level 1 header, it's removed. - var headerLevelToCreate = headerLevel == 0 ? 2 : headerLevel - 1; - - if(headerLevelToCreate > 0){ - - // The button only creates level 1 and 2 underline headers. - // Why not have it iterate over hash header levels? Wouldn't that be easier and cleaner? - var headerChar = headerLevelToCreate >= 2 ? "-" : "="; - var len = chunk.selection.length; - if(len > wmd.wmd_env.lineLength){ - len = wmd.wmd_env.lineLength; - } - chunk.endTag = "\n"; - while(len--){ - chunk.endTag += headerChar; - } - } - }; - - command.doHorizontalRule = function(chunk, postProcessing, useDefaultText){ - chunk.startTag = "----------\n"; - chunk.selection = ""; - chunk.addBlankLines(2, 1, true); - } -}; - - -Attacklab.wmd_env = {}; -Attacklab.account_options = {}; -Attacklab.wmd_defaults = {version:1, output:"HTML", lineLength:40, delayLoad:false}; - -if(!Attacklab.wmd) -{ - Attacklab.wmd = function() - { - Attacklab.loadEnv = function() - { - var mergeEnv = function(env) - { - if(!env) - { - return; - } - - for(var key in env) - { - Attacklab.wmd_env[key] = env[key]; - } - }; - - mergeEnv(Attacklab.wmd_defaults); - mergeEnv(Attacklab.account_options); - mergeEnv(top["wmd_options"]); - Attacklab.full = true; - - var defaultButtons = "bold italic link blockquote code image ol ul heading hr"; - Attacklab.wmd_env.buttons = Attacklab.wmd_env.buttons || defaultButtons; - }; - Attacklab.loadEnv(); - - }; - - Attacklab.wmd(); - Attacklab.wmdBase(); - Attacklab.Util.startEditor(); -}; -- else { - var newText = text.replace(/&/g, "&"); - newText = newText.replace(/" + newText +>