diff --git a/Markdown.Editor.js b/Markdown.Editor.js
index d229fcd..20c938e 100644
--- a/Markdown.Editor.js
+++ b/Markdown.Editor.js
@@ -25,11 +25,6 @@
// this area.
// -------------------------------------------------------------------
- // The text that appears on the upper part of the dialog box when
- // entering links.
- var linkDialogText = "
http://example.com/ \"optional title\"
";
- var imageDialogText = "http://example.com/images/diagram.jpg \"optional title\"
";
-
// The default text that appears in the dialog input box when entering
// links.
var imageDefaultText = "http://";
@@ -49,10 +44,105 @@
// - getConverter() returns the markdown converter object that was passed to the constructor
// - run() actually starts the editor; should be called after all necessary plugins are registered. Calling this more than once is a no-op.
// - refreshPreview() forces the preview to be updated. This method is only available after run() was called.
- Markdown.Editor = function (markdownConverter, idPostfix, help) {
+ $.fn.markdown_editor = function ( option ) {
+ var args = Array.apply(null, arguments);
+ args.shift();
+ return this.each(function () {
+ var $this = $(this),
+ data = $this.data('datepicker'),
+ options = typeof option == 'object' && option;
+ if (!data) {
+ $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options))));
+ }
+ if (typeof option == 'string' && typeof data[option] == 'function') {
+ data[option].apply(data, args);
+ }
+ });
+ };
+ $.fn.markdown_editor.defaults = {
+ };
- idPostfix = idPostfix || "";
+ $.fn.markdown_editor.Constructor = Markdown.Editor;
+
+ var translations = $.fn.markdown_editor.translations = {
+ en: {
+ tooltips: {
+ bold: 'Bold - Ctrl+B',
+ bold_insertion: 'strong text',
+ italic: 'Italic - Ctrl+I',
+ italic_insertion: 'emphasized text',
+ quote: 'Blockquote - Ctrl+Q',
+ quote_insertion: 'Blockquote',
+ code: 'Code Sample - Ctrl+K',
+ code_insertion: 'enter code here',
+ olist: 'Numbered List - Ctrl+O',
+ olist_insertion: 'List item',
+ ulist: 'Bulleted List - Ctrl+U',
+ ulist_insertion: 'List item',
+ heading: 'Heading - Ctrl+H',
+ heading_insertion: 'Heading',
+ link: 'Link - Ctrl+L',
+ image: 'Image - Ctrl+G',
+ hr: 'Horizontal Rule - Ctrl+R',
+ undo: 'Undo - Ctrl+Z',
+ redo_pc: 'Redo - Ctrl+Y',
+ redo_mac: 'Redo - Ctrl+Shift+Z',
+ emotions: 'Emotions - Ctrl+E'
+ },
+ dialog_text: {
+ link_title: "Insert Link",
+ link_example: "http://example.com/ \"optional title\"
",
+ link_description: "enter link description here" ,
+ image_title: "Insert Image",
+ image_example: "http://example.com/images/diagram.jpg \"optional title\"
",
+ image_description: "enter image description here" ,
+ },
+ button_text: {
+ ok: "OK",
+ cancel: "Cancel"
+ }
+ }
+ };
+
+ // call this function before construct Editor if you want your editor to support emotions
+ /*
+ imgPath:
+ '/static/img/'
+
+ emotions:
+ [['cool.gif', 'arrow.gif', 'biggrin.gif', 'confused.gif', 'cry.gif', 'eek.gif','neutral.gif'],
+ ['evil.gif', 'exclaim.gif', 'idea.gif', 'lol.gif', 'mad.gif', 'mrgreen.gif','question.gif'],
+ ['razz.gif', 'redface.gif', 'rolleyes.gif', 'sad.gif','smile.gif','surprised.gif', 'twisted.gif'],
+ ['wink.gif']]
+ */
+
+ Markdown.SupportEmotions = function(imgPath,emotions){
+ var imgPath = imgPath || '/static/img/';
+ if (typeof emotions == 'undefined')
+ return;
+
+ emotionsTableBody = [''];
+ for (var i=0,len=emotions.length; i']
+ for (j=0; j']
+ tr.push(td.join(''));
+ }
+ tr.push('')
+ emotionsTableBody.push(tr.join(''));
+ }
+
+ emotionsTableBody.push('');
+ emotionsTableBody = emotionsTableBody.join('');
+ }
+ Markdown.Editor = function (markdownConverter, idPostfix, help, language) {
+
+ idPostfix = idPostfix || "";
+ this.language = language != undefined ? language : "en";
+ this.language = this.language in translations ? this.language : "en";
var hooks = this.hooks = new Markdown.HookCollection();
hooks.addNoop("onPreviewRefresh"); // called with no arguments after the preview has been refreshed
hooks.addNoop("postBlockquoteCreation"); // called with the user's selection *after* the blockquote was created; should return the actual to-be-inserted text
@@ -88,7 +178,7 @@
}
}
- uiManager = new UIManager(idPostfix, panels, undoManager, previewManager, commandManager, help);
+ uiManager = new UIManager(idPostfix, panels, undoManager, previewManager, commandManager, help, this.language);
uiManager.setUndoRedoButtonStates();
var forceRefresh = that.refreshPreview = function () { previewManager.refresh(true); };
@@ -347,6 +437,16 @@
return result;
};
+ position.getLeft = function (elem, isInner) {
+ var result = elem.offsetLeft;
+ if (!isInner) {
+ while (elem = elem.offsetParent) {
+ result += elem.offsetLeft;
+ }
+ }
+ return result;
+ };
+
position.getHeight = function (elem) {
return elem.offsetHeight || elem.scrollHeight;
};
@@ -973,12 +1073,13 @@
// callback: The function which is executed when the prompt is dismissed, either via OK or Cancel.
// It receives a single argument; either the entered text (if OK was chosen) or null (if Cancel
// was chosen).
- ui.prompt = function (title, text, defaultInputText, callback) {
+ ui.prompt = function (title, text, defaultInputText, callback, language) {
// These variables need to be declared at this level since they are used
// in multiple functions.
var dialog; // The dialog box.
var input; // The text box where you enter the hyperlink.
+ var button_text = translations[language].button_text;
if (defaultInputText === undefined) {
@@ -1085,14 +1186,14 @@
okButton.className = "btn btn-primary";
okButton.type = "button";
okButton.onclick = function () { return close(false); };
- okButton.innerHTML = "OK";
+ okButton.innerHTML = button_text.ok;
// The cancel button
var cancelButton = doc.createElement("button");
cancelButton.className = "btn btn-primary";
cancelButton.type = "button";
cancelButton.onclick = function () { return close(true); };
- cancelButton.innerHTML = "Cancel";
+ cancelButton.innerHTML = button_text.cancel;
footer.appendChild(okButton);
footer.appendChild(cancelButton);
@@ -1135,8 +1236,53 @@
}, 0);
};
- function UIManager(postfix, panels, undoManager, previewManager, commandManager, helpOptions) {
+ ui.emotions = function(title,callback,pos){
+ var checkExist = function(){
+ var last_pos = {top:position.getTop(emotions_div),left:position.getLeft(emotions_div)}
+ if (pos.left == last_pos.left && pos.top == last_pos.top)
+ return true;
+ return false;
+ }
+
+ var createEmotions = function(){
+ //
+
+ // show/toggle it if you have already create it && rebind the callback
+ if (typeof emotions_div != 'undefined'){
+ $(emotions_table).unbind('click').click(callback);
+ return (checkExist())?$(emotions_div).toggle():$(emotions_div).show();
+ }
+
+ // The body
+ emotions_div = doc.createElement("div");
+ emotions_div.className = "emotions-body";
+ emotions_div.style.position = 'absolute';
+ emotions_div.style.background = 'white';
+ emotions_div.style.border = '1px solid #ddd';
+
+ emotions_table = doc.createElement("table");
+ emotions_table.className= "emotions-table";
+ $(emotions_table).html(emotionsTableBody);
+ emotions_table.style.margin = "2px";
+
+ emotions_div.appendChild(emotions_table);
+ $(emotions_div).mouseleave(function(){emotions_div.style.display = 'none'});
+ $(emotions_table).click(callback);
+ doc.body.appendChild(emotions_div);
+ }
+
+ setTimeout(function () {
+ createEmotions();
+ $(emotions_div).css(pos);
+ }, 0);
+
+ }
+
+ function UIManager(postfix, panels, undoManager, previewManager, commandManager, helpOptions, language) {
+
var inputBox = panels.input,
buttons = {}; // buttons.undo, buttons.link, etc. The actual DOM elements.
@@ -1186,6 +1332,9 @@
case "r":
doClick(buttons.hr);
break;
+ case "e":
+ doClick(buttons.emotion);
+ break;
case "y":
doClick(buttons.redo);
break;
@@ -1283,8 +1432,8 @@
state.restore();
previewManager.refresh();
};
-
- var noCleanup = button.textOp(chunks, fixupInputArea);
+ var pos = {top:position.getTop(button)+30, left:position.getLeft(button)}
+ var noCleanup = button.textOp(chunks, fixupInputArea, pos);
if (!noCleanup) {
fixupInputArea();
@@ -1359,36 +1508,50 @@
}
group1 = makeGroup(1);
- buttons.bold = makeButton("wmd-bold-button", "Bold - Ctrl+B", "icon-bold", bindCommand("doBold"), group1);
- buttons.italic = makeButton("wmd-italic-button", "Italic - Ctrl+I", "icon-italic", bindCommand("doItalic"), group1);
+ var tooltips = translations[language].tooltips;
+ buttons.bold = makeButton("wmd-bold-button", tooltips.bold, "icon-bold", bindCommand(function (chunk, postProcessing, language) {
+ return this.doBorI(chunk, postProcessing, 2, tooltips.bold_insertion);
+ }), group1);
+ buttons.italic = makeButton("wmd-italic-button", tooltips.italic, "icon-italic", bindCommand(function (chunk, postProcessing) {
+ return this.doBorI(chunk, postProcessing, 1, tooltips.italic_insertion);
+ }), group1);
group2 = makeGroup(2);
- buttons.link = makeButton("wmd-link-button", "Link - Ctrl+L", "icon-link", bindCommand(function (chunk, postProcessing) {
- return this.doLinkOrImage(chunk, postProcessing, false);
+ buttons.link = makeButton("wmd-link-button", tooltips.link, "icon-link", bindCommand(function (chunk, postProcessing) {
+ return this.doLinkOrImage(chunk, postProcessing, false, language);
}), group2);
- buttons.quote = makeButton("wmd-quote-button", "Blockquote - Ctrl+Q", "icon-blockquote", bindCommand("doBlockquote"), group2);
- buttons.code = makeButton("wmd-code-button", "Code Sample - Ctrl+K", "icon-code", bindCommand("doCode"), group2);
- buttons.image = makeButton("wmd-image-button", "Image - Ctrl+G", "icon-picture", bindCommand(function (chunk, postProcessing) {
- return this.doLinkOrImage(chunk, postProcessing, true);
+ buttons.quote = makeButton("wmd-quote-button", tooltips.quote, "icon-blockquote", bindCommand(function (chunk, postProcessing) {
+ return this.doBlockquote(chunk, postProcessing, tooltips.quote_insertion)
+ }), group2);
+ buttons.code = makeButton("wmd-code-button", tooltips.code, "icon-code", bindCommand(function (chunk, postProcessing) {
+ return this.doCode(chunk, postProcessing, tooltips.code_insertion)
+ }), group2);
+ buttons.image = makeButton("wmd-image-button", tooltips.image, "icon-picture", bindCommand(function (chunk, postProcessing) {
+ return this.doLinkOrImage(chunk, postProcessing, true, language);
}), group2);
group3 = makeGroup(3);
- buttons.olist = makeButton("wmd-olist-button", "Numbered List - Ctrl+O", "icon-list", bindCommand(function (chunk, postProcessing) {
- this.doList(chunk, postProcessing, true);
+ buttons.olist = makeButton("wmd-olist-button", tooltips.olist, "icon-list", bindCommand(function (chunk, postProcessing) {
+ this.doList(chunk, postProcessing, true, tooltips.olist_insertion);
}), group3);
- buttons.ulist = makeButton("wmd-ulist-button", "Bulleted List - Ctrl+U", "icon-bullet-list", bindCommand(function (chunk, postProcessing) {
- this.doList(chunk, postProcessing, false);
+ buttons.ulist = makeButton("wmd-ulist-button", tooltips.ulist, "icon-bullet-list", bindCommand(function (chunk, postProcessing) {
+ this.doList(chunk, postProcessing, false, tooltips.ulist_insertion);
}), group3);
- buttons.heading = makeButton("wmd-heading-button", "Heading - Ctrl+H", "icon-header", bindCommand("doHeading"), group3);
- buttons.hr = makeButton("wmd-hr-button", "Horizontal Rule - Ctrl+R", "icon-hr-line", bindCommand("doHorizontalRule"), group3);
+ buttons.heading = makeButton("wmd-heading-button", tooltips.heading, "icon-header", bindCommand(function(chunk, postProcessing) {
+ this.doHeading(chunk, postProcessing, tooltips.heading_insertion);
+ }), group3)
+ buttons.hr = makeButton("wmd-hr-button", tooltips.hr, "icon-hr-line", bindCommand("doHorizontalRule"), group3);
+ // add emotion button if emotionsTablyBody defined
+ if (typeof emotionsTableBody != 'undefined')
+ buttons.emotion = makeButton("wmd-emotion-button",tooltips.emotions,"icon-th",bindCommand("doEmotion"), group3)
group4 = makeGroup(4);
- buttons.undo = makeButton("wmd-undo-button", "Undo - Ctrl+Z", "icon-undo", null, group4);
+ buttons.undo = makeButton("wmd-undo-button", tooltips.undo, "icon-undo", null, group4);
buttons.undo.execute = function (manager) { if (manager) manager.undo(); };
var redoTitle = /win/.test(nav.platform.toLowerCase()) ?
- "Redo - Ctrl+Y" :
- "Redo - Ctrl+Shift+Z"; // mac and other non-Windows platforms
+ tooltips.redo_pc :
+ tooltips.redo_mac; // mac and other non-Windows platforms
buttons.redo = makeButton("wmd-redo-button", redoTitle, "icon-share-alt", null, group4);
buttons.redo.execute = function (manager) { if (manager) manager.redo(); };
@@ -1456,13 +1619,7 @@
chunk.selection = chunk.selection.replace(/\s+$/, "");
};
- commandProto.doBold = function (chunk, postProcessing) {
- return this.doBorI(chunk, postProcessing, 2, "strong text");
- };
-
- commandProto.doItalic = function (chunk, postProcessing) {
- return this.doBorI(chunk, postProcessing, 1, "emphasized text");
- };
+ commandProto.doItalic =
// chunk: The selected region that will be enclosed with */**
// nStars: 1 for italics, 2 for bold
@@ -1603,11 +1760,12 @@
});
}
- commandProto.doLinkOrImage = function (chunk, postProcessing, isImage) {
+ commandProto.doLinkOrImage = function (chunk, postProcessing, isImage, language) {
chunk.trimWhitespace();
chunk.findTags(/\s*!?\[/, /\][ ]?(?:\n[ ]*)?(\[.*?\])?/);
var background;
+ var dialog_text = translations[language].dialog_text;
if (chunk.endTag.length > 1 && chunk.startTag.length > 0) {
@@ -1662,23 +1820,22 @@
if (!chunk.selection) {
if (isImage) {
- chunk.selection = "enter image description here";
+ chunk.selection = dialog_text.image_description;
}
else {
- chunk.selection = "enter link description here";
+ chunk.selection = dialog_text.link_description;
}
}
}
postProcessing();
};
-
if (isImage) {
if (!this.hooks.insertImageDialog(linkEnteredCallback))
- ui.prompt('Insert Image', imageDialogText, imageDefaultText, linkEnteredCallback);
+ ui.prompt(dialog_text.image_title, dialog_text.image_example, imageDefaultText, linkEnteredCallback, language);
}
else {
- ui.prompt('Insert Link', linkDialogText, linkDefaultText, linkEnteredCallback);
+ ui.prompt(dialog_text.link_title, dialog_text.link_example, linkDefaultText, linkEnteredCallback, language);
}
return true;
}
@@ -1729,7 +1886,7 @@
}
};
- commandProto.doBlockquote = function (chunk, postProcessing) {
+ commandProto.doBlockquote = function (chunk, postProcessing, default_insertion) {
chunk.selection = chunk.selection.replace(/^(\n*)([^\r]+?)(\n*)$/,
function (totalMatch, newlinesBefore, text, newlinesAfter) {
@@ -1745,7 +1902,7 @@
});
chunk.selection = chunk.selection.replace(/^(\s|>)+$/, "");
- chunk.selection = chunk.selection || "Blockquote";
+ chunk.selection = chunk.selection || default_insertion;
// The original code uses a regular expression to find out how much of the
// text *directly before* the selection already was a blockquote:
@@ -1873,8 +2030,7 @@
}
};
- commandProto.doCode = function (chunk, postProcessing) {
-
+ commandProto.doCode = function (chunk, postProcessing, default_insertion) {
var hasTextBefore = /\S[ ]*$/.test(chunk.before);
var hasTextAfter = /^[ ]*\S/.test(chunk.after);
@@ -1902,7 +2058,7 @@
if (!chunk.selection) {
chunk.startTag = " ";
- chunk.selection = "enter code here";
+ chunk.selection = default_insertion;
}
else {
if (/^[ ]{0,3}\S/m.test(chunk.selection)) {
@@ -1938,7 +2094,7 @@
}
};
- commandProto.doList = function (chunk, postProcessing, isNumberedList) {
+ commandProto.doList = function (chunk, postProcessing, isNumberedList, default_insertion) {
// These are identical except at the very beginning and end.
// Should probably use the regex extension function to make this clearer.
@@ -2019,7 +2175,7 @@
});
if (!chunk.selection) {
- chunk.selection = "List item";
+ chunk.selection = default_insertion;
}
var prefix = getItemPrefix();
@@ -2041,7 +2197,7 @@
};
- commandProto.doHeading = function (chunk, postProcessing) {
+ commandProto.doHeading = function (chunk, postProcessing, default_heading) {
// Remove leading/trailing whitespace and reduce internal spaces to single spaces.
chunk.selection = chunk.selection.replace(/\s+/g, " ");
@@ -2051,7 +2207,7 @@
// make a level 2 hash header around some default text.
if (!chunk.selection) {
chunk.startTag = "## ";
- chunk.selection = "Heading";
+ chunk.selection = default_heading;
chunk.endTag = " ##";
return;
}
@@ -2106,5 +2262,15 @@
chunk.skipLines(2, 1, true);
}
+ commandProto.doEmotion = function(chunk, postProcessing,pos){
+ var tdClickCallback = function(e){
+ var value= e.target.getAttribute('src');
+ var mark = '![]('+value+')';
+ chunk.startTag=mark;
+ postProcessing();
+ return false;
+ }
-})();
\ No newline at end of file
+ ui.emotions("Emotions",tdClickCallback,pos);
+ }
+})();
diff --git a/README.md b/README.md
index 76f5547..a2073a4 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,21 @@
-PageDown-Bootstrap
-==================
+PageDown-bootstrap with i18n and emotion support
+=======================
-This is a fork of http://code.google.com/p/pagedown/ changed to use Twitter Bootstrap for styling the editor and modal popups.
+> This is a fork of https://github.com/samwillis/pagedown-bootstrap to add i18n and emotions support
-The demo is viewable here: http://samwillis.co.uk/pagedown-bootstrap/demo/browser/demo.html
+**i18n support**
+
+Currenly the hint and the hover tooltips are seperated from Markdown.Editor.js to i18n/Markdown.i18n.LANGUAGE.js, where translations are located. Only chinese translation is complete, but you can add pretty much any language as you like. Just make sure the format looks like the i18n/Markdown.i18n.zh-cn.js file(Your pull requests are always welcome!).
+
+Usage:
+
+reference the translation file in your template and pass a language preference to set the editor language when you are constructing your editor in your js code
+
+**emotions**
+
+You have to call Markdown.SupportEmotions(imgPath,emotions) before constructing your
+editor if your want it to include emotions
+
+The demo is viewable here: http://shellfly.org/pagedown-with-emotions/demo/browser/demo.html
New icons based on http://glyphicons.com/, http://dribbble.com/shots/365544-Mini-glyphs-12-px-Free-PSD and the origional icons.
diff --git a/demo/browser/demo.html b/demo/browser/demo.html
index 9cc1e4c..3d214b3 100644
--- a/demo/browser/demo.html
+++ b/demo/browser/demo.html
@@ -22,13 +22,14 @@
-
+
+
@@ -81,6 +82,7 @@ 2. This is a custom editor