tinymce-editor.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. <?php
  2. namespace Grav\Plugin;
  3. use Grav\Common\Page\Page;
  4. use Grav\Common\Page\Markdown\Excerpts;
  5. use Grav\Common\Plugin;
  6. class TinyMCEEditorPlugin extends Plugin {
  7. private $terminated = array("area", "base", "basefont", "bgsound", "br", "col", "command", "embed", "frame", "hr", "image", "img", "input", "isindex", "keygen", "link", "menuitem", "meta", "nextid", "param", "source", "track", "wbr");
  8. private function fixNodes(\DOMNode $node) {
  9. if($node->hasChildNodes()) {
  10. foreach($node->childNodes as $child) {
  11. $this->fixNodes($child);
  12. }
  13. } else if(!in_array(strtolower($node->nodeName), $this->terminated)) {
  14. $node->appendChild(new \DOMText(""));
  15. }
  16. }
  17. public static function getSubscribedEvents() {
  18. return ["onAdminSave" => ["onAdminSave", 0], "onPluginsInitialized" => ["onPluginsInitialized", 0], "onTwigSiteVariables" => ["onTwigSiteVariables", 0], "onPageContentProcessed" => ["onPageContentProcessed", 0]];
  19. }
  20. public function onAdminSave($event) {
  21. $page = $event["object"];
  22. if($page instanceof Page && $page->folder() != $page->getOriginal()->folder() && $page->rawMarkdown() != "") {
  23. $newdir = explode(".", $page->folder());
  24. $newdir = $this->grav["uri"]->rootUrl() . $page->parent()->route() . "/" . end($newdir) . "/";
  25. $dom = new \DOMDocument("1.0", "UTF-8");
  26. @$dom->loadHTML(mb_convert_encoding($page->rawMarkdown(), "HTML-ENTITIES", "UTF-8"), LIBXML_PARSEHUGE);
  27. foreach($page->getOriginal()->media()->all() as $key => $value) {
  28. foreach($dom->getElementsByTagName("img") as $tag) {
  29. $query = parse_url($tag->getAttribute("src"), PHP_URL_QUERY);
  30. if($query != NULL) {
  31. $query = "?" . $query;
  32. }
  33. if($tag->getAttribute("src") == $this->grav["uri"]->rootUrl() . $page->getOriginal()->route() . "/" . urlencode($key) . $query) {
  34. $tag->setAttribute("src", $newdir . $key . $query);
  35. }
  36. }
  37. foreach($dom->getElementsByTagName("audio") as $tag) {
  38. $query = parse_url($tag->getAttribute("src"), PHP_URL_QUERY);
  39. if($query != NULL) {
  40. $query = "?" . $query;
  41. }
  42. if($tag->getAttribute("src") == $this->grav["uri"]->rootUrl() . $page->getOriginal()->route() . "/" . urlencode($key) . $query) {
  43. $tag->setAttribute("src", $newdir . $key . $query);
  44. }
  45. }
  46. foreach($dom->getElementsByTagName("source") as $tag) {
  47. $query = parse_url($tag->getAttribute("src"), PHP_URL_QUERY);
  48. if($query != NULL) {
  49. $query = "?" . $query;
  50. }
  51. if($tag->getAttribute("src") == $this->grav["uri"]->rootUrl() . $page->getOriginal()->route() . "/" . urlencode($key) . $query) {
  52. $tag->setAttribute("src", $newdir . $key . $query);
  53. }
  54. }
  55. foreach($dom->getElementsByTagName("a") as $tag) {
  56. $query = parse_url($tag->getAttribute("href"), PHP_URL_QUERY);
  57. if($query != NULL) {
  58. $query = "?" . $query;
  59. }
  60. if($tag->getAttribute("href") == $this->grav["uri"]->rootUrl() . $page->getOriginal()->route() . "/" . urlencode($key) . $query) {
  61. $tag->setAttribute("href", $newdir . $key . $query);
  62. }
  63. }
  64. }
  65. $html = "";
  66. foreach($dom->getElementsByTagname("body")[0]->childNodes as $node) {
  67. $this->fixNodes($node);
  68. $html .= $dom->saveXML($node);
  69. }
  70. $page->rawMarkdown($html);
  71. }
  72. }
  73. public function onPluginsInitialized() {
  74. if($this->isAdmin()) {
  75. $this->enable(["onTwigTemplatePaths" => ["onTwigTemplatePaths", 999]]);
  76. }
  77. }
  78. public function onTwigTemplatePaths() {
  79. if(file_exists(__DIR__ . "/../../data/tinymce-editor/templates")) {
  80. $this->grav["twig"]->twig_paths[] = __DIR__ . "/../../data/tinymce-editor/templates";
  81. } else {
  82. $this->grav["twig"]->twig_paths[] = __DIR__ . "/templates";
  83. }
  84. }
  85. public function onTwigSiteVariables() {
  86. if($this->isAdmin()) {
  87. $page = $this->grav["admin"]->page();
  88. $version = "tinymce";
  89. if($this->config["plugins"]["tinymce-editor"]["apikey"] == "") {
  90. if(file_exists(__DIR__ . "/../../data/tinymce-editor/js/" . $version)) {
  91. $this->grav["assets"]->add("user://data/tinymce-editor/js/" . $version . "/tinymce.min.js");
  92. } else {
  93. $this->grav["assets"]->add("plugin://tinymce-editor/js/" . $version . "/tinymce.min.js");
  94. }
  95. } else {
  96. $this->grav["assets"]->add("https://cloud.tinymce.com/4/tinymce.min.js?apiKey=" . urlencode($this->config["plugins"]["tinymce-editor"]["apikey"]));
  97. }
  98. if(file_exists(__DIR__ . "/../../data/tinymce-editor/css")) {
  99. $this->grav["assets"]->add("user://data/tinymce-editor/css/editor.css");
  100. } else {
  101. $this->grav["assets"]->add("plugin://tinymce-editor/css/editor.css");
  102. }
  103. if($this->config["plugins"]["tinymce-editor"]["restrictions"]["blacklist"]) {
  104. foreach($this->grav["pages"]->root()->collection($this->config["plugins"]["tinymce-editor"]["blacklist"], false) as $item) {
  105. if($item == $page) {
  106. return;
  107. }
  108. }
  109. }
  110. $whitelisted = true;
  111. if($this->config["plugins"]["tinymce-editor"]["restrictions"]["whitelist"]) {
  112. $whitelisted = false;
  113. foreach($this->grav["pages"]->root()->collection($this->config["plugins"]["tinymce-editor"]["whitelist"], false) as $item) {
  114. if($item == $page) {
  115. $whitelisted = true;
  116. break;
  117. }
  118. }
  119. }
  120. if($whitelisted) {
  121. if(file_exists(__DIR__ . "/../../data/tinymce-editor/blueprints")) {
  122. $this->grav["locator"]->addPath("blueprints", "", __DIR__ . "/../../data/tinymce-editor/blueprints");
  123. } else {
  124. $this->grav["locator"]->addPath("blueprints", "", __DIR__ . "/blueprints");
  125. }
  126. }
  127. }
  128. }
  129. public function onPageContentProcessed($event) {
  130. $page = $event["page"];
  131. if(!$this->isAdmin() && $page->getRawContent() != "") {
  132. $excerpts = new Excerpts($page);
  133. $dom = new \DOMDocument("1.0", "UTF-8");
  134. @$dom->loadHTML(mb_convert_encoding($page->getRawContent(), "HTML-ENTITIES", "UTF-8"), LIBXML_PARSEHUGE);
  135. foreach($page->media()->all() as $key => $value) {
  136. foreach($dom->getElementsByTagName("img") as $tag) {
  137. $query = parse_url($tag->getAttribute("src"), PHP_URL_QUERY);
  138. if($query != NULL) {
  139. $query = "?" . $query;
  140. }
  141. if($tag->getAttribute("src") == urlencode($key) . $query) {
  142. $excerpt = ["element" => ["attributes" => ["href" => $tag->getAttribute("src")]]];
  143. $excerpt["element"]["attributes"]["src"] = $excerpts->processLinkExcerpt($excerpt)["element"]["attributes"]["href"];
  144. $tag->setAttribute("src", $excerpts->processImageExcerpt($excerpt)["element"]["attributes"]["src"]);
  145. }
  146. }
  147. foreach($dom->getElementsByTagName("audio") as $tag) {
  148. $query = parse_url($tag->getAttribute("src"), PHP_URL_QUERY);
  149. if($query != NULL) {
  150. $query = "?" . $query;
  151. }
  152. if($tag->getAttribute("src") == urlencode($key) . $query) {
  153. $excerpt = ["element" => ["attributes" => ["href" => $tag->getAttribute("src")]]];
  154. $tag->setAttribute("src", $excerpts->processLinkExcerpt($excerpt)["element"]["attributes"]["href"]);
  155. }
  156. }
  157. foreach($dom->getElementsByTagName("source") as $tag) {
  158. $query = parse_url($tag->getAttribute("src"), PHP_URL_QUERY);
  159. if($query != NULL) {
  160. $query = "?" . $query;
  161. }
  162. if($tag->getAttribute("src") == urlencode($key) . $query) {
  163. $excerpt = ["element" => ["attributes" => ["href" => $tag->getAttribute("src")]]];
  164. $tag->setAttribute("src", $excerpts->processLinkExcerpt($excerpt)["element"]["attributes"]["href"]);
  165. }
  166. }
  167. foreach($dom->getElementsByTagName("a") as $tag) {
  168. $query = parse_url($tag->getAttribute("href"), PHP_URL_QUERY);
  169. if($query != NULL) {
  170. $query = "?" . $query;
  171. }
  172. if($tag->getAttribute("href") == urlencode($key) . $query) {
  173. $excerpt = ["element" => ["attributes" => ["href" => $tag->getAttribute("href")]]];
  174. $tag->setAttribute("href", $excerpts->processLinkExcerpt($excerpt)["element"]["attributes"]["href"]);
  175. }
  176. }
  177. }
  178. $html = "";
  179. foreach($dom->getElementsByTagname("body")[0]->childNodes as $node) {
  180. $this->fixNodes($node);
  181. $html .= $dom->saveXML($node);
  182. }
  183. $page->setRawContent($html);
  184. }
  185. }
  186. }