My personal site (brandoncornejo.name) (binaryatrocity.name)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

335 lines
12 KiB

10 years ago
  1. /*! UIkit 2.3.1 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */
  2. (function(global, $, UI){
  3. var Markdownarea = function(element, options){
  4. var $element = $(element);
  5. if($element.data("markdownarea")) return;
  6. this.element = $element;
  7. this.options = $.extend({}, Markdownarea.defaults, options);
  8. this.init();
  9. this.element.data("markdownarea", this);
  10. };
  11. $.extend(Markdownarea.prototype, {
  12. init: function(){
  13. var $this = this, tpl = Markdownarea.template;
  14. tpl = tpl.replace(/\{\:lblPreview\}/g, this.options.lblPreview);
  15. tpl = tpl.replace(/\{\:lblCodeview\}/g, this.options.lblCodeview);
  16. this.markdownarea = $(tpl);
  17. this.content = this.markdownarea.find(".uk-markdownarea-content");
  18. this.toolbar = this.markdownarea.find(".uk-markdownarea-toolbar");
  19. this.preview = this.markdownarea.find(".uk-markdownarea-preview").children().eq(0);
  20. this.code = this.markdownarea.find(".uk-markdownarea-code");
  21. this.element.before(this.markdownarea).appendTo(this.code);
  22. this.editor = CodeMirror.fromTextArea(this.element[0], this.options.codemirror);
  23. this.editor.markdownarea = this;
  24. this.editor.on("change", (function(){
  25. var render = function(){
  26. var value = $this.editor.getValue();
  27. $this.originalvalue = String(value);
  28. $this.currentvalue = String(value);
  29. $this.element.trigger("markdownarea-before", [$this]);
  30. marked($this.currentvalue, function (err, markdown) {
  31. if (err) throw err;
  32. $this.preview.html(markdown);
  33. $this.element.val($this.currentvalue).trigger("markdownarea-update", [$this]);
  34. });
  35. };
  36. render();
  37. return UI.Utils.debounce(render, 200);
  38. })());
  39. this._buildtoolbar();
  40. this.fit();
  41. $(window).on("resize", UI.Utils.debounce(function(){
  42. $this.fit();
  43. }, 200));
  44. var previewContainer = $this.preview.parent(),
  45. codeContent = this.code.find('.CodeMirror-sizer'),
  46. codeScroll = this.code.find('.CodeMirror-scroll').on('scroll',UI.Utils.debounce(function() {
  47. if($this.markdownarea.attr("data-mode")=="tab") return;
  48. // calc position
  49. var codeHeight = codeContent.height() - codeScroll.height(),
  50. previewHeight = previewContainer[0].scrollHeight - previewContainer.height(),
  51. ratio = previewHeight / codeHeight,
  52. previewPostition = codeScroll.scrollTop() * ratio;
  53. // apply new scroll
  54. previewContainer.scrollTop(previewPostition);
  55. }, 10));
  56. this.markdownarea.on("click", ".uk-markdown-button-markdown, .uk-markdown-button-preview", function(e){
  57. e.preventDefault();
  58. if($this.markdownarea.attr("data-mode")=="tab") {
  59. $this.markdownarea.find(".uk-markdown-button-markdown, .uk-markdown-button-preview").removeClass("uk-active").filter(this).addClass("uk-active");
  60. $this.activetab = $(this).hasClass("uk-markdown-button-markdown") ? "code":"preview";
  61. $this.markdownarea.attr("data-active-tab", $this.activetab);
  62. }
  63. });
  64. this.preview.parent().css("height", this.code.height());
  65. },
  66. _buildtoolbar: function(){
  67. if(!(this.options.toolbar && this.options.toolbar.length)) return;
  68. var $this = this, bar = [];
  69. this.options.toolbar.forEach(function(cmd){
  70. if(Markdownarea.commands[cmd]) {
  71. var title = Markdownarea.commands[cmd].title ? Markdownarea.commands[cmd].title : cmd;
  72. bar.push('<li><a data-markdownarea-cmd="'+cmd+'" title="'+title+'" data-uk-tooltip>'+Markdownarea.commands[cmd].label+'</a></li>');
  73. if(Markdownarea.commands[cmd].shortcut) {
  74. $this.registerShortcut(Markdownarea.commands[cmd].shortcut, Markdownarea.commands[cmd].action);
  75. }
  76. }
  77. });
  78. this.toolbar.html(bar.join("\n"));
  79. this.markdownarea.on("click", "a[data-markdownarea-cmd]", function(){
  80. var cmd = $(this).data("markdownareaCmd");
  81. if(cmd && Markdownarea.commands[cmd] && (!$this.activetab || $this.activetab=="code")) {
  82. Markdownarea.commands[cmd].action.apply($this, [$this.editor])
  83. }
  84. });
  85. },
  86. fit: function() {
  87. var mode = this.options.mode;
  88. if(mode=="split" && this.markdownarea.width() < this.options.maxsplitsize) {
  89. mode = "tab";
  90. }
  91. if(mode=="tab") {
  92. if(!this.activetab) {
  93. this.activetab = "code";
  94. this.markdownarea.attr("data-active-tab", this.activetab);
  95. }
  96. this.markdownarea.find(".uk-markdown-button-markdown, .uk-markdown-button-preview").removeClass("uk-active")
  97. .filter(this.activetab=="code" ? '.uk-markdown-button-markdown':'.uk-markdown-button-preview').addClass("uk-active");
  98. }
  99. this.markdownarea.attr("data-mode", mode);
  100. },
  101. registerShortcut: function(combination, callback){
  102. var $this = this;
  103. combination = $.isArray(combination) ? combination : [combination];
  104. for(var i=0,max=combination.length;i < max;i++) {
  105. var map = {};
  106. map[combination[i]] = function(){
  107. callback.apply($this, [$this.editor]);
  108. };
  109. $this.editor.addKeyMap(map);
  110. }
  111. }
  112. });
  113. //jQuery plugin
  114. $.fn.markdownarea = function(options){
  115. return this.each(function(){
  116. var ele = $(this);
  117. if(!ele.data("markdownarea")) {
  118. var obj = new Markdownarea(ele, options);
  119. }
  120. });
  121. };
  122. var baseReplacer = function(replace, editor){
  123. var text = editor.getSelection(),
  124. markdown = replace.replace('$1', text);
  125. editor.replaceSelection(markdown, 'end');
  126. };
  127. Markdownarea.commands = {
  128. "fullscreen": {
  129. "title" : 'Fullscreen',
  130. "label" : '<i class="uk-icon-expand"></i>',
  131. "action" : function(editor){
  132. editor.markdownarea.markdownarea.toggleClass("uk-markdownarea-fullscreen");
  133. var wrap = editor.getWrapperElement();
  134. if(editor.markdownarea.markdownarea.hasClass("uk-markdownarea-fullscreen")) {
  135. editor.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset, width: wrap.style.width, height: wrap.style.height};
  136. wrap.style.width = "";
  137. wrap.style.height = editor.markdownarea.content.height()+"px";
  138. document.documentElement.style.overflow = "hidden";
  139. } else {
  140. document.documentElement.style.overflow = "";
  141. var info = editor.state.fullScreenRestore;
  142. wrap.style.width = info.width; wrap.style.height = info.height;
  143. window.scrollTo(info.scrollLeft, info.scrollTop);
  144. }
  145. editor.refresh();
  146. editor.markdownarea.preview.parent().css("height", editor.markdownarea.code.height());
  147. }
  148. },
  149. "bold" : {
  150. "title" : "Bold",
  151. "label" : '<i class="uk-icon-bold"></i>',
  152. "shortcut": ['Ctrl-B', 'Cmd-B'],
  153. "action" : function(editor){
  154. baseReplacer("**$1**", editor);
  155. }
  156. },
  157. "italic" : {
  158. "title" : "Italic",
  159. "label" : '<i class="uk-icon-italic"></i>',
  160. "action" : function(editor){
  161. baseReplacer("*$1*", editor);
  162. }
  163. },
  164. "strike" : {
  165. "title" : "Strikethrough",
  166. "label" : '<i class="uk-icon-strikethrough"></i>',
  167. "action" : function(editor){
  168. baseReplacer("~~$1~~", editor);
  169. }
  170. },
  171. "blockquote" : {
  172. "title" : "Blockquote",
  173. "label" : '<i class="uk-icon-quote-right"></i>',
  174. "action" : function(editor){
  175. baseReplacer("> $1", editor);
  176. }
  177. },
  178. "link" : {
  179. "title" : "Link",
  180. "label" : '<i class="uk-icon-link"></i>',
  181. "action" : function(editor){
  182. baseReplacer("[$1](http://)", editor);
  183. }
  184. },
  185. "picture" : {
  186. "title" : "Picture",
  187. "label" : '<i class="uk-icon-picture-o"></i>',
  188. "action" : function(editor){
  189. baseReplacer("![$1](http://)", editor);
  190. }
  191. },
  192. "listUl" : {
  193. "title" : "Unordered List",
  194. "label" : '<i class="uk-icon-list-ul"></i>',
  195. "action" : function(editor){
  196. baseReplacer("* $1", editor);
  197. }
  198. },
  199. "listOl" : {
  200. "title" : "Ordered List",
  201. "label" : '<i class="uk-icon-list-ol"></i>',
  202. "action" : function(editor){
  203. baseReplacer("1. $1", editor);
  204. }
  205. }
  206. }
  207. Markdownarea.defaults = {
  208. "mode" : "split",
  209. "maxsplitsize" : 1000,
  210. "codemirror" : { mode: 'gfm', tabMode: 'indent', tabindex: "2", lineWrapping: true, dragDrop: false },
  211. "toolbar" : [ "bold", "italic", "strike", "link", "picture", "blockquote", "listUl", "listOl" ],
  212. "lblPreview" : "Preview",
  213. "lblCodeview" : "Markdown"
  214. };
  215. Markdownarea.template = '<div class="uk-markdownarea uk-clearfix" data-mode="split">' +
  216. '<div class="uk-markdownarea-navbar">' +
  217. '<ul class="uk-markdownarea-navbar-nav uk-markdownarea-toolbar"></ul>' +
  218. '<div class="uk-markdownarea-navbar-flip">' +
  219. '<ul class="uk-markdownarea-navbar-nav">' +
  220. '<li class="uk-markdown-button-markdown"><a>{:lblCodeview}</a></li>' +
  221. '<li class="uk-markdown-button-preview"><a>{:lblPreview}</a></li>' +
  222. '<li><a data-markdownarea-cmd="fullscreen"><i class="uk-icon-expand"></i></a></li>' +
  223. '</ul>' +
  224. '</div>' +
  225. '</div>' +
  226. '<div class="uk-markdownarea-content">' +
  227. '<div class="uk-markdownarea-code"></div>' +
  228. '<div class="uk-markdownarea-preview"><div></div></div>' +
  229. '</div>' +
  230. '</div>';
  231. UI["markdownarea"] = Markdownarea;
  232. // init code
  233. $(function() {
  234. marked.setOptions({
  235. gfm: true,
  236. tables: true,
  237. breaks: true,
  238. pedantic: false,
  239. sanitize: false,
  240. smartLists: true,
  241. smartypants: false,
  242. langPrefix: 'lang-'
  243. });
  244. $("textarea[data-uk-markdownarea]").each(function() {
  245. var area = $(this), obj;
  246. if (!area.data("markdownarea")) {
  247. obj = new Markdownarea(area, UI.Utils.options(area.attr("data-uk-markdownarea")));
  248. }
  249. });
  250. });
  251. })(window, jQuery, jQuery.UIkit);