GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

$.fn.formatTxt   F
last analyzed

Complexity

Conditions 32
Paths 2232

Size

Total Lines 73

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 32
nc 2232
nop 1
dl 0
loc 73
rs 2.6366
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like $.fn.formatTxt often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/*!
2
 * MultiformTextEditor - jQuery plugin for rich text editing
3
 * version: 1.0.0 (30 Nov 2017)
4
 * @requires jQuery v2.0 or later
5
 *
6
 * License: MIT License
7
 *
8
 * Copyright (c) 2017 Multi4me - [email protected]
9
 *
10
 */
11
12
13
14
/*Focado em programadores com experiência em JavaScript e JQuery, o objetivo do plugin é ser uma forma de editar texto com a flexibilidade que permita adicionar qualquer tipo de formatação e inserção sem a necessidade de alterar a base do plugin e usando qualquer estrutura HTML e estilização que se queira.
15
- O protótipo "formatTxt()" aplica os eventos aos itens do menu e caixa de edição para destaque, detecção e aplicação dos formatos e montagens. Usa o objeto "datafrmt_obj" para aplicação das edições com o comando "execCommand(comando, ShowDefaultUI(false), valor(opcional))" e outras possibilidades de formatação.
16
- É possível, por exemplo, adicionar uma lista de formas em SVG (retângulo, losango, elipse, etc.) para serem inseridos no texto, algo que não é padrão dos plugins de edição, ou mesmo um item para aplicar um conjunto de estilos css ao texto selecionado por meio de uma classe pré-criada no css da página.
17
- O programador deverá seguir os padrões do objeto "datafrmt_obj" para adicionar propriedades e métodos para formatar, manipular e inserir na caixa editável ou usando o que já está setado (negrito, itálico, sublinhado, ...), podendo reescrever os dados padrões, seus rótulos e valores.
18
- Como caixa de texto deve-se usar um elemento (não-input) com o atributo "contenteditable" valendo "true" e o menu deve ser montado seguindo apenas alguns padrões:
19
	- cada item de formatação terá a classe "frmttxt-mn-it" e nele o atributo "data-frmt=*" possuirá o mesmo rótulo da formatação referenciada no objeto "datafrmt_obj", opcionalmente podendo-se usar "data-val=*" para quando se quer passar valor à formatação, embora seja possível passar valor de diferentes formas;
20
	- elementos que listam um grupo de itens de formatação (como uma paleta de cores, em que cada cor é um elemento "frmttxt-mn-it") terá a classe "frmttxt-mn-gp", que quando clicado exibirá seu filho com a classe "frmttxt-mn-drpdn" que é quem possui o conjunto de itens de formatação;
21
	- se um elemento em algum lugar no menu for necessário para manipular elementos e dados antes e durante as formatações (como dois elementos para o usuário selecionar se quer aplicar cor ao texto ou fundo), deve-se setar a classe "frmttxt-mn-mp" e o atributo "data-mnpl=*" com o nome do método criado no objeto "datamnpl_obj" (deve ser diferente dos nomes de "datafrmt_obj").
22
- Veja a explicação do objeto "datafrmt_obj" e "datamnpl_obj" ao final. Ambos podem ser editados pelo programador para se alterar os padrões de formatação já disponíveis.
23
- Exemplo de menu de edição e caixa de texto:
24
	<div class="menu-edit unselectable">
25
		<b class="frmttxt-mn-it" data-frmt="ngrto">B</b>
26
		<i class="frmttxt-mn-it" data-frmt="itlco">i</i>
27
		<u class="frmttxt-mn-it" data-frmt="sblnhdo" data-val="underline">U</u>
28
		&nbsp;&nbsp;❘&nbsp;&nbsp;
29
		<div class="frmttxt-mn-gp texto-cor">
30
			<span>✽<span>
31
			<div class="frmttxt-mn-drpdn d-nn">
32
				<span class="frmttxt-mn-it" data-frmt="txtcor" data-val="rgb(255, 255, 255)" style="background: #FFFFFF;"></span><span class="frmttxt-mn-it" data-frmt="txtcor" data-val="rgb(247, 218, 100)" style="background: #F7DA64;"></span>
33
				<span class="frmttxt-mn-it" data-frmt="txtcor" data-val="rgb(0, 168, 133)" style="background: #00A885;"></span><span class="frmttxt-mn-it" data-frmt="txtcor" data-val="rgb(128, 110, 128)" style="background: #806E80;"></span>
34
				<span class="frmttxt-mn-it rmv" data-frmt="txtcor" data-val="#888888" style="background: #F1F1F1;">×</span><!-- Usado como remoção de cor de texto ou fundo -->
35
				<div class="frmttxt-mn-mp" data-mnpl="txtcortp">
36
					<input id="tipo-cor1" type="radio" name="tipo-cor" value="1" checked><label for="tipo-cor1">Texto</label>
37
					<input id="tipo-cor2" type="radio" name="tipo-cor" value="2"><label for="tipo-cor2">Fundo</label>
38
				</div>
39
			</div>
40
		</div>
41
		&nbsp;&nbsp;&nbsp;❘&nbsp;&nbsp;
42
		<span class="frmttxt-mn-it limpa-frmt" data-frmt="lmpfrmt">&nbsp;</span>
43
	</div>
44
	<div id="txt-edit" contenteditable="true" placeholder="Digite o texto"></div>
45
- O exemplo acima foi montado já usando os rótulos das formatações pré-criadas para negrito, itálico, sublinhado e cor e ao ser instanciado, a seguir, acrescenta-se objeto com uma nova formatação para criação de bloco de citação. Uma função é passada como último parâmetro para executar algo após qualquer alteração na caixa de texto:
46
	$(".menu-edit").formatTxt($("#txt-edit"), {tagcompleta: {tg:["BLOCKQUOTE"], vltgc: function(mnit, slc){
47
		return "<blockquote>"+(slc.txt || "...")+"</blockquote>"; 
48
	}}}, null, function(){console.log("alterou")});
49
- Ainda no exemplo acima o programador poderá antes alterar dados das formatações padrões como a "sblnhdo", por exemplo, mudando a forma como texto será sublinhado (aplicando um estilo com atributo "text-decoration") e colocando 'data-val="underline"' no html do item no menu:
50
	$.fn.formatTxt.datafrmt_obj.sblnhdo = {tg:[{nm:null, atr:"style", ext:"text-decoration"}], vlatr: function(mnit, slc){ return ["style", "text-decoration"]; }};
51
	- também poderia-se passar o mesmo objeto na aplicação de "formatTxt()" como parâmetro e usando o mesmo nome da formatação padrão ("sblnhdo") para que seja sobrescrita*/
52
53
54
(function($){
55
	$.fn.formatTxt = function(elmtcx, dfrmt_obj, dmnpl_obj, cllbck){
56
		return this.each(function(){//Aplica à um ou mais elementos de uma vez
57
			var elmt_mn = $(this);//elemento instanciado - menu de edição da caixa
58
			var elmt_cx = (typeof(elmtcx)!="function" ? elmtcx : elmtcx.apply(elmt_mn));
59
			var dados_obj = $.extend({}, $.fn.formatTxt.datafrmt_obj, dfrmt_obj, $.fn.formatTxt.datamnpl_obj, dmnpl_obj);//funde os objetos padrões aos objetos passados como parâmetro. O "$.extend" já valida cada objeto não usando caso seja nulo, indefinido, falso, etc.
60
			elmt_mn.data("frmttxt-cx", elmt_cx);//guarda como dado no menu o elemento da caixa específico
61
			elmt_cx.data("frmttxt-mn", elmt_mn);//guarda como dado na caixa o elemento do menu específico
62
			var pos_limit;//variáveis globalizadas neste escopo
63
			//Prepara clique nos itens de edição do menu para formatação no texto, podendo ser subitem de um grupo. Necessário usar evento "mousedown" evitando problema em "click" no IE
64
			elmt_mn.on("mousedown.mnedt", ".frmttxt-mn-it", function(event){
65
				event.preventDefault();//necessário para melhoria no IE
66
				event.stopPropagation();//evita que os subitens reexecutem eventos do pai
67
				var elmtcxit = $(event.delegateTarget).data("frmttxt-cx");
68
				//Aplica formatação conforme o item de objeto a ser aplicado, podendo ser simples (por tipo e opcionalmente usando valor, podendo ser um método de captura) ou montando a tag completa usando método
69
				var slc_obj = $.fn.formatTxt.GetSetSelectObj();//obtém objeto com os dados de seleção
70
				var dfrmt = $(this).attr("data-frmt");//nome do tipo de formato
71
				dados_obj[dfrmt].precall ? dados_obj[dfrmt].precall(this, slc_obj) : null;//chama o método de pre-execução (quando existe), manipulando dados e elementos antes de usá-los na formatação
72
				var dval = $(this).attr("data-val");//valor do formato ou indefinido (se não existe)
73
				var tp = dados_obj[dfrmt].tp;//tipo de comando (opcional)
74
				var css = dados_obj[dfrmt].css;//true/false para tipo estilização (opcional)
75
				var exec = true;//receberá false caso o comando não seja suportado pelo navegador
76
				var execss;//receberá true/false caso seja usado e o comando para estilização seja suportado ou não pelo navegador
77
				if(css){//Se for passado como "true", antes de aplicar formatação, tenta executar o comando "styleWithCSS" (não suportado pelo IE)
78
					try{
79
						execss = document.execCommand("styleWithCSS", false, "true");//seta para tipo formatação por estilização, ainda retornando true/false conforme sucesso da aplicação
80
					}catch(e){ execss = false; }
81
				}
82
				if(dados_obj[dfrmt].incall){//Se existe, chama o método de execução interna para realizar a formatação toda personalizada
83
					exec = dados_obj[dfrmt].incall(this, slc_obj, execss);
84
				}else{
85
					if(tp){//Simples - executa o tipo de comando a ser aplicado ao texto - "execCommand(CommandName(tp), ShowDefaultUI(false), ValueArgument(null ou informado))"
86
						var vl = dados_obj[dfrmt].vl ? dados_obj[dfrmt].vl(this, slc_obj) : dval;//se valor é um método de captura usa-o passando elemento como parâmetro, senão: usa "data-val" do elemento
87
						try{//Tenta executar comando e caso não seja suportado atribui 'false' à variável "exec"
88
							document.execCommand(tp, false, (vl!=undefined ? vl : null));//um valor é passado ao comando ou nulo
89
						}catch(e){ exec = false; }
90
					}else if(dados_obj[dfrmt].vlatr){//Valores de atributo - aplica ao envólucro da seleção ou cria elemento com o atributo
91
						var vlatr = dados_obj[dfrmt].vlatr(this, slc_obj);//método usa o item de menu/submenu como parâmetro e retorna uma array (['atributo', 'valor1'(opcional), 'valor2'(opcional)])
92
						var atr = vlatr[0]; var vl1 = vlatr[1]; var vl2 = vlatr[2];
93
						var elmt_slc = $(slc_obj.elmt);//elemento/envólucro da seleção
94
						if(!$(slc_obj.elmt).is("[contenteditable=true]") && $(slc_obj.elmt).text() == slc_obj.txt){//Se o envolucro da seleção não é a própria caixa editável e se o texto selecionado é igual à todo o texto do envólucro detectado aplica o atributo
95
							if(atr == "style"){//Para aplicar atributo de estilo:
96
								var ecss = elmt_slc.css(vl1);//valor atual da propriedade css especificado ou indefinido se ainda não foi aplicado
97
								if(dval == "inherit" || ecss == vl2 || ecss == dval){//Se o dado de valor do item no menu é "inherit" ou se, no elemento selecionado, o valor do estilo específico já foi aplicado (com mesmo valor informado ou dado do item):
98
									elmt_slc.css(vl1, "");//retira a propriedade css informada (vl1)
99
								}else{//Se o estilo ainda não foi aplicado ou valor é diferente:
100
									elmt_slc.css(vl1, (vl2 ? vl2 : dval));//aplica a propriedade "css" (vl1) informada com o valor (vl2, se informado) ou com o dado de valor do item no menu (dval)
101
								}
102
							}else if(atr == "class"){//Para aplicar atributo de classe:
103
								var cls = (vl1 ? vl1 : dval);//usa como classe o valor (vl1, se informado) ou pelo dado do item no menu (dval)
104
								elmt_slc.toggleClass(cls);//se o elemento já possui a classe remove-a, senão adiciona-a
105
							}else{//Para qualquer outro atributo:
106
								var vl = (vl1 ? vl1 : dval);//usa como valor o vl1 (se informado) ou o dado do item no menu (dval)
107
								elmt_slc.attr(atr) == vl ? elmt_slc.removeAttr(atr) : elmt_slc.attr(atr, vl);//se o elemento já possui o atributo com o mesmo valor especificado remove-o, senão adiciona ou altera com valor informado
108
							}
109
						}else if(slc_obj.txt){//Se seleção não possui invólucro próprio cria um "<span>" padrão com o atributo para substituição (se texto não for vazio)
110
							var elmt_nv = $("<span/>", {"text": slc_obj.txt});//novo elemento padrão com o texto da seleção
111
							atr == "style" ? elmt_nv.css(vl1, (vl2 ? vl2 : dval)) : elmt_nv.attr(atr, (vl1 ? vl1 : dval));//se o atributo a ser adicionado é de estilo aplica css, senão aplica como atributo comum
112
							try{//Tenta executar comando e caso não seja suportado atribui 'false' à variável "exec"
113
								document.execCommand("insertHTML", false, elmt_nv.prop('outerHTML'));//excuta na seleção a substituição pelo elemento novo
114
							}catch(e){ exec = false; }
115
						}
116
					}else if(dados_obj[dfrmt].vltgc){//Tag completa. Insere no lugar do texto selecionado um elemento todo premontado //-->comparar para ver se a seleção já possui elemento com mesma tag e texto e desmontá-lo
117
						var vltgc = dados_obj[dfrmt].vltgc(this, slc_obj);//passa o item de menu/submenu como parâmetro do método
118
						try{//Tenta executar comando e caso não seja suportado atribui 'false' à variável "exec"
119
							document.execCommand("insertHTML", false, vltgc);//usa fixamente o comando "insertHTML" (não suportado pelo IE)
120
						}catch(e){ exec = false; }
121
					}
122
				}
123
				try{//Tenta executar comando não suportado pelo IE
124
					document.execCommand("styleWithCSS", false, "false");//re-seta para tipo formatação por tag's (padrão)
125
				}catch(e){/*faz nada*/}
126
				elmtcxit.focus();//foca na caixa de texto novamente evitando falhas no desfoque
127
				//Chama o método de pós-execução (quando existe), manipulando dados e elementos após a formatação
128
				if(dados_obj[dfrmt].poscall){
129
					var ret = dados_obj[dfrmt].poscall(this, slc_obj, $.fn.formatTxt.GetSetSelectObj(), exec, execss);//parâmetros: o item clicado no menu, dados da seleção inicial, dados da seleção agora, "exec" e "execss" (true/false informando se a formatação foi suportada)
130
					typeof ret == "boolean" ? exec = ret : null;//se há um retorno true/false atribui ao "exec"
131
				}
132
				//Manipula caixa de conteúdo editável e usa a função a ser chamada após mudanças no texto (opcional)
133
				cllbck != undefined ? cllbck.apply(this, [elmtcxit, slc_obj, exec]) : null;//em "apply(this, [param1, param2...])" o primeiro parâmetro refere-se ao "this" (escopo) usado na função, que é o item clicado no menu. Parâmetros: a caixa editável, dados da seleção e exec (true/false informando se o commando foi suportado)
134
				//Executa o clique para ocultar submenu, filtrando pelo evento específico com rótulo ".mnedt"
135
				$("body").trigger("mousedown.mnedt");
136
			});
137
			//Prepara clique nos itens de grupo do menu exibindo o elemento de submenu (dropdown) que agrupa os subitens
138
			elmt_mn.find(".frmttxt-mn-drpdn").hide();//garante que todos submenus estejam ocultos
139
			elmt_mn.on("mousedown.mnedt", ".frmttxt-mn-gp", function(event){
140
				event.preventDefault();//necessário para melhoria no IE
141
				var wrap_drpdwn = $(this).find(".frmttxt-mn-drpdn");
142
				if(wrap_drpdwn.is(":hidden")){//Exibe submenu apenas se está oculto evitando repetições
143
					$("body").trigger("mousedown.mnedt");//se algum outro está visível executa evento que oculta
144
					wrap_drpdwn.show();//exibe o submenu
145
					!pos_limit ? pos_limit = $(event.delegateTarget).offset().left + $(event.delegateTarget).width() : null;//guarda a posição (x, à direita) limite do elemento menu
146
					if(wrap_drpdwn.css("left") != "auto" && (wrap_drpdwn.offset().left + wrap_drpdwn.width()) > pos_limit){//Após ficar visível o submenu é verificado e ajeitado caso passe do limite do menu
147
						wrap_drpdwn.css({left: "auto", right: "-13px"});//inverte-se, ficando deslocado a esquerda
148
					}
149
					var wrap_gp = $(this);//reserva elemento do grupo
150
					//Aplica evento ao "body", verificando quando o usuário clica fora do grupo, ocultando o submenu
151
					$("body").off("mousedown.mnedt keydown.mnedt");//remove eventos previamente evitando acumulo dos mesmos eventos
152
					$("body").on("mousedown.mnedt keydown.mnedt", function(event){//Ao qualquer elemento ser pressionado. É usado rótulo ".mnedt" para ser agora e depois: removido especificamente
153
						var kcd = event.which;
154
						//Verifica se o alvo não é o elemento pai do grupo ("wrap_gp") e não é um elemento filho dela
155
						if(kcd == 27 || (!$(event.target).is(wrap_gp) && wrap_gp.has(event.target).length == 0)){//Filtro de exceções
156
							wrap_gp.find(".frmttxt-mn-drpdn").hide();//oculta submenu
157
							$("body").off("mousedown.mnedt keydown.mnedt");//remove evento, filtrando pelo evento específico com rótulo de menu (sem interferir nos outros cliques do "body")
158
							$.fn.formatTxt.GetSetSelectObj(null, true);//restaura a seleção, quando guardada
159
						}
160
					});
161
				}else if(!$(event.target).is(wrap_drpdwn) && wrap_drpdwn.has(event.target).length == 0){//Se submenu já está visível e o item clicado não foi o submenu e filhos: oculta-o
162
					wrap_drpdwn.hide();//oculta submenu
163
					$.fn.formatTxt.GetSetSelectObj(null, true);//restaura a seleção, quando guardada
164
				}
165
			});
166
			//Prepara clique nos itens de manipulação do menu para agregar eventos extras ao fluxo principal. É necessário o vento "click" para ser executado após o usuário soltar mouse
167
			elmt_mn.on("click.mnedt", ".frmttxt-mn-mp", function(event){
168
				event.stopPropagation();//evita eventos de elementos pai sejam executados
169
				var elmtcxit = $(event.delegateTarget).data("frmttxt-cx");
170
				//Executa métodos conforme o item de objeto "datamnpl_obj"
171
				var slc_obj = $.fn.formatTxt.GetSetSelectObj();//obtém objeto com os dados de seleção
172
				var dmnpl = $(this).data("mnpl");//nome do método manipulador
173
				var ret = dados_obj[dmnpl](this, slc_obj, event);//chama o método manipulando dados e elementos para usá-los nas formatações independentemente
174
				//Como poderá haver alterações após execução do método: manipula a caixa de texto editável
175
				ret !== false ? elmtcxit.focus() : null;//foca na caixa de texto novamente evitando falhas no desfoque, mas apenas se não retornar 'true' (booleano)
176
				elmtcxit.keyup();//executa evento que detecta a formatação para destacar no menu
177
			});
178
			//Ao selecionar texto (por mouse ou teclado) detecta a formatação (tags) para destacar no menu. Usa temporizador para só executar num intervalo de tempo
179
			elmt_cx.on("mouseup.mnedt keyup.mnedt", function(event){
180
				var elmtmnit = $(event.delegateTarget).data("frmttxt-mn");
181
				typeof mnslc_tm != "undefined" ? clearTimeout(mnslc_tm) : null;//limpa o temporizador antes de reseta-lo
182
				mnslc_tm = setTimeout(function(){
183
					elmtmnit.find(".frmttxt-mn-slcndo").removeClass('frmttxt-mn-slcndo');//remove destaque de todos elementos do menu (filhos, netos...) que possuem a classe
184
					var slc_obj = $.fn.formatTxt.GetSetSelectObj();//obtém objeto com os dados de seleção
185
					if(slc_obj && !$(slc_obj.elmt).is("[contenteditable=true]")){//Só entra se há seleção e se o envolucro da seleção não é a própria caixa editável
186
						//Aplica classe de destaque aos elementos do menu comparando "tag" do texto selecionado com as tags de referência (alguns possuem tags altenativas para diferentes navegadores e/ou formas de formatação)
187
						var tg_ar, tg_vl;
188
						for(var prop in dados_obj){//Varre o objeto passando por cada propriedade
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
189
							tg_ar = dados_obj[prop].tg;//array de tags
190
							if(tg_ar){//Se o item possui tags de referência
191
								for(i=0; i<tg_ar.length; i++){
192
									if(typeof tg_ar[i]=="string" && tg_ar[i]==slc_obj.tag){//Tag simples - verifica nome somente [ex.: <b>, <i>, <u>, ...]
193
										elmtmnit.find("[data-frmt="+prop+"]").addClass('frmttxt-mn-slcndo');//aplica o destaque ao item conforme nome da formatação (propriedade)
194
										break;//bateu com uma tag da propriedade atual - sai do loop filho
195
									}else if(tg_ar[i].nm == slc_obj.tag || tg_ar[i].nm === null){//Tag com subitens ({nm:"*", atr:"*", ext:"*"}) - verifica na seleção: nome de tag(pode valer 'null'), atributo, podendo ter dado extra. Se o objeto de tag tem o "nm" igual a 'null' aceita qualquer nome de tag
196
										tg_vl = $(slc_obj.elmt).attr(tg_ar[i].atr);//obtém o valor do atributo informado ou indefinido (se o elemento não o possui).
197
										if(tg_vl){//Se há um valor (o atributo bateu com o do elemento)
198
											if(tg_ar[i].atr == "style"){//Se é atributo estilo: captura o valor pelo dado extra
199
												tg_vl = $(slc_obj.elmt).prop("style")[tg_ar[i].ext];//captura no estilo do elemento selecionado: o valor da propriedade especificada
200
												if(!tg_vl){//Se for invalido pula para a próxima tag
201
													continue;
202
												}
203
											}else if(tg_ar[i].atr == "class"){//Se é atributo de classe usa a classe informada (extra)
204
												if(tg_ar[i].ext && $(slc_obj.elmt).hasClass(tg_ar[i].ext)){//Se a classe foi especificada e existe no elemento usa-a como valor
205
													tg_vl = tg_ar[i].ext;
206
												}else{//Se classe não existe pula para a próxima tag
207
													continue;
208
												}
209
											}
210
											elmtmnit.find("[data-frmt='"+prop+"'][data-val='"+tg_vl+"']").addClass('frmttxt-mn-slcndo');//aplica o destaque ao item do menu
211
											break;//bateu com uma tag da propriedade atual - sai do loop filho
212
										}
213
									}
214
								}
215
							}
216
						};
217
					}
218
				}, 200);
219
			});
220
			//Na caixa, limpa formatação ao colar texto
221
			elmt_cx.on("paste.mnedt", function(event){
222
				event.preventDefault();
223
				var cntd;
224
				if(event.originalEvent.clipboardData){//Verifica se existe dados de cópia na memória
225
					cntd = (event.originalEvent || event).clipboardData.getData('text/plain');//captura o conteúdo copiado
226
					document.execCommand("insertText", false, cntd);//insere o conteúdo
227
				}else if(window.clipboardData){//Verifica dados de cópia na memória (para IE)
228
					cntd = window.clipboardData.getData('Text');//captura o conteúdo copiado
229
					if(window.getSelection){
230
						window.getSelection().getRangeAt(0).insertNode(document.createTextNode(cntd));//insere o conteúdo
231
					}else{
232
						document.selection.createRange().pasteHTML(cntd);//insere o conteúdo
233
					}
234
				}
235
			});
236
			//Na caixa, ao usuário teclar 'tab' insere código de espaço equivalente no html, sem deixar perder o foco
237
			elmt_cx.on("keydown.mnedt", function(event){
238
				var kcd = event.which;//o "which" da jQuery normaliza os códigos de tecla independente do tipo de evento
239
				if(kcd == 9){//código da  tecla "tab"
240
					event.preventDefault();//impede a aplicação padrão da tecla (foco no próximo elemento)
241
					try{//Tenta executar commando padrão do "JavaScript" de inserção de texto (não suportado no IE)
242
						document.execCommand("insertHtml", false, "&nbsp;&nbsp;&nbsp;&nbsp;");
243
					}catch(e){//Se não funcionou insere pelo método de seleção
244
						$.fn.formatTxt.GetSetSelectObj("    ");//insere quatro espaços
245
					}
246
				}
247
			});
248
		});
249
	};
250
	
251
	//Função captura dados do trecho selecionado/posicionado pelo usuário e retorna como objeto. Os parâmetros são para inserção de texto e restauração de seleção de 'range'
252
	$.fn.formatTxt.range = null;
253
	$.fn.formatTxt.GetSetSelectObj = function(txt, rng){
254
		var slc_rng, slc_elmt, slc_tag, slc_txt, vrtxt = (txt && typeof txt == "string");
255
		if(window.getSelection){
256
			var slctn = window.getSelection();
257
			if(slctn.rangeCount){
258
				slc_rng = slctn.getRangeAt(0);
259
				var node = slc_rng.commonAncestorContainer;
260
				slc_txt = slctn.toString();
261
				slc_elmt = node.nodeType == 1 ? node : node.parentNode;
262
				if(slc_txt && slc_elmt.textContent != slc_txt){//Se não bateu com texto selecionado. Para navegadores como Firefox que não detectam o envólucro imediato
263
					var ncntnr = slctn.getRangeAt(0).startContainer.nextSibling;
264
					slc_elmt = (ncntnr && ncntnr.textContent == slc_txt ? ncntnr : slc_elmt);
265
				}
266
				slc_tag = (slc_elmt.nodeType == 1 ? slc_elmt.nodeName : slc_elmt.parentNode.nodeName);
267
				if(vrtxt){//Se foi passado texto para inserção, insere-o
268
					slc_rng.deleteContents();
269
					slc_rng.insertNode(document.createTextNode(txt));
270
				}
271
				if(rng == true && $.fn.formatTxt.range){//Se foi requisitado e há "range" (trecho) reservado: restaura seleção
272
					slctn.removeAllRanges();
273
					slctn.addRange($.fn.formatTxt.range);
274
					$.fn.formatTxt.range = null;//anula reserva de "range" novamente
275
				}
276
			}else{
277
				return null;
278
			}
279
		}else if(document.selection && document.selection.type != "Control"){//Para IE
280
			slc_rng = document.selection.createRange();
281
			slc_elmt = slc_rng.parentElement();
282
			slc_txt = slc_rng.text;
283
			slc_tag = slc_rng.parentElement().nodeName;
284
			vrtxt ? slc_rng.text = txt : null;//se informado texto, insere-o
285
			if(rng == true && $.fn.formatTxt.range){//Se foi requisitado e há "range" (trecho) reservado: restaura seleção
286
				$.fn.formatTxt.range.select();
287
				$.fn.formatTxt.range = null;//anula reserva de "range" novamente
288
			}
289
		}else{
290
			return null;
291
		}
292
		return {rng: slc_rng, elmt: slc_elmt, tag: slc_tag, txt: slc_txt};
293
	}
294
	//Função para alterar elemento(s) podendo-se mudar a tag/elemento, assim como adicionar e remover atributos, opcionalmente
295
	$.fn.formatTxt.altrElmnt = function(elmt, nelmt, atr_ad, atr_rm){
296
		elmt.each(function(){
297
			if(atr_ad){//Se há array de atributos a serem adicionados:
298
				for(i=0; i<atr_ad.length; i++){
299
					var atr = atr_ad[i].atr;
300
					var vl1 = (typeof atr_ad[i].vl1 != "function" ? atr_ad[i].vl1 : atr_ad[i].vl1(this));
301
					if(atr == "style"){//Se é atributo de estilo inclui por "css()" usando dois valores
302
						var vl2 = (typeof atr_ad[i].vl2 != "function" ? atr_ad[i].vl2 : atr_ad[i].vl2(this));
303
						$(this).css(vl1, vl2);
304
					}else if(atr == "class"){//Se é atributo de classe inclui valor por "addClass()"
305
						$(this).addClass(vl1);
306
					}else{//Se é atributo comum inclui valor
307
						$(this).attr(atr, vl1);
308
					}
309
				}
310
			}
311
			if(atr_rm){//Se há array de atributos a serem removidos:
312
				for(i=0; i<atr_rm.length; i++){
313
					$(this).removeAttr(atr_rm[i]);
314
				}
315
			}
316
			if(nelmt){//Se foi passado novo elemento, substitui pela tag informada
317
				var atrs = {};
318
				$.each($(this)[0].attributes, function(idx, atr){//Reserva os atributos do elemento
319
					atrs[atr.nodeName] = atr.nodeValue;
320
				});
321
				//Substitui o elemento pelo novo, com todos os atributos e conteúdo
322
				$(this).replaceWith( $("<"+nelmt+"/>", atrs).append($(this).contents()) );
323
			}
324
		});
325
	}
326
	//Função para matar aplicações do plugin nos filhos do elemento (ou coleção de elementos) de menu e de cada caixa editável. Remove eventos com o rótulo "mnedt" e outros dados
327
	$.fn.formatTxt.destroy = function(elmt){//O elemento do parâmetro deve ser um menu que tenha sido instanciado anteriormente
328
		$("body").trigger("mousedown.mnedt");//oculta submenus
329
		elmt.off(".mnedt");//remove eventos do(s) menu(s)
330
		elmt.find("*").off(".mnedt");//remove eventos dos filhos do(s) menu(s)
331
		elmt.find(".frmttxt-mn-slcndo").removeClass('frmttxt-mn-slcndo');//remove destaques do(s) menu(s)
332
		elmt.each(function(){//Usa o elemento da caixa editável reservado em cada menu
333
			var elmtcxit = $(this).data("frmttxt-cx");
334
			elmtcxit.off(".mnedt");//remove eventos da caixa
335
			elmtcxit.find("*").off(".mnedt");//remove eventos dos filhos da caixa
336
			elmtcxit.removeData("frmttxt-mn");//remove o dado com o elemento de menu reservado na caixa
337
		});
338
		elmt.removeData("frmttxt-cx");//remove o dado com o elemento de caixa reservado na(s) caixa(s)
339
	}
340
341
	/*- Cada item (propriedade) é um rótulo para a formatação e o elemento do menu deverá ter o mesmo em "data-frmt='nome'", ex.: "ngrto" para aplicação de negrito.
342
	- O subitem "precall" (quando necessário) é um método de pre-execução chamado para manipular dados e elementos antes de usá-los na formatação, podendo alterar até mesmo os próprios dados do objeto (ex.: usando formatação de cor, antes de executar, é verificado se foi selecionado aplicação de cor no texto ou no fundo, alterando o subitem de tipo de formatação "tp"), o "incall" executa internamente para quando se quer aplicar formatação de uma maneira totalmente personalizada e o "poscall" faz o mesmo mas ao final das execuções principais e por isso pode ser usado para solucionar execuções não suportadas (nesse caso deve-se retornar true/false conforme funcionamento).
343
	- O subitem "tp" é o nome do tipo padrão de comando a ser aplicado como formatação. Quando não usado, a formatação usará apenas o subitem "vlatr" ou "vltgc".
344
	- O subitem "tg" possui array com as tags (em maiúsculo) de referência para a tag que a formatação cria e para, ao usuário selecionar texto, destacar o elemento do menu correspondente (ex.:"B" para <b> procurará elemento com data-frmt="ngrto"), podendo ser várias (navegadores podem criar diferentes tags) e quando a mesma formatação possui valores diferentes (como tamanhos de fonte) e/ou é aplicada usando os métodos de valor ("vlatr" ou "vltgc") "tg" poderá ter objetos com 'nome', 'atributo', podendo possuir ainda propriedade 'extra' para style ou valor específico de classe, ex.: {nm:"SPAN", atr:"style", ext:"font-size"} ou {nm:"DIV", atr:"class", ext:"formato-1"}. O 'extra' para atributo "style" deverá seguir o padrão do método "css()" da jQuery (ex.: "borderTopWidth" para borda superior).
345
	- Quando se quer aplicar valor o item (elemento) do menu deverá possuir "data-val='valor'" e o valor deverá ser "inherit" para os casos em que se quer remoção de estilo específico. O subitem "vl" é um método para capturar valor dinamicamente (como a cor) sem se usar "data-val='valor'". O subitem "vlatr" retorna uma array com um 'atributo' (índice 0), 'valor1' (2, opcional) e 'valor2' (3, opcional - fixo ou capturado se não for usado o "data-val='valor'") para ser aplicado ao trecho selecionado, ex.: ["style", "color", mnit.css("color")], se "tg" for usado deverá ter o "nm" valendo "null" pois o atributo poderá ser aplicado a qualquer elemento que circunda a seleção. O método "vltgc" é para substituir a seleção por uma tag completa (incluindo o texto), ex.: para uma linha: "<hr>" ou para uma citação: "<blockquote>texto</blockquote>". Nos casos de uso de "vlatr" e "vltgc" o subitem "tp" não será usado.
346
	- O subitem "css" deverá ser incluído valendo "true" quando se quer que a formatação aconteça por meio de estilização ou como no caso de criação de lista (que ajeita o tamanho dos subelementos) altere filhos por estilização. É útil para tipos de comandos que criam por padrão tag's não suportadas em HTML5, como a criação de "<font...>" (obsoleto) para cor e tamanho. Seu uso limita a comparação de tag com valor (para destaque) em alguns casos, nos quais deverá ser usado o método "vlatr" ou "vltgc" para aplicar a formatação*/
347
	$.fn.formatTxt.datafrmt_obj = {
348
		ngrto: {tp:"bold", tg:["B", "STRONG"]}, itlco: {tp:"italic", tg:["I", "EM"]}, sblnhdo: {tp:"underline", tg:["U"]},
349
		rscdo: {tp:"strikeThrough", tg:["STRIKE"]}, sbrscrto: {tp:"superscript", tg:["SUP"]}, sbscrto: {tp:"subscript", tg:["SUB"]},
350
		sbrlnhdo: {tg:[{nm:null, atr:"style", ext:"text-decoration"}], vlatr: function(mnit, slc){ return ["style", "text-decoration"]; }},
0 ignored issues
show
Unused Code introduced by
The parameter mnit is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter slc is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
351
		insrcrctr: {tp:"insertText", vl: function(mnit, slc){ return $(mnit).text(); }, poscall: function(mnit, slc, nslc, exc, excs){
0 ignored issues
show
Unused Code introduced by
The parameter excs is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter slc is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
352
						//Uma vez que a inserção de texto pelo comando "document.execCommand("insertText", ...)" não é suportado pelo IE:
353
						if(exc == false){//Usa a função 'cross-browser' de seleção, para inserir
354
							return ($.fn.formatTxt.GetSetSelectObj($(mnit).text()) ? true : false);//retorna true/false conforme funcionamento
355
						}
356
					}},
357
		tplist1: {tp:"insertUnorderedList", css: true}, tplist2: {tp:"insertOrderedList", css: true},
358
		fnttmnho: {tg:[{nm:null, atr:"style", ext:"font-size"}], vlatr: function(mnit, slc){ return ["style", "font-size"]; }},
0 ignored issues
show
Unused Code introduced by
The parameter slc is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter mnit is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
359
		txtcor: {precall: function(mnit, slc){
0 ignored issues
show
Unused Code introduced by
The parameter slc is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
360
					this.tp = ($(mnit).parents(".frmttxt-mn-drpdn").find(".frmttxt-mn-mp input:checked").val() == "1" ? "foreColor" : "backColor");
361
				}, tp:"foreColor", tg:[{nm:null, atr:"style", ext:"color"}], css: true, poscall: function(mnit, slc, nslc, exc, excs){
362
					if(excs == false && nslc.tag == "FONT"){//Se formatação não foi aplicada com estilização e foi criado um elemento "<font>" (para IE):
363
						/*this.tg[0].nm = "FONT"; this.tg[0].atr = "color"; this.tg[0].ext = null;//altera padrões da tag de comparação
364
						var mnitval = $(mnit).attr("data-val"); $(mnit).attr("data-val", mnitval.replace(/\s/g, ""));//retira do valor os espaços conforme padrão da tag <font>: 'rgb(235,107,86)'*/
365
						if(this.tp == "foreColor"){//Se foi aplicado cor de texto substitui por um "<span>" com estilo da mesma cor
366
							$.fn.formatTxt.altrElmnt($(nslc.elmt), "span", [{atr:"style", vl1:"color", vl2:$(nslc.elmt).attr("color")}], ["color"]);
367
						}else{//Se foi aplicado cor de fundo substitui por um "<span>" (já foi aplicado com estilo)
368
							$.fn.formatTxt.altrElmnt($(nslc.elmt), "span");
369
						}
370
					}
371
				}},
372
		insrlnk: {precall: function(mnit, slc){
0 ignored issues
show
Unused Code introduced by
The parameter slc is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
373
					var inp_elmt = $(mnit).parents(".frmttxt-mn-drpdn").find("input"); var val_txt = inp_elmt.val();
374
					inp_elmt.val((/^([a-zA-Z0-9+.-]+):\/\//i).test(val_txt) || val_txt=="" ? val_txt : "http://"+val_txt);//verifica se há protocolo na url e insere "http://" por padrão
375
					$.fn.formatTxt.GetSetSelectObj(null, true);//restaura a seleção guardada para formatação do mesmo trecho
376
				}, tp:"createLink", vl: function(mnit, slc){ return $(mnit).parents(".frmttxt-mn-drpdn").find("input").val(); }, poscall: function(mnit, slc, nslc, exc, excs){
0 ignored issues
show
Unused Code introduced by
The parameter exc is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter slc is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter excs is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
377
					var inp_elmt = $(mnit).parents(".frmttxt-mn-drpdn").find("input");
378
					if(inp_elmt.val()){//Se o valor do input é valido:
379
						!this.tp ? $(nslc.elmt).attr("href", inp_elmt.val()) : null;//se o "tp" está anulado (quando há link focado mas não selecionado) apenas altera a "url"
380
						$(nslc.elmt).attr("target", "_blank");//após criar link adiciona "target" para nova aba ao clicar
381
						$(mnit).parents(".frmttxt-mn-drpdn").find("input").val("");//apenas limpa o texto do "input" após formatação
382
					}
383
				}},
384
		rmvlnk: {precall: function(mnit, slc){
385
					slc.tag=="A" && slc.txt=="" ? this.tp = null : null;//anula o tipo de formatação quando há link focado mas não selecionado, para pular direto para o "poscall()"
386
				},tp:"unlink", tg:["A"], poscall: function(mnit, slc, nslc, exc, excs){
0 ignored issues
show
Unused Code introduced by
The parameter nslc is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter exc is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter excs is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
387
					if(slc.tag=="A" && !this.tp){//Se o "tp" está anulado (quando há link focado mas não selecionado):
388
						$(slc.elmt).replaceWith($(slc.elmt).text());//remove link substituindo o elemento por seu texto
389
						this.tp = "unlink";//retorna o tipo de formatação
390
					}
391
				}},
392
		lmpfrmt: {tp:"removeFormat"}
393
		/*, simplescaptura: {tp:"insertText", vl: function(mnit){ return $(mnit).text();}},
394
		atributo-css: {tg:[{nm:null, atr:"style", ext:"text-decoration"}], vlatr: function(mnit){ return ["style", "text-decoration"]; }},
395
		atributo-class: {tg:[{nm:null, atr:"class", ext:"sobrelinhado"}], vlatr: function(mnit){ return ["class"]; }},
396
		tagcompleta: {tg:["BLOCKQUOTE"], vltgc: function(mnit, slc){ return "<blockquote>"+(slc.txt || "...")+"</blockquote>"; }}*/
397
	}
398
	/*- Para eventos extras do menu pode-se usar o objeto "datamnpl_obj" de métodos para anexar manipulações ao fluxo principal de formatações e independente delas. Ex.: a formatação de cor necessita de um manipulador para alterar o valor de destaque (dstq:{atr:"style", ext:"color"}) entre cor do texto ("color") e cor do fundo ("background-color") verificando qual foi selecionado pelo usuário.
399
	- Os nomes/rótulos dos métodos devem ser diferentes dos nomes de propriedade em "datafrmt_obj" uma vez que, no instanciamento, eles são unidos num só objeto, permitindo manipulação de todos os dados. O uso de 'this' nos métodos refere-se ao objeto pai "dados_obj" criado no instanciamento.*/
400
	$.fn.formatTxt.datamnpl_obj = {
401
		txtcortp: function(mnmp, slc){//Para cores
0 ignored issues
show
Unused Code introduced by
The parameter slc is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
402
			var chk = $(mnmp).children("input:checked").val();//opção selecionada pelo usuário
403
			this.txtcor.tg[0].ext = (chk == "1" ? "color" : "background-color");//altera o valor de comparação para destaque
404
			$(mnmp).parents(".frmttxt-mn-drpdn").find(".frmttxt-mn-it.rmv").attr("data-val", (chk == "1" ? "#888888" : "inherit"));//altera o valor usado no item que simula remoção de cor, usando a cor padrão para cor de texto e "inherit" para cor de fundo
405
		},
406
		insrlnkvl: function(mnmp, slc, evnt){//Para inserção de caracteres
407
			var inp_elmt = $(mnmp).find("input");
408
			if(inp_elmt.is(":visible")){//Se o "input" estiver visível:
409
				if(slc && !$(evnt.target).is(inp_elmt)){//Se há seleção e "input" não foi clicado depois de já visível:
410
					$.fn.formatTxt.range = slc.rng;//reserva o "range" (trecho) selecionado antes de perder foco
411
					this.insrlnk.tp = (slc.tag=="A" && slc.txt=="" ? null : "createLink");//se uma tag de link foi focado, mas não selecionada, anula o "tp" (tipo de comando) da formatação "insrlnk", obrigando a alteração apenas do "href" pelo método "vlatr"
412
					var val_txt = (slc.tag=="A" ? $(slc.elmt).attr("href") : "");//verifica se o elemento selecionado já é link, capturando a url ou vazio
413
					inp_elmt.val(val_txt).focus();//inlui texto e foca no "input"
414
				}
415
				if(!$._data(inp_elmt[0], "events")){//Se ainda não foi aplicado o evento de tecla ao input:
416
					inp_elmt.on("keydown.mnedt", function(event){//Ao pressionar alguma tecla, verifica:
417
						var kcd = event.which;
418
						if(kcd == 13){//código da  tecla "enter"
419
							event.preventDefault();//impede a aplicação padrão da tecla (foco no próximo elemento)
420
							inp_elmt.val() ? $(this).parent().children(".frmttxt-mn-it").mousedown() : null;//se link é valido executa o evento de formatação já aplicado ao botão "ok"
421
						}
422
					});
423
				}
424
				return false;//retorna 'false' para evitar que a caixa editável seja focada saindo do "input"
425
			}else{
426
				inp_elmt.val("");//apenas limpa o "input" ao ocultar
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
427
			}
428
		}
429
	}
430
}(jQuery));
431