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.

226 lines
7.9 KiB

  1. (function ($) {
  2. // #region Helpers
  3. function ConvertMarkupToValidXhtml(markup) {
  4. var docImplementation = document.implementation;
  5. var htmlDocument = docImplementation.createHTMLDocument("temp");
  6. var xHtmlDocument = docImplementation.createDocument('http://www.w3.org/1999/xhtml', 'html', null);
  7. var xhtmlBody = xHtmlDocument.createElementNS('http://www.w3.org/1999/xhtml', 'body');
  8. htmlDocument.body.innerHTML = "<div>" + markup + "</div>";
  9. xHtmlDocument.documentElement.appendChild(xhtmlBody);
  10. xHtmlDocument.importNode(htmlDocument.body, true);
  11. xhtmlBody.appendChild(htmlDocument.body.firstChild);
  12. /<body.*?><div>(.*?)<\/div><\/body>/im.exec(xHtmlDocument.documentElement.innerHTML);
  13. return RegExp.$1;
  14. }
  15. // #endregion
  16. var postId, isNew,
  17. txtTitle, txtContent, txtMessage, txtImage, chkPublish,
  18. btnNew, btnEdit, btnDelete, btnSave, btnCancel,
  19. editPost = function () {
  20. txtTitle.attr('contentEditable', true);
  21. txtContent.wysiwyg({ hotKeys: {}, activeToolbarClass: "active" });
  22. txtContent.css({ minHeight: "400px" });
  23. txtContent.focus();
  24. btnNew.attr("disabled", true);
  25. btnEdit.attr("disabled", true);
  26. btnSave.removeAttr("disabled");
  27. btnCancel.removeAttr("disabled");
  28. chkPublish.removeAttr("disabled");
  29. showCategoriesForEditing();
  30. toggleSourceView();
  31. $("#tools").fadeIn().css("display", "inline-block");
  32. },
  33. cancelEdit = function () {
  34. if (isNew) {
  35. if (confirm("Do you want to leave this page?")) {
  36. history.back();
  37. }
  38. } else {
  39. txtTitle.removeAttr('contentEditable');
  40. txtContent.removeAttr('contentEditable');
  41. btnCancel.focus();
  42. btnNew.removeAttr("disabled");
  43. btnEdit.removeAttr("disabled");
  44. btnSave.attr("disabled", true);
  45. btnCancel.attr("disabled", true);
  46. chkPublish.attr("disabled", true);
  47. showCategoriesForDisplay();
  48. $("#tools").fadeOut();
  49. }
  50. },
  51. toggleSourceView = function () {
  52. $(".source").bind("click", function () {
  53. var self = $(this);
  54. if (self.attr("data-cmd") === "source") {
  55. self.attr("data-cmd", "design");
  56. self.addClass("active");
  57. txtContent.text(txtContent.html());
  58. } else {
  59. self.attr("data-cmd", "source");
  60. self.removeClass("active");
  61. txtContent.html(txtContent.text());
  62. }
  63. });
  64. },
  65. savePost = function (e) {
  66. if ($(".source").attr("data-cmd") === "design") {
  67. $(".source").click();
  68. }
  69. txtContent.cleanHtml();
  70. var parsedDOM;
  71. /* IE9 doesn't support text/html MimeType https://github.com/madskristensen/MiniBlog/issues/35
  72. parsedDOM = new DOMParser().parseFromString(txtContent.html(), 'text/html');
  73. parsedDOM = new XMLSerializer().serializeToString(parsedDOM);
  74. /<body>(.*)<\/body>/im.exec(parsedDOM);
  75. parsedDOM = RegExp.$1;
  76. */
  77. /* When its time to drop IE9 support toggle commented region with
  78. the following statement and ConvertMarkupToXhtml function */
  79. parsedDOM = ConvertMarkupToValidXhtml(txtContent.html());
  80. $.post("/post.ashx?mode=save", {
  81. id: postId,
  82. isPublished: chkPublish[0].checked,
  83. title: txtTitle.text().trim(),
  84. content: parsedDOM,
  85. categories: getPostCategories(),
  86. token: document.querySelector("[data-token]").getAttribute("data-token")
  87. })
  88. .success(function (data) {
  89. if (isNew) {
  90. location.href = data;
  91. return;
  92. }
  93. showMessage(true, "The post was saved successfully");
  94. cancelEdit(e);
  95. })
  96. .fail(function (data) {
  97. if (data.status === 409) {
  98. showMessage(false, "The title is already in use");
  99. } else {
  100. showMessage(false, "Something bad happened. Server reported " + data.status + " " + data.statusText);
  101. }
  102. });
  103. },
  104. deletePost = function () {
  105. if (confirm("Are you sure you want to delete this post?")) {
  106. $.post("/post.ashx?mode=delete", { id: postId, token: document.querySelector("[data-token]").getAttribute("data-token") })
  107. .success(function () { location.href = "/"; })
  108. .fail(function () { showMessage(false, "Something went wrong. Please try again"); });
  109. }
  110. },
  111. showMessage = function (success, message) {
  112. var className = success ? "alert-success" : "alert-error";
  113. txtMessage.addClass(className);
  114. txtMessage.text(message);
  115. txtMessage.parent().fadeIn();
  116. setTimeout(function () {
  117. txtMessage.parent().fadeOut("slow", function () {
  118. txtMessage.removeClass(className);
  119. });
  120. }, 4000);
  121. },
  122. getPostCategories = function () {
  123. var categories = '';
  124. if ($("#txtCategories").length > 0) {
  125. categories = $("#txtCategories").val();
  126. } else {
  127. $("ul.categories li a").each(function (index, item) {
  128. if (categories.length > 0) {
  129. categories += ",";
  130. }
  131. categories += $(item).html();
  132. });
  133. }
  134. return categories;
  135. },
  136. showCategoriesForEditing = function () {
  137. var firstItemPassed = false;
  138. var categoriesString = getPostCategories();
  139. $("ul.categories li").each(function (index, item) {
  140. if (!firstItemPassed) {
  141. firstItemPassed = true;
  142. } else {
  143. $(item).remove();
  144. }
  145. });
  146. $("ul.categories").append("<li><input id='txtCategories' class='form-control' /></li>");
  147. $("#txtCategories").val(categoriesString);
  148. },
  149. showCategoriesForDisplay = function () {
  150. if ($("#txtCategories").length > 0) {
  151. var categoriesArray = $("#txtCategories").val().split(',');
  152. $("#txtCategories").parent().remove();
  153. $.each(categoriesArray, function (index, category) {
  154. $("ul.categories").append(' <li itemprop="articleSection" title="' + category + '"> <a href="/category/' + encodeURIComponent(category.toLowerCase()) + '">' + category + '</a> </li> ');
  155. });
  156. }
  157. };
  158. isNew = location.pathname.replace(/\//g, "") === "postnew";
  159. postId = $("[itemprop~='blogPost']").attr("data-id");
  160. txtTitle = $("[itemprop~='blogPost'] [itemprop~='name']");
  161. txtContent = $("[itemprop~='articleBody']");
  162. txtMessage = $("#admin .alert");
  163. txtImage = $("#admin #txtImage");
  164. btnNew = $("#btnNew");
  165. btnEdit = $("#btnEdit").bind("click", editPost);
  166. btnDelete = $("#btnDelete").bind("click", deletePost);
  167. btnSave = $("#btnSave").bind("click", savePost);
  168. btnCancel = $("#btnCancel").bind("click", cancelEdit);
  169. chkPublish = $("#ispublished").find("input[type=checkbox]");
  170. $(document).keyup(function (e) {
  171. if (!document.activeElement.isContentEditable) {
  172. if (e.keyCode === 46) { // Delete key
  173. deletePost();
  174. } else if (e.keyCode === 27) { // ESC key
  175. cancelEdit();
  176. }
  177. }
  178. });
  179. $('.uploadimage').click(function (e) {
  180. e.preventDefault();
  181. $('#txtImage').click();
  182. });
  183. if (isNew) {
  184. editPost();
  185. $("#ispublished").fadeIn();
  186. chkPublish[0].checked = true;
  187. } else if (txtTitle !== null && txtTitle.length === 1 && location.pathname.length > 1) {
  188. btnEdit.removeAttr("disabled");
  189. btnDelete.removeAttr("disabled");
  190. $("#ispublished").css({ "display": "inline" });
  191. }
  192. })(jQuery);