tinymce-editor.php 7.9 KB

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