修訂 | 92 (tree) |
---|---|
時間 | 2022-09-10 05:18:17 |
作者 | derekwildstar |
Atualização do plugin do MantisBT Monitor
@@ -0,0 +1,215 @@ | ||
1 | +<?php | |
2 | +header("Content-Type: application/javascript; charset=utf-8"); | |
3 | +$scriptName = $_GET["sn"]?:""; | |
4 | +?> | |
5 | +/** | |
6 | +* Desabilita os tags não editáveis, removendo deles o atributo "class" | |
7 | +* responsável por torná-los não editáveis no TinyMCE. Isso é necessário porque o | |
8 | +* mantis não exibe corretamente os elementos que contém atribtutos, então, | |
9 | +* salvar elementos com um atributo class definido é ruim | |
10 | +*/ | |
11 | +function disableNonEditable(aContent) { | |
12 | + if (aContent == "") return aContent; | |
13 | + | |
14 | + let html = (new DOMParser()).parseFromString(aContent,"text/html"); | |
15 | + let nodes = null; | |
16 | + | |
17 | +<?php | |
18 | +// Obtém a instância do plugin atualmente em execução. No caso, só pode ser o | |
19 | +// Plugin do MantisBT Monitor, se não for, alguém está tentando fazer alguma | |
20 | +// merda. A função plugin_get pode receber de parâmetro o nome base do plugin, | |
21 | +// que pode ser obtido com plugin_get_current(). Caso algo aconteça, use esta | |
22 | +// abordagem | |
23 | +$mbtmp = plugin_get(); | |
24 | + | |
25 | +$nonEditableTags = explode(",",$mbtmp->clearTagsList(plugin_config_get("specialnoneditabletags"))); | |
26 | + | |
27 | +foreach($nonEditableTags as $tag) { | |
28 | + echo <<<EOS | |
29 | + nodes = html.getElementsByTagName("$tag"); | |
30 | + for (let node of nodes) { | |
31 | + node.removeAttribute("class"); | |
32 | + } | |
33 | + | |
34 | + | |
35 | +EOS; | |
36 | +} | |
37 | +?> | |
38 | + return html.body.innerHTML; | |
39 | +} | |
40 | + | |
41 | +/** | |
42 | +* Habilita os tags não editáveis, adicionando a eles o atributo "class" com o | |
43 | +* valor "mceNonEditable" | |
44 | +*/ | |
45 | +function enableNonEditable(aContent) { | |
46 | + if (aContent == "") return aContent; | |
47 | + | |
48 | + let html = (new DOMParser()).parseFromString(aContent,"text/html"); | |
49 | + let nodes = null; | |
50 | + | |
51 | +<?php | |
52 | +$nonEditableTags = explode(",",$mbtmp->clearTagsList(plugin_config_get("specialnoneditabletags"))); | |
53 | + | |
54 | +foreach($nonEditableTags as $tag) { | |
55 | + echo <<<EOS | |
56 | + nodes = html.getElementsByTagName("$tag"); | |
57 | + for (let node of nodes) { | |
58 | + node.classList.add("mceNonEditable"); | |
59 | + } | |
60 | + | |
61 | + | |
62 | +EOS; | |
63 | +} | |
64 | +?> | |
65 | + return html.body.innerHTML; | |
66 | +} | |
67 | + | |
68 | +function isPastingAttachmentReference(aPastedText) { | |
69 | + const regex = /<atta class="mceNonEditable"><atna>(.*)<\/atna><atnn>(.*)<\/atnn>/i; | |
70 | + return regex.exec(aPastedText) != null; | |
71 | +} | |
72 | +<?php | |
73 | +// ATENÇÃO: Não use o plugin paste, pois ele altera a forma como o texto é | |
74 | +// colado no editor, inviabilizando o uso do evento onPaste para | |
75 | +// colocar código-fonte externo! | |
76 | +if ($scriptName == "mbtmTinyMCEEditor") { | |
77 | + $toolBar1 = plugin_config_get("tinymcealternatetoolbar1"); | |
78 | + $toolBar2 = plugin_config_get("tinymcealternatetoolbar2"); | |
79 | +} else { | |
80 | + $toolBar1 = plugin_config_get("tinymcetoolbar1"); | |
81 | + $toolBar2 = plugin_config_get("tinymcetoolbar2"); | |
82 | +} | |
83 | + | |
84 | +$customElements = $mbtmp->getTinyMCECustomElements(); | |
85 | +$extendedValidElements = $mbtmp->getTinyMCEExtendedValidElements(); | |
86 | +?> | |
87 | + | |
88 | +/******************************************************************************* | |
89 | +Se você chegou aqui porque está tentando resolver algum bug relacionado ao | |
90 | +funcionamento do TinyMCE, saiba que este componente não é bugado. A forma como | |
91 | +ele está configurado o faz funcionar muito fora do padrão e é isso que o faz ter | |
92 | +certos comportamentos bizarros. Ele precisou ser configurado desta forma para se | |
93 | +adequar ao MantisBT, este sim, cheio de bizarrices | |
94 | +*******************************************************************************/ | |
95 | + | |
96 | +tinyMCE.init({selector: "textarea" | |
97 | + ,height: 300 | |
98 | + ,entity_encoding: "numeric" | |
99 | + ,plugins: "legacyoutput visualblocks lists insertdatetime charmap hr preview fullscreen code searchreplace noneditable tjpe" | |
100 | + ,menubar: false | |
101 | + ,toolbar1: "<?=$toolBar1;?>" | |
102 | + ,toolbar2: "<?=$toolBar2;?>" | |
103 | + ,browser_spellcheck: true | |
104 | + ,contextmenu: false | |
105 | + ,insertdatetime_formats: ["%H:%M:%S", "%d/%m/%Y", "%d/%m/%Y %H:%M:%S", "%d/%m/%Y às %H:%M:%S", "%Y-%m-%d", "%Y-%m-%dT%H:%M:%S"] | |
106 | + ,content_css: ["/mantis/css/default.css" | |
107 | + ,"/mantis/css/common_config.php" | |
108 | + ,"/mantis/css/status_config.php" | |
109 | + ,"/mantis/css/dropzone-4.3.0.min.css" | |
110 | + ,"/mantis/css/bootstrap-3.3.6.min.css" | |
111 | + ,"/mantis/css/font-awesome-4.6.3.min.css" | |
112 | + ,"/mantis/css/open-sans.css" | |
113 | + ,"/mantis/css/bootstrap-datetimepicker-4.17.43.min.css" | |
114 | + ,"/mantis/css/ace.min.css" | |
115 | + ,"/mantis/css/ace-mantis.css" | |
116 | + ,"/mantis/css/ace-skins.min.css" | |
117 | + ,"<?=plugin_file("css/MantisBTMonitor.css");?>"] | |
118 | + ,invalid_elements: "div" | |
119 | + // Elementos que não existem no HTML5, mas precisam ser aceitos | |
120 | + // pelo TinyMCE. Os nomes de elementos são separados por vírgulas. | |
121 | + // Qualquer elemento que não esteja defindo no HTML5 e não esteja | |
122 | + // nesta lista será removido do TinyMCE automaticamente e sem | |
123 | + // aviso. Por padrão elementos são tratados pelo TinyMCE como | |
124 | + // elementos de bloco. Para definir um elemento "inline", coloque | |
125 | + // um til (~) antes do nome do elemento. Ao aparecer nesta lista, | |
126 | + // um elemento já pode ser manipulado no TinyMCE, não sendo | |
127 | + // necessário adicioná-lo novamente em extended_valid_elements, | |
128 | + // contudo, como estas listas são geradas automaicamente pelo | |
129 | + // plugin do MantisBT Monitor, você deve estar vendo elementos | |
130 | + // listdos tanto aqui como em extended_valid_elements sem qualquer | |
131 | + // especificação de atributo (apenas o nome do atributo). Isso não | |
132 | + // causará problemas | |
133 | + ,custom_elements: "<?=$customElements;?>" | |
134 | + // O atributo valid_elements por padrão contém um conjunto de | |
135 | + // elementos (e seus atributos) que são aceitos pelo TinyMCE. Este | |
136 | + // atributo não deve ser alterado normalmente. Ao invés disso, | |
137 | + // usa-se o atributo extended_valid_elements como forma de | |
138 | + // sobrescrever configurações de atributos para elementos | |
139 | + // específicos ou definir (adicionar) configurações de atributos | |
140 | + // para estes elementos. Aqui, estamos apenas definindo as | |
141 | + // configurações dos elementos que foram definidos em | |
142 | + // custom_elements. Tags customizados listados aqui também não | |
143 | + // serão preenchidos com   | |
144 | + ,extended_valid_elements: "<?=$extendedValidElements;?>" | |
145 | + ,valid_children: "" | |
146 | + // A configuração abaixo foi removida porque o Mantis não gosta de | |
147 | + // tags auto-fechantes (<tag/>). Outra forma de manter os elementos | |
148 | + // que são auto-fechantes é usando o exemplo deste fiddle | |
149 | + // https://fiddle.tiny.cloud/ehhaab | |
150 | + // ,protect: [/\<(teap|tere|hoap|hore) *\/\>/g] // isso é usado para manter os tags sem qualquer alteração pelo TinyMCE | |
151 | + ,block_formats: "Parágrafo simples=p;Texto preformatado=pre;Código \"inline\"=code;Cabeçalho de primeiro nível=h1;Cabeçalho de segundo nível=h2;Cabeçalho de terceiro nível=h3" | |
152 | + ,setup: function(aEditor) { | |
153 | + // Pós processamento executado apenas quando o texto está sendo | |
154 | + // confirmado, isto é, passado do editor para o <textarea> | |
155 | + aEditor.on("GetContent",function(aEventData) { | |
156 | + if (aEventData.format == "html" && aEventData.hasOwnProperty("save") && aEventData.save) { | |
157 | + if (aEventData.content.trim() != "") { | |
158 | + aEventData.content = "<mbtm></mbtm>" + aEventData.content; | |
159 | + } | |
160 | + | |
161 | + aEventData.content = disableNonEditable(aEventData.content); | |
162 | + } | |
163 | + }); | |
164 | + // Pré processamento executado quando o texto está sendo | |
165 | + // carregado no editor, isto é, passado do <textarea> para o | |
166 | + // editor | |
167 | + aEditor.on("BeforeSetContent",function(aEventData){ | |
168 | + aEventData.content = aEventData.content.replaceAll("<mbtm></mbtm>",""); | |
169 | + aEventData.content = enableNonEditable(aEventData.content); | |
170 | + }); | |
171 | + // Verifica se estamos tentando colar no editor algum tag | |
172 | + // especial. Neste caso, não há a colagem padrão, mas sim um | |
173 | + // inserção ou substituição do conteúdo do editor. Este código | |
174 | + // só funciona quando o plugin Paste do TinyMCE não está | |
175 | + // ativado. Este código só atua em colagens de código-fonte no | |
176 | + // editor do TinyMCE. Quando, por exemplo, um tag especial é | |
177 | + // copiado e colado de e para o próprio editor, a expressão | |
178 | + // regular que detecta o conteúdo sendo colado não vai enxergar | |
179 | + // o código-fonte do tag especial, sendo realizada a colagem | |
180 | + // original, que já lida com o tag especial | |
181 | + aEditor.on("paste",function(aEventData) { | |
182 | + let pastedText = (aEventData.clipboardData || window.clipboardData).getData("text/plain"); | |
183 | + | |
184 | + if (isPastingAttachmentReference(pastedText)) { | |
185 | + aEventData.preventDefault(); | |
186 | + aEditor.execCommand("mceInsertContent",false,pastedText); | |
187 | + } | |
188 | + }); | |
189 | + } | |
190 | + }); | |
191 | + | |
192 | +/******************************************************************************* | |
193 | +O Dropzone interfere na forma como o TinyMCE serializa o texto do editor. | |
194 | +Normalmente o TinyMCE serializa o texto do editor no momento em que o usuário | |
195 | +executa o submit do <form>, porém em forms que contém o Dropzone, quando se | |
196 | +adiciona algum arquivo a ser anexado, o envio efetivo dos dados ocorre ANTES que | |
197 | +o TinyMCE serialize seu texto no <textarea>, fazendo com que o texto não seja | |
198 | +enviado ao servidor. As linhas abaixo forçam a serialização do conteúdo do | |
199 | +TinyMCE. Abaixo, primeiramente obtém-se a instância do objeto dropzone | |
200 | +diretamente a partir do form que foi usado durante sua instanciação e em seguida | |
201 | +se aplica a solução, a qual foi obtida em: | |
202 | +https://stackoverflow.com/questions/41481758/include-textarea-tynimce-with-dropzone | |
203 | +*******************************************************************************/ | |
204 | + | |
205 | +window.onload = function() { | |
206 | + let dropZone = $("div.dropzone").length > 0?$("div.dropzone").closest("form").length > 0?$("div.dropzone").closest("form")[0].dropzone != undefined?$("div.dropzone").closest("form")[0].dropzone:null:null:null; | |
207 | + | |
208 | + if (dropZone != null) { | |
209 | + dropZone.on("sending", function(file, xhr, formData) { | |
210 | + for (let i = 0;i < tinyMCE.editors.length;i++) { | |
211 | + formData.append(tinyMCE.editors[i].targetElm.name, tinyMCE.editors[i].save()); | |
212 | + } | |
213 | + }); | |
214 | + } | |
215 | +} | |
\ No newline at end of file |
@@ -11,8 +11,8 @@ | ||
11 | 11 | </div> |
12 | 12 | <div class="space-2"></div> |
13 | 13 | <ul class="nav nav-tabs padding-18"> |
14 | + <li><a href="<?=plugin_page("mbtmConfig");?>"><i class="blue ace-icon fa fa-gears"></i> <?=lang_get("plugin_mbtm_configtabtitle"); ?></a></li> | |
14 | 15 | <li class="active"><a><i class="blue ace-icon fa fa-info-circle"></i> <?=lang_get("plugin_mbtm_abouttabtitle"); ?></a></li> |
15 | - <li><a href="<?=plugin_page("mbtmConfig");?>"><i class="blue ace-icon fa fa-gears"></i> <?=lang_get("plugin_mbtm_configtabtitle"); ?></a></li> | |
16 | 16 | </ul> |
17 | 17 | <div class="widget-body"> |
18 | 18 | <div class="widget-main no-padding"> |
@@ -16,6 +16,7 @@ | ||
16 | 16 | <?php |
17 | 17 | event_signal( 'EVENT_LAYOUT_BODY_BEGIN' ); |
18 | 18 | echo($bodyContents); |
19 | +layout_body_javascript(); | |
19 | 20 | html_body_end(); |
20 | 21 | ?> |
21 | 22 | </html> |
\ No newline at end of file |
@@ -6,6 +6,13 @@ | ||
6 | 6 | $tinymcemode = plugin_config_get("tinymcemode"); |
7 | 7 | $tinymceenabledfor = plugin_config_get("tinymceenabledfor"); |
8 | 8 | $tinymcedisabledfor = plugin_config_get("tinymcedisabledfor"); |
9 | +$tinymcetoolbar1 = plugin_config_get("tinymcetoolbar1"); | |
10 | +$tinymcetoolbar2 = plugin_config_get("tinymcetoolbar2"); | |
11 | +$tinymcealternatetoolbar1 = plugin_config_get("tinymcealternatetoolbar1"); | |
12 | +$tinymcealternatetoolbar2 = plugin_config_get("tinymcealternatetoolbar2"); | |
13 | +$additionaltags = plugin_config_get("additionaltags"); | |
14 | +$specialtags = plugin_config_get("specialtags"); | |
15 | +$specialnoneditabletags = plugin_config_get("specialnoneditabletags"); | |
9 | 16 | ?> |
10 | 17 | <div class="col-md-12 col-xs-12"> |
11 | 18 | <div class="space-10"></div> |
@@ -15,8 +22,8 @@ | ||
15 | 22 | </div> |
16 | 23 | <div class="space-2"></div> |
17 | 24 | <ul class="nav nav-tabs padding-18"> |
25 | + <li class="active"><a><i class="blue ace-icon fa fa-gears"></i> <?=lang_get("plugin_mbtm_configtabtitle"); ?></a></li> | |
18 | 26 | <li><a href="<?=plugin_page("mbtmAbout");?>"><i class="blue ace-icon fa fa-info-circle"></i> <?=lang_get("plugin_mbtm_abouttabtitle"); ?></a></li> |
19 | - <li class="active"><a><i class="blue ace-icon fa fa-gears"></i> <?=lang_get("plugin_mbtm_configtabtitle"); ?></a></li> | |
20 | 27 | </ul> |
21 | 28 | <div class="form-container"> |
22 | 29 | <form id="formatting-config-form" action="<?=plugin_page("mbtmConfigSave");?>" method="post"> |
@@ -26,6 +33,11 @@ | ||
26 | 33 | <div class="table-responsive"> |
27 | 34 | <table class="table table-bordered table-condensed table-striped"> |
28 | 35 | <tr> |
36 | + <td colspan="2" class="widget-header bold center"> | |
37 | + Configurações relacionadas ao TinyMCE | |
38 | + </td> | |
39 | + </tr> | |
40 | + <tr> | |
29 | 41 | <th class="category width-30"> |
30 | 42 | Modo de uso do TinyMCE<br /> |
31 | 43 | <span class="small">Informe como o TinyMCE será integrado ao MantisBT</span> |
@@ -67,6 +79,74 @@ | ||
67 | 79 | <input name="tinymcedisabledfor" id="tinymcedisabledfor" class="form-control" value="<?=string_attribute($tinymcedisabledfor); ?>" /> |
68 | 80 | </td> |
69 | 81 | </tr> |
82 | + <tr> | |
83 | + <th class="category width-30"> | |
84 | + Primeira barra de ferramentas do TinyMCE<br /> | |
85 | + <span class="small">Estrutura da primeira barra de ferramentas do TinyMCE</span> | |
86 | + </th> | |
87 | + <td> | |
88 | + <input name="tinymcetoolbar1" id="tinymcetoolbar1" class="form-control" value="<?=string_attribute($tinymcetoolbar1); ?>" /> | |
89 | + </td> | |
90 | + </tr> | |
91 | + <tr> | |
92 | + <th class="category width-30"> | |
93 | + Segunda barra de ferramentas do TinyMCE<br /> | |
94 | + <span class="small">Estrutura da segunda barra de ferramentas do TinyMCE</span> | |
95 | + </th> | |
96 | + <td> | |
97 | + <input name="tinymcetoolbar2" id="tinymcetoolbar2" class="form-control" value="<?=string_attribute($tinymcetoolbar2); ?>" /> | |
98 | + </td> | |
99 | + </tr> | |
100 | + <tr> | |
101 | + <th class="category width-30"> | |
102 | + Primeira barra de ferramentas alternativa do TinyMCE<br /> | |
103 | + <span class="small">Estrutura da primeira barra de ferramentas alternativa do TinyMCE</span> | |
104 | + </th> | |
105 | + <td> | |
106 | + <input name="tinymcealternatetoolbar1" id="tinymcealternatetoolbar1" class="form-control" value="<?=string_attribute($tinymcealternatetoolbar1); ?>" /> | |
107 | + </td> | |
108 | + </tr> | |
109 | + <tr> | |
110 | + <th class="category width-30"> | |
111 | + Segunda barra de ferramentas alternativa do TinyMCE<br /> | |
112 | + <span class="small">Estrutura da segunda barra de ferramentas alternativa do TinyMCE</span> | |
113 | + </th> | |
114 | + <td> | |
115 | + <input name="tinymcealternatetoolbar2" id="tinymcealternatetoolbar2" class="form-control" value="<?=string_attribute($tinymcealternatetoolbar2); ?>" /> | |
116 | + </td> | |
117 | + </tr> | |
118 | + <tr> | |
119 | + <td colspan="2" class="widget-header bold center"> | |
120 | + Tags que precisam ser aceitos pelo MantisBT | |
121 | + </td> | |
122 | + </tr> | |
123 | + <tr> | |
124 | + <th class="category width-30"> | |
125 | + Tags adicionais<br /> | |
126 | + <span class="small">Tags adicionais aceitos pelo MantisBT</span> | |
127 | + </th> | |
128 | + <td> | |
129 | + <input name="additionaltags" id="additionaltags" class="form-control" value="<?=string_attribute($additionaltags); ?>" /> | |
130 | + </td> | |
131 | + </tr> | |
132 | + <tr> | |
133 | + <th class="category width-30"> | |
134 | + Tags especiais<br /> | |
135 | + <span class="small">Tags especiais aceitos pelo MantisBT e requeridos pelo MantisBT Monitor</span> | |
136 | + </th> | |
137 | + <td> | |
138 | + <input name="specialtags" id="specialtags" class="form-control" value="<?=string_attribute($specialtags); ?>" /> | |
139 | + </td> | |
140 | + </tr> | |
141 | + <tr> | |
142 | + <th class="category width-30"> | |
143 | + Tags especiais não editáveis<br /> | |
144 | + <span class="small">Tags especiais que não podem ser editados via TinyMCE</span> | |
145 | + </th> | |
146 | + <td> | |
147 | + <input name="specialnoneditabletags" id="specialnoneditabletags" class="form-control" value="<?=string_attribute($specialnoneditabletags); ?>" /> | |
148 | + </td> | |
149 | + </tr> | |
70 | 150 | </table> |
71 | 151 | </div> |
72 | 152 | </div> |
@@ -18,7 +18,7 @@ | ||
18 | 18 | foreach ($defaultConfigs as $key => $defaultValue) { |
19 | 19 | $value = gpc_get_string($key); |
20 | 20 | // Remove espaços em campos específicos |
21 | - if ($key == "tinymceenabledfor" || $key == "tinymcedisabledfor") { | |
21 | + if ($key == "tinymceenabledfor" || $key == "tinymcedisabledfor" || $key == "additionaltags" || $key == "specialtags" || $key == "specialnoneditabletags") { | |
22 | 22 | $value = str_replace(" ","",$value); |
23 | 23 | } |
24 | 24 |
@@ -31,6 +31,6 @@ | ||
31 | 31 | |
32 | 32 | layout_page_header("Configurações do Plugin do MantisBT Monitor",$mbtmConfigPage); |
33 | 33 | layout_page_begin(); |
34 | -html_operation_successful($mbtmConfigPage,"As configurações do Plugin do MantisBT Monitor foram salvas com sucesso! Aguarde ser redirecionado ou clique o botão abaixo para voltar a tela de configurações do plugin imediatamente"); | |
34 | +html_operation_successful($mbtmConfigPage,"<center>As configurações do Plugin do MantisBT Monitor foram salvas com sucesso! Aguarde ser redirecionado ou clique o botão abaixo para voltar a tela de configurações do plugin imediatamente</center>"); | |
35 | 35 | layout_page_end(); |
36 | 36 | ?> |
@@ -43,6 +43,7 @@ | ||
43 | 43 | } |
44 | 44 | /* ]]> */ |
45 | 45 | </script> |
46 | + | |
46 | 47 | EOS; |
47 | 48 | |
48 | 49 | require(__DIR__ . "/mbtmBasePage.php"); |
@@ -1,5 +1,16 @@ | ||
1 | 1 | <?php |
2 | 2 | class MantisBTMonitorPlugin extends MantisPlugin { |
3 | + const DEFAULT_TINYMCE_MODE = "EP"; | |
4 | + const DEFAULT_TINYMCE_ENABLEDFOR = "cbff"; | |
5 | + const DEFAULT_TINYMCE_DISABLEDFOR = ""; | |
6 | + const DEFAULT_TINYMCE_TOOLBAR1 = "fullscreen preview searchreplace | undo redo | selectall | bold italic underline strikethrough subscript superscript removeformat | blockquote h1 h2 h3 formatselect"; | |
7 | + const DEFAULT_TINYMCE_TOOLBAR2 = "visualblocks insertdatetime charmap hr | bullist numlist | code | tjpeaard"; | |
8 | + const DEFAULT_TINYMCE_ALTERNATIVETOOLBAR1 = "searchreplace | undo redo | selectall | bold italic underline strikethrough subscript superscript removeformat | blockquote h1 h2 h3 formatselect"; | |
9 | + const DEFAULT_TINYMCE_ALTERNATIVETOOLBAR2 = "visualblocks insertdatetime charmap hr | bullist numlist | tjpeaard"; | |
10 | + const DEFAULT_ADDITIONAL_TAGS = "hr,sup,sub,strike,blockquote,code,h1,h2,h3"; | |
11 | + const DEFAULT_SPECIAL_TAGS = "~vers,~stat,~fwte,~fwho,~atna,~atnn,reit[class],num[class]"; | |
12 | + const DEFAULT_SPECIAL_NONEDITABLE_TAGS = "~atta[class],teap[class],tere[class],hoap[class],hore[class],uds1[class],uds2[class],uds3[class],uds4[class],uds5[class],unts[class],une1[class],une2[class],une3[class],une4[class],une5[class],ungc[class]"; | |
13 | + | |
3 | 14 | // Código de registro (obrigatório!) |
4 | 15 | function register() { |
5 | 16 | $this->name = lang_get("plugin_mbtm_name"); |
@@ -6,7 +17,7 @@ | ||
6 | 17 | $this->description = lang_get("plugin_mbtm_description"); |
7 | 18 | $this->version = "1.0.0"; |
8 | 19 | $this->requires = array("MantisCore" => "2.5.0"); |
9 | - $this->page = "mbtmAbout"; | |
20 | + $this->page = "mbtmConfig"; | |
10 | 21 | $this->author = "Carlos Barreto Feitoza Filho"; |
11 | 22 | $this->contact = "carlos.feitoza@tjpe.jus.br"; |
12 | 23 | $this->url = "http://www.tjpe.jus.br"; |
@@ -14,16 +25,23 @@ | ||
14 | 25 | |
15 | 26 | // Configurações que este plugin possui e seus valores padrão |
16 | 27 | function config() { |
17 | - return array("tinymcemode" => "EP" | |
18 | - ,"tinymceenabledfor" => "cbff" | |
19 | - ,"tinymcedisabledfor" => ""); | |
28 | + return array("tinymcemode" => $this::DEFAULT_TINYMCE_MODE | |
29 | + ,"tinymceenabledfor" => $this::DEFAULT_TINYMCE_ENABLEDFOR | |
30 | + ,"tinymcedisabledfor" => $this::DEFAULT_TINYMCE_DISABLEDFOR | |
31 | + ,"tinymcetoolbar1" => $this::DEFAULT_TINYMCE_TOOLBAR1 | |
32 | + ,"tinymcetoolbar2" => $this::DEFAULT_TINYMCE_TOOLBAR2 | |
33 | + ,"tinymcealternatetoolbar1" => $this::DEFAULT_TINYMCE_ALTERNATIVETOOLBAR1 | |
34 | + ,"tinymcealternatetoolbar2" => $this::DEFAULT_TINYMCE_ALTERNATIVETOOLBAR2 | |
35 | + ,"additionaltags" => $this::DEFAULT_ADDITIONAL_TAGS | |
36 | + ,"specialtags" => $this::DEFAULT_SPECIAL_TAGS | |
37 | + ,"specialnoneditabletags" => $this::DEFAULT_SPECIAL_NONEDITABLE_TAGS); | |
20 | 38 | } |
21 | 39 | |
22 | 40 | // Esta função é chamada toda vez que o plugin for inicializado. Aqui é um |
23 | 41 | // bom lugar para sobrescrever variáveis globais |
24 | 42 | function init() { |
25 | - config_set_global("html_valid_tags",config_get_global("html_valid_tags") . ", hr, sup, sub, strike, blockquote, code, h1, h2, h3"); | |
26 | - config_set_global("html_valid_tags",config_get_global("html_valid_tags") . ", mbtm, teap, tere, hoap, hore, vers, stat, fwte, fwho, atta, atna, atnn, uds1, uds2, uds3, uds4, uds5, unts, une1, une2, une3, une4, une5, ungc, stt, sth, reit, num"); | |
43 | + config_set_global("html_valid_tags",config_get_global("html_valid_tags") . "," . plugin_config_get("additionaltags")); | |
44 | + config_set_global("html_valid_tags",config_get_global("html_valid_tags") . ",mbtm," . $this->clearTagsList(plugin_config_get("specialtags")) . "," . $this->clearTagsList(plugin_config_get("specialnoneditabletags"))); | |
27 | 45 | } |
28 | 46 | |
29 | 47 | // Eventos que este plugin manipula podem ser definidos aqui |
@@ -86,373 +104,25 @@ | ||
86 | 104 | function onBeforeHeadEnd($aEvent,$aParameters) { |
87 | 105 | echo("\t<!-- MBTMP -->\n"); |
88 | 106 | html_css_link(plugin_file("css/MantisBTMonitor.css")); |
89 | - | |
90 | - $scriptName = basename($_SERVER["SCRIPT_NAME"], ".php"); | |
91 | - | |
92 | - if ($scriptName == "plugin") { | |
93 | - $scriptName = basename($_GET["page"]); | |
94 | - } | |
95 | - | |
107 | + | |
96 | 108 | if ($this->isTinyMCEAllowed()) { |
109 | + $scriptName = basename($_SERVER["SCRIPT_NAME"], ".php"); | |
110 | + | |
111 | + if ($scriptName == "plugin") { | |
112 | + $scriptName = basename($_GET["page"]); | |
113 | + } | |
114 | + | |
97 | 115 | // O TinyMCE e tudo que ele depende, só será adicionada às páginas |
98 | 116 | // específicadas |
99 | 117 | if (in_array($scriptName,["bugnote_edit_page" |
100 | - ,"view","bug_update_page" | |
118 | + ,"view" | |
119 | + ,"bug_update_page" | |
101 | 120 | ,"bug_report_page" |
102 | 121 | ,"mbtmTinyMCEEditor"],true)) { |
122 | + | |
103 | 123 | echo("\t<script src=\"" . plugin_file("js/tinymce/tinymce.min.js") . "\" referrerpolicy=\"origin\"></script>\n"); |
104 | - | |
105 | - // ATENÇÃO: Não use o plugin paste, pois ele altera a forma como o texto | |
106 | - // é colado no editor, inviabilizando o uso do evento onPaste | |
107 | - // para colocar código-fonte externo! | |
108 | - $toolBar1 = "fullscreen preview searchreplace | undo redo | selectall | bold italic underline strikethrough subscript superscript removeformat | blockquote h1 h2 h3 formatselect"; | |
109 | - $toolBar2 = "visualblocks insertdatetime charmap hr | bullist numlist | code | tjpeaard"; | |
110 | - | |
111 | - if ($scriptName == "MantisBTMonitorTinyMCEEditor") { | |
112 | - $toolBar1 = "searchreplace | undo redo | selectall | bold italic underline strikethrough subscript superscript removeformat | blockquote h1 h2 h3 formatselect"; | |
113 | - $toolBar2 = "visualblocks insertdatetime charmap hr | bullist numlist | tjpeaard"; | |
114 | - } | |
115 | - ?> | |
116 | - <script> | |
117 | - /* <![CDATA[ */ | |
118 | -/* | |
119 | -* Se você chegou aqui porque está tentando resolver algum bug relacionado ao | |
120 | -* funcionamento do TinyMCE, saiba que este componente não é bugado. A forma como | |
121 | -* ele está configurado o faz funcionar muito fora do padrão e é isso que o faz | |
122 | -* ter certos comportamentos bizarros. Ele precisou ser configurado desta forma | |
123 | -* para se adequar ao mantis. | |
124 | -*/ | |
125 | - | |
126 | -function disableNonEditable(aContent) { | |
127 | - if (aContent == "") return aContent; | |
128 | - // Aqui eu preciso remover o atributo "class" de todos os elementos que | |
129 | - // não podem ser editados diretamente no TinyMCE. Isso é necessário porque o | |
130 | - // mantis não exibe corretamente os elementos que contém atribtutos, então, | |
131 | - // salvar elementos com um atributo class definido é ruim | |
132 | - let html = (new DOMParser()).parseFromString(aContent,"text/html"); | |
133 | - | |
134 | - // Removendo o atributo class dos nós de referência a anexos (<atta>) | |
135 | - let nodes = html.getElementsByTagName("atta"); | |
136 | - for (let atta of nodes) { | |
137 | - atta.removeAttribute("class"); | |
138 | - } | |
139 | - | |
140 | - // Removendo o atributo class dos nós de aprovação em testes (<teap>) | |
141 | - nodes = html.getElementsByTagName("teap"); | |
142 | - for (let teap of nodes) { | |
143 | - teap.removeAttribute("class"); | |
144 | - } | |
145 | - | |
146 | - // Removendo o atributo class dos nós de rejeição em testes (<tere>) | |
147 | - nodes = html.getElementsByTagName("tere"); | |
148 | - for (let tere of nodes) { | |
149 | - tere.removeAttribute("class"); | |
150 | - } | |
151 | - | |
152 | - // Removendo o atributo class dos nós de aprovação em homologação (<hoap>) | |
153 | - nodes = html.getElementsByTagName("hoap"); | |
154 | - for (let hoap of nodes) { | |
155 | - hoap.removeAttribute("class"); | |
156 | - } | |
157 | - | |
158 | - // Removendo o atributo class dos nós de rejeição em homologação (<hore>) | |
159 | - nodes = html.getElementsByTagName("hore"); | |
160 | - for (let hore of nodes) { | |
161 | - hore.removeAttribute("class"); | |
162 | - } | |
163 | - | |
164 | - // Daqui pra frente você já entendeu, não vou comentar mais... | |
165 | - | |
166 | - nodes = html.getElementsByTagName("uds1"); | |
167 | - for (let uds1 of nodes) { | |
168 | - uds1.removeAttribute("class"); | |
169 | - } | |
170 | - | |
171 | - nodes = html.getElementsByTagName("uds2"); | |
172 | - for (let uds2 of nodes) { | |
173 | - uds2.removeAttribute("class"); | |
174 | - } | |
175 | - | |
176 | - nodes = html.getElementsByTagName("uds3"); | |
177 | - for (let uds3 of nodes) { | |
178 | - uds3.removeAttribute("class"); | |
179 | - } | |
180 | - | |
181 | - nodes = html.getElementsByTagName("uds4"); | |
182 | - for (let uds4 of nodes) { | |
183 | - uds4.removeAttribute("class"); | |
184 | - } | |
185 | - | |
186 | - nodes = html.getElementsByTagName("uds5"); | |
187 | - for (let uds5 of nodes) { | |
188 | - uds5.removeAttribute("class"); | |
189 | - } | |
190 | - | |
191 | - nodes = html.getElementsByTagName("unts"); | |
192 | - for (let unts of nodes) { | |
193 | - unts.removeAttribute("class"); | |
194 | - } | |
195 | - | |
196 | - nodes = html.getElementsByTagName("une1"); | |
197 | - for (let une1 of nodes) { | |
198 | - une1.removeAttribute("class"); | |
199 | - } | |
200 | - | |
201 | - nodes = html.getElementsByTagName("une2"); | |
202 | - for (let une2 of nodes) { | |
203 | - une2.removeAttribute("class"); | |
204 | - } | |
205 | - | |
206 | - nodes = html.getElementsByTagName("une3"); | |
207 | - for (let une3 of nodes) { | |
208 | - une3.removeAttribute("class"); | |
209 | - } | |
210 | - | |
211 | - nodes = html.getElementsByTagName("une4"); | |
212 | - for (let une4 of nodes) { | |
213 | - une4.removeAttribute("class"); | |
214 | - } | |
215 | - | |
216 | - nodes = html.getElementsByTagName("une5"); | |
217 | - for (let une5 of nodes) { | |
218 | - une5.removeAttribute("class"); | |
219 | - } | |
220 | - | |
221 | - nodes = html.getElementsByTagName("ungc"); | |
222 | - for (let ungc of nodes) { | |
223 | - ungc.removeAttribute("class"); | |
224 | - } | |
225 | - | |
226 | - nodes = html.getElementsByTagName("stt"); | |
227 | - for (let stt of nodes) { | |
228 | - stt.removeAttribute("class"); | |
229 | - } | |
230 | - | |
231 | - nodes = html.getElementsByTagName("sth"); | |
232 | - for (let sth of nodes) { | |
233 | - sth.removeAttribute("class"); | |
234 | - } | |
235 | - | |
236 | - return html.body.innerHTML; | |
237 | -} | |
238 | - | |
239 | -function enableNonEditable(aContent) { | |
240 | - if (aContent == "") return aContent; | |
241 | - // Aqui eu preciso adicionar o atributo "class" em todos os elementos que | |
242 | - // não podem ser editados diretamente no TinyMCE. A classe a ser aplicada é | |
243 | - // "mceNonEditable" | |
244 | - let html = (new DOMParser()).parseFromString(aContent,"text/html"); | |
245 | - | |
246 | - // Adicionando o atributo class nos nós de referência a anexos (<atta>) | |
247 | - let nodes = html.getElementsByTagName("atta"); | |
248 | - for (let atta of nodes) { | |
249 | - atta.classList.add("mceNonEditable"); | |
250 | - } | |
251 | - | |
252 | - // Adicionando o atributo class dos nós de aprovação em testes (<teap>) | |
253 | - nodes = html.getElementsByTagName("teap"); | |
254 | - for (let teap of nodes) { | |
255 | - teap.classList.add("mceNonEditable"); | |
256 | - } | |
257 | - | |
258 | - // Adicionando o atributo class dos nós de rejeição em testes (<tere>) | |
259 | - nodes = html.getElementsByTagName("tere"); | |
260 | - for (let tere of nodes) { | |
261 | - tere.classList.add("mceNonEditable"); | |
262 | - } | |
263 | - | |
264 | - // Adicionando o atributo class dos nós de aprovação em homologação (<hoap>) | |
265 | - nodes = html.getElementsByTagName("hoap"); | |
266 | - for (let hoap of nodes) { | |
267 | - hoap.classList.add("mceNonEditable"); | |
268 | - } | |
269 | - | |
270 | - // Adicionando o atributo class dos nós de rejeição em homologação (<hore>) | |
271 | - nodes = html.getElementsByTagName("hore"); | |
272 | - for (let hore of nodes) { | |
273 | - hore.classList.add("mceNonEditable"); | |
274 | - } | |
275 | - | |
276 | - // Daqui pra frente você já entendeu, não vou comentar mais... | |
277 | - | |
278 | - nodes = html.getElementsByTagName("uds1"); | |
279 | - for (let uds1 of nodes) { | |
280 | - uds1.classList.add("mceNonEditable"); | |
281 | - } | |
282 | - | |
283 | - nodes = html.getElementsByTagName("uds2"); | |
284 | - for (let uds2 of nodes) { | |
285 | - uds2.classList.add("mceNonEditable"); | |
286 | - } | |
287 | - | |
288 | - nodes = html.getElementsByTagName("uds3"); | |
289 | - for (let uds3 of nodes) { | |
290 | - uds3.classList.add("mceNonEditable"); | |
291 | - } | |
292 | - | |
293 | - nodes = html.getElementsByTagName("uds4"); | |
294 | - for (let uds4 of nodes) { | |
295 | - uds4.classList.add("mceNonEditable"); | |
296 | - } | |
297 | - | |
298 | - nodes = html.getElementsByTagName("uds5"); | |
299 | - for (let uds5 of nodes) { | |
300 | - uds5.classList.add("mceNonEditable"); | |
301 | - } | |
302 | - | |
303 | - nodes = html.getElementsByTagName("unts"); | |
304 | - for (let unts of nodes) { | |
305 | - unts.classList.add("mceNonEditable"); | |
306 | - } | |
307 | - | |
308 | - nodes = html.getElementsByTagName("une1"); | |
309 | - for (let une1 of nodes) { | |
310 | - une1.classList.add("mceNonEditable"); | |
311 | - } | |
312 | - | |
313 | - nodes = html.getElementsByTagName("une2"); | |
314 | - for (let une2 of nodes) { | |
315 | - une2.classList.add("mceNonEditable"); | |
316 | - } | |
317 | - | |
318 | - nodes = html.getElementsByTagName("une3"); | |
319 | - for (let une3 of nodes) { | |
320 | - une3.classList.add("mceNonEditable"); | |
321 | - } | |
322 | - | |
323 | - nodes = html.getElementsByTagName("une4"); | |
324 | - for (let une4 of nodes) { | |
325 | - une4.classList.add("mceNonEditable"); | |
326 | - } | |
327 | - | |
328 | - nodes = html.getElementsByTagName("une5"); | |
329 | - for (let une5 of nodes) { | |
330 | - une5.classList.add("mceNonEditable"); | |
331 | - } | |
332 | - | |
333 | - nodes = html.getElementsByTagName("ungc"); | |
334 | - for (let ungc of nodes) { | |
335 | - ungc.classList.add("mceNonEditable"); | |
336 | - } | |
337 | - | |
338 | - nodes = html.getElementsByTagName("stt"); | |
339 | - for (let stt of nodes) { | |
340 | - stt.classList.add("mceNonEditable"); | |
341 | - } | |
342 | - | |
343 | - nodes = html.getElementsByTagName("sth"); | |
344 | - for (let sth of nodes) { | |
345 | - sth.classList.add("mceNonEditable"); | |
346 | - } | |
347 | - | |
348 | - return html.body.innerHTML; | |
349 | -} | |
350 | - | |
351 | -function isPastingAttachmentReference(aPastedText) { | |
352 | - const regex = /<atta class="mceNonEditable"><atna>(.*)<\/atna><atnn>(.*)<\/atnn>/i; | |
353 | - return regex.exec(aPastedText) != null; | |
354 | -} | |
355 | - | |
356 | -tinyMCE.init({selector: "textarea" | |
357 | - ,height: 300 | |
358 | - ,entity_encoding: "numeric" | |
359 | - ,plugins: "legacyoutput visualblocks lists insertdatetime charmap hr preview fullscreen code searchreplace noneditable tjpe" | |
360 | - ,menubar: false | |
361 | - ,toolbar1: "<?=$toolBar1;?>" | |
362 | - ,toolbar2: "<?=$toolBar2;?>" | |
363 | - ,browser_spellcheck: true | |
364 | - ,contextmenu: false | |
365 | - ,insertdatetime_formats: ["%H:%M:%S", "%d/%m/%Y", "%d/%m/%Y %H:%M:%S", "%d/%m/%Y às %H:%M:%S", "%Y-%m-%d", "%Y-%m-%dT%H:%M:%S"] | |
366 | - ,content_css: ["/mantis/css/default.css" | |
367 | - ,"/mantis/css/common_config.php" | |
368 | - ,"/mantis/css/status_config.php" | |
369 | - ,"/mantis/css/dropzone-4.3.0.min.css" | |
370 | - ,"/mantis/css/bootstrap-3.3.6.min.css" | |
371 | - ,"/mantis/css/font-awesome-4.6.3.min.css" | |
372 | - ,"/mantis/css/open-sans.css" | |
373 | - ,"/mantis/css/bootstrap-datetimepicker-4.17.43.min.css" | |
374 | - ,"/mantis/css/ace.min.css" | |
375 | - ,"/mantis/css/ace-mantis.css" | |
376 | - ,"/mantis/css/ace-skins.min.css" | |
377 | - ,"<?=plugin_file("css/MantisBTMonitor.css");?>"] | |
378 | - ,invalid_elements: "div" | |
379 | - ,extended_valid_elements: "teap[class],tere[class],hoap[class],hore[class],atta[class],atna,atnn,uds1[class],uds2[class],uds3[class],uds4[class],uds5[class],unts[class],une1[class],une2[class],une3[class],une4[class],une5[class],ungc[class],stt[class],sth[class],reit[class],num[class]" // também faz com que os tags customizados não sejam preenchidos com   | |
380 | - ,custom_elements: "teap,tere,hoap,hore,~vers,~stat,~fwte,~fwho,~atta,~atna,~atnn,uds1,uds2,uds3,uds4,uds5,unts,une1,une2,une3,une4,une5,ungc,stt,sth,reit,num" | |
381 | - ,valid_children: "" | |
382 | - // A configuração abaixo foi removida porque o Mantis não gosta de | |
383 | - // tags auto-fechantes (<tag/>). Outra forma de manter os elementos | |
384 | - // que são auto-fechantes é usando o exemplo deste fiddle | |
385 | - // https://fiddle.tiny.cloud/ehhaab | |
386 | - // ,protect: [/\<(teap|tere|hoap|hore) *\/\>/g] // isso é usado para manter os tags sem qualquer alteração pelo TinyMCE | |
387 | - ,block_formats: "Parágrafo simples=p;Texto preformatado=pre;Código \"inline\"=code;Cabeçalho de primeiro nível=h1;Cabeçalho de segundo nível=h2;Cabeçalho de terceiro nível=h3" | |
388 | - ,setup: function(aEditor) { | |
389 | - // Pós processamento executado apenas quando o texto está sendo | |
390 | - // confirmado, isto é, passado do editor para o <textarea> | |
391 | - aEditor.on("GetContent",function(aEventData) { | |
392 | - if (aEventData.format == "html" && aEventData.hasOwnProperty("save") && aEventData.save) { | |
393 | - if (aEventData.content.trim() != "") { | |
394 | - aEventData.content = "<mbtm></mbtm>" + aEventData.content; | |
395 | - } | |
396 | - | |
397 | - aEventData.content = disableNonEditable(aEventData.content); | |
398 | - } | |
399 | - }); | |
400 | - // Pré processamento executado quando o texto está sendo | |
401 | - // carregado no editor, isto é, passado do <textarea> para o | |
402 | - // editor | |
403 | - aEditor.on("BeforeSetContent",function(aEventData){ | |
404 | - aEventData.content = aEventData.content.replaceAll("<mbtm></mbtm>",""); | |
405 | - aEventData.content = enableNonEditable(aEventData.content); | |
406 | - }); | |
407 | - // Verifica se estamos tentando colar no editor algum tag | |
408 | - // especial. Neste caso, não há a colagem padrão, mas sim um | |
409 | - // inserção ou substituição do conteúdo do editor. Este código | |
410 | - // só funciona quando o plugin Paste do TinyMCE não está | |
411 | - // ativado. Este código só atua em colagens de código-fonte no | |
412 | - // editor do TinyMCE. Quando, por exemplo, um tag especial é | |
413 | - // copiado e colado de e para o próprio editor, a expressão | |
414 | - // regular que detecta o conteúdo sendo colado não vai enxergar | |
415 | - // o código-fonte do tag especial, sendo realizada a colagem | |
416 | - // original, que já lida com o tag especial | |
417 | - aEditor.on("paste",function(aEventData) { | |
418 | - let pastedText = (aEventData.clipboardData || window.clipboardData).getData("text/plain"); | |
419 | - | |
420 | - if (isPastingAttachmentReference(pastedText)) { | |
421 | - aEventData.preventDefault(); | |
422 | - aEditor.execCommand("mceInsertContent",false,pastedText); | |
423 | - } | |
424 | - }); | |
425 | - } | |
426 | - }); | |
427 | - | |
428 | -/** | |
429 | -* O Dropzone interfere na forma como o TinyMCE serializa o texto do editor. | |
430 | -* Normalmente o TinyMCE serializa o texto do editor no momento em que o usuário | |
431 | -* executa o submit do <form>, porém em forms que contém o Dropzone, quando se | |
432 | -* adiciona algum arquivo a ser anexado, o envio efetivo dos dados ocorre ANTES | |
433 | -* que o TinyMCE serialize seu texto no <textarea>, fazendo com que o texto não | |
434 | -* seja enviado ao servidor. As linhas abaixo forçam a serialização do conteúdo | |
435 | -* do TinyMCE. Abaixo, primeiramente obtém-se a instância do objeto dropzone | |
436 | -* diretamente a partir do form que foi usado durante sua instanciação e em | |
437 | -* seguida se aplica a solução, a qual foi obtida em: | |
438 | -* https://stackoverflow.com/questions/41481758/include-textarea-tynimce-with-dropzone | |
439 | -*/ | |
440 | - | |
441 | -window.onload = function() { | |
442 | - let dropZone = $("div.dropzone").length > 0?$("div.dropzone").closest("form").length > 0?$("div.dropzone").closest("form")[0].dropzone != undefined?$("div.dropzone").closest("form")[0].dropzone:null:null:null; | |
443 | - | |
444 | - if (dropZone != null) { | |
445 | - dropZone.on("sending", function(file, xhr, formData) { | |
446 | - for (let i = 0;i < tinyMCE.editors.length;i++) { | |
447 | - formData.append(tinyMCE.editors[i].targetElm.name, tinyMCE.editors[i].save()); | |
124 | + echo("\t<script src=\"" . plugin_page("js/mbtmTinyMCE&sn=$scriptName") . "\"></script>\n"); | |
448 | 125 | } |
449 | - }); | |
450 | - } | |
451 | -} | |
452 | - /* ]]> */ | |
453 | - </script> | |
454 | -<?php | |
455 | - } | |
456 | 126 | } |
457 | 127 | |
458 | 128 | echo("\t<!-- MBTMP -->\n"); |
@@ -505,6 +175,37 @@ | ||
505 | 175 | break; |
506 | 176 | } |
507 | 177 | return $result; |
508 | - } | |
178 | + } | |
179 | + | |
180 | + /** | |
181 | + * Limpa a lista de tags informada, removendo da mesma todos os atributos que | |
182 | + * só fazem sentido para o TinyMCE | |
183 | + * @param string $aTagsList String que contém a lista de tags que se pretende | |
184 | + * limpar, removendo da mesma "~" e elementos entre colchetes | |
185 | + * @return string Lista de tags sem qualquer ocorrência de "~" ou elementos | |
186 | + * entre colchetes | |
187 | + */ | |
188 | + function clearTagsList($aTagsList) { | |
189 | + // Esta expressão regular pode não ser suficiente para cobrir todas as | |
190 | + // possibilidade de configuração que o TinyMCE aceita, mas cobre o | |
191 | + // básico | |
192 | + return preg_replace('/~?|\[[\w]*\]/s', "", $aTagsList); | |
193 | + } | |
194 | + | |
195 | + /** | |
196 | + * Retorna a lista de elementos customizados que pode ser usada no atributo | |
197 | + * "custom_elements" do TinyMCE | |
198 | + */ | |
199 | + function getTinyMCECustomElements() { | |
200 | + return preg_replace('/\[[\w]*\]/s', "", plugin_config_get("specialtags") . "," . plugin_config_get("specialnoneditabletags")); | |
201 | + } | |
202 | + | |
203 | + /** | |
204 | + * Retorna a lista estendida de elementos válidos que pode ser usada no | |
205 | + * atributo "extended_valid_elements" do TinyMCE | |
206 | + */ | |
207 | + function getTinyMCEExtendedValidElements() { | |
208 | + return preg_replace('/~?/s', "", plugin_config_get("specialtags") . "," . plugin_config_get("specialnoneditabletags")); | |
209 | + } | |
509 | 210 | } |
510 | 211 | ?> |
\ No newline at end of file |