TinyMCE removing attribute from custom tag - html

I'm trying to insert a placeholder in html code that will be replaced later on dynamically. So far I managed to get the code inserted, and TinyMCE recognizes the tag, but when I try to append an id attribute to it, the attribute gets removed for an unknown reason. I tried most of the additional options, but none seem to work.
Current config:
extended_valid_elements : "module[id]",
valid_children : "module[img]",
custom_elements : "module",
The code to create the button (and subsequently insert the code):
setup : function(ed) {
// Add a custom button
ed.addButton("module", {
title : "Module",
image : "images/app-x-php-icon.png",
onclick : function() {
ed.focus();
var options = document.getElementById('rendermcemods').innerHTML+"";
var optionList = options.split('|');
var name=prompt("Please enter module name out of: "+options,optionList[0]);
for(var i=0;i<optionList.length;i++){
if(optionList[i] == name){
var patt=new RegExp('<module id="'+name+'">.*</module>','ig');
var content = '<module id="'+name+'"><img src="images/app-x-php-icon.png" /></module>';
//alert(content);
if(! patt.test(ed.getContent())){
ed.execCommand('mceInsertContent', false,content);
}
}
}
}
});
}
As you might notice, there's an alert before the insert, which I used to verify that the content is right...
When use the button to insert the code and then view the html, this is what I get:
<module><img src=images/app-x-php-icon.png" alt="" /></module>
Would anyone know how to fix this?
Update:
full config settings for tinyMCE:
// General options
mode : "none",
theme : "advanced",
plugins : "autolink,lists,spellchecker,pagebreak,style,layer,table,\n\
save,advhr,advimage,advlink,emotions,iespell,inlinepopups,\n\
insertdatetime,media,searchreplace,print,contextmenu,paste,\n\
directionality,fullscreen,noneditable,visualchars,\n\
nonbreaking,xhtmlxtras",
// Theme options
theme_advanced_buttons1 : "fullscreen,help,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,styleselect,formatselect,fontselect,fontsizeselect,|,module",
theme_advanced_buttons2 : "cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,code,|,insertdate,inserttime,|,forecolor,backcolor",
theme_advanced_buttons3 : "tablecontrols,|,hr,removeformat,visualaid,|,sub,sup,|,charmap,emotions,iespell,media,advhr,|,ltr,rtl,|,spellchecker,|,cite,abbr,acronym,del,ins,attribs,|,visualchars,nonbreaking,blockquote,|,insertfile,insertimage",
theme_advanced_toolbar_location : "top",
theme_advanced_toolbar_align : "left",
theme_advanced_statusbar_location : "bottom",
theme_advanced_resizing : true,
// Skin options
skin : "o2k7",
skin_variant : "silver",
document_base_url : "http://www.example.com",
content_css : "content.css",
extended_valid_elements : "module[id]",
valid_children : "module[img]",
/*custom_elements : "module", */
// Drop lists for link/image/media/template dialogs
external_link_list_url : "js/generateList.php?A=link",
external_image_list_url : "js/generateList.php?A=image",
media_external_list_url : "js/generateList.php?A=media",
setup : function(ed) {
// Add a custom button
ed.addButton("module", {
title : "Module",
image : "images/app-x-php-icon.png",
onclick : function() {
ed.focus();
var options = document.getElementById('rendermcemods').innerHTML+"";
var optionList = options.split('|');
var name=prompt("Please enter module name out of: "+options,optionList[0]);
for(var i=0;i<optionList.length;i++){
if(optionList[i] == name){
var patt=new RegExp('<module id="'+name+'">.*</module>','ig');
var content = '<module id="'+name+'"><img src="images/app-x-php-icon.png" /></module>';
//alert(content);
if(! patt.test(ed.getContent())){
ed.execCommand('mceInsertContent', false,content);
}
}
}
}
});
}
Another update: It might be interesting (and hopefully help to solve) to know that the id attribute isn't removed when tinyMCE is loaded and it already is in there, and a clean-up on existing code with the attribute doesn't remove it either.

I would put module to the valid_elements instead of the extended_valid_elements/custom_elements. The extended_valid_elements do sometimes behave strange.
My own config then looks like this (you will need to enlarge your own valid_elements and valid_children settings (if not used in your custom tinymce config you will have to use the defaults (can be found at the moxiecode website))):
// The valid_elements option defines which elements will remain in the edited text when the editor saves.
valid_elements: "#[id|class|title|style|onmouseover]," +
"module," +
"a[name|href|target|title|alt]," +
"#p,blockquote,-ol,-ul,-li,br,img[src|height|width],-sub,-sup,-b,-i,-u," +
"-span[data-mce-type],hr",
valid_children: "body[p|ol|ul|hr]" +
"module[img]" +
",p[a|span|b|i|u|sup|sub|img|hr|#text|blockquote]" +
",span[a|b|i|u|sup|sub|img|#text|blockquote]" +
",a[span|b|i|u|sup|sub|img|#text|blockquote]" +
",b[span|a|i|u|sup|sub|img|#text|blockquote]" +
",i[span|a|b|u|sup|sub|img|#text|blockquote]" +
",sup[span|a|i|b|u|sub|img|#text]" +
",sub[span|a|i|b|u|sup|img|#text]" +
",li[span|a|b|i|u|sup|sub|img|ol|ul|#text]" +
",ol[li]" +
",ul[li]",

The solution I ended up using was modifying the blockElementsMap and the transitional map taht are in the source code. That seemed to be the only way to get the custom tag recognized as 'blocklevel' element, as well as being able to add it exactly like I want in the code for later processing.

Related

Multi-checkboxes And Chart Data

I try out to create a Data visualization with Chart.js.
My question is quite simple...
I have multi with different id.
Checking an input "from" to an input "to"
you will able to get data in your chart,
If you check A to B you get some Data, if you check A to C some others... etc...
so I use multi condition to define the data must be shown in my Chart.
here my code,
<input id="DFN001" type="checkbox" name="DFN001" onclick="check()" value="from" >From DFN001</li>
and my JavaScript
<script>
var ctx1 = document.getElementById("chart_1").getContext("2d");
var data = datas1 ;
function validate(){
var DFN001 = document.getElementById('DFN001');
if (DFN001.checked){
datas1 = [10,15,20,85,30,35,40];
}else{
alert("You didn't check it! Let me check it for you.")
}
}
var lineChartData1 = {
labels : ["January","February","March","April","May","June","July"],
datasets : [
{
label: "My First dataset",
fillColor : "rgba(220,220,220,0.2)",
strokeColor : "rgba(220,220,220,1)",
pointColor : "rgba(220,220,220,1)",
pointStrokeColor : "#fff",
pointHighlightFill : "#fff",
pointHighlightStroke : "rgba(220,220,220,1)",
data : data
}
]
}
document.getElementById('generate_1').onclick = function()
{
window.myPie = new Chart(ctx1).Line(lineChartData1,{
responsive: true
});
};
</script>
but when I try it, I get this error... "Uncaught ReferenceError: datas1 is not defined" ...
Can Someone Help me ? or there is and other way do make it ?
thanks a LOT !
Best Regards, and Nice Day,
Mirko
You have a couple of program flow related stuff you have to take care of.
datas1 needs to be initialized before you attempt to set data using it. So you need to call validate(), not just declare it. In validate(), datas1 will be set only if the checkbox is checked. For now, let's simply check it using HTML (when you add the rest of your code, just remember not to attempt setting data unless datas1 is set i.e. the corresponding checkbox is checked)
<input id="DFN001" type="checkbox" name="DFN001" onclick="check()" value="from" checked>From DFN001
Calling validate is pretty simple
...
validate();
var ctx1 = document.getElementById...
You need to call new Chart to actually render the chart. Something like
new Chart(ctx1).Line(lineChartData1);
Finally you need to have the canvas element in your HTML (I assume you already have this - just included for completeness)
<canvas id="chart_1"></canvas>
In short, you'll need to call the Chart initialization, data initialization, etc. (on your checkbox clicks) keeping the above in mind.
Here's a fiddle with all the above changes - http://jsfiddle.net/cy2spqrg/

Can't bind html with angularJS and tinymce

so the goal is to edit some text with tinymce, persist it and display it in a div using angularJS with the same html, style formating.
I'm using tinymce 3.5.8 with angularUI directive, I've managed to save the content of the wysiwyg in my database (mySQL, TEXT). I'm retrieving it through Spring as a String and send it back to the angularJS app.
I've tried putting a
<div ng-bind-html-unsafe="myModel">
where myModel is defined as
$scope.myModel = Projet.get(getting the json somewhere);
but tags are not interpreted as html, they just print like
<p><span style="color #ff9900;>Texte de test</span></p>.
I've also tried with ngSanitize and ng-bind-html.
html :
<div class="content-swipe-box">
<h3>Contexte</h3>
<div ng-bind-html-unsafe="projet.contexte"></div>
</div>
controller :
$scope.projet = ProjetService.getProject($routeParams.projectId);
Database entry (TEXT)
<p><span style="color: #ff9900;">aaaaa</span></p>
<p>&nbsp;</p>
directive (that's the angularui directive where I've added options):
...
link: function (scope, elm, attrs, ngModel) {
var expression, options, tinyInstance;
// generate an ID if not present
if (!attrs.id) {
attrs.$set('id', 'uiTinymce' + generatedIds++);
}
options = {
skin:"bootstrap",
theme_advanced_disable:"styleselect, anchor",
plugins : "advlist, fullscreen, preview",
theme_advanced_buttons1:"bold, italic, underline, justifyleft, justifycenter, justifyright, justifyfull, formatselect, fontselect, fontsizeselect, forecolor",
theme_advanced_buttons2:"bullist, numlist, outdent, indent, undo, redo, link, unlink, image, cleanup, code, blockquote, hr,removeformat,visualaid,separator,charmap, preview, fullscreen ",
theme_advanced_resizing: true,
theme_advanced_resize_horizontal : false,
force_br_newlines : true,
force_p_newlines : false,
Thank you for your help !
It sounds like you have saved the html to your database as escaped html. If this is what has happened then you will have to unescape it first, you can do that using the technique described in this answer
function htmlDecode(input){
var e = document.createElement('div');
e.innerHTML = input;
return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
}
htmlDecode("<img src='myimage.jpg'>");
// returns "<img src='myimage.jpg'>"

tinymce text alignment issue

I write text description in tinymce with spaces and html(line break and others etc etc).then i save it to mysql database.when i get it again and alert it,it shows me as same as it was.so till now it is fine.
When again i add it to tinymce to edit it,all html and spaces disappears..what can be the issue?
Here is my code
$('#description').tinymce({
// Location of TinyMCE script
script_url : 'tinymce/jscripts/tiny_mce/tiny_mce.js',
// General options
width : "825",
height: "300",
theme : "advanced",
theme_advanced_toolbar_align : "left",
theme_advanced_statusbar_location : "bottom",
theme_advanced_toolbar_location : "top",
theme_advanced_buttons1 : "bold,italic,underline,strikethrough,bullist,numlist,spellchecker",
theme_advanced_buttons2 : "",
theme_advanced_buttons3 : "",
theme_advanced_buttons4 : "",
force_br_newlines : true,
force_p_newlines : false,
gecko_spellcheck : true,
forced_root_block : '', // Needed for 3.x
plugins : "paste,spellchecker",
spellchecker_languages : "+English=en,Russian=ru",
// encoding : "xml",
// Example content CSS (should be your site CSS)
content_css : "tinymce/examples/css/content.css",
//
apply_source_formatting : true,
// Replace values for the template plugin
template_replace_values : {
username : "Some User",
staffid : "991234"
}
});
here is how i am getting value
alert(json.description_demo);//this is ok
$("#description").val(json.description_demo);
alert($("#description").val());//now this is not ok..here is issue
tried this also
alert(json.description_demo);//ok
tinyMCE.get('description').setContent(json.description_demo);
alert(tinyMCE.get('description').getContent());//issue not ok
images
You will have to use tinyMce features to get ans set the value.
Try using
tinyMCE.get('description').getContent() to get the value
tinyMCE.get('description').setContent(value from db) to set the value.
Chekout tinymce docs http://www.tinymce.com/wiki.php/API3:method.tinymce.Editor.getContent

TinyMCE strips class attribute from iframe element

I want to target specific iframes using a class attribute in order to set the width with CSS.
The iframes are google maps embeds like this one:
<iframe width="425" height="350" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="https://maps.google.co.uk/?ie=UTF8&t=m&ll=52.8382,-2.327815&spn=4.646012,9.338379&z=6&output=embed"></iframe>
They are copied and pasted into the HTML source editor of tinyMCE. I need to apply a class attribute to the iframe but it is striped out when clicking update on the source editor.
I've tried using valid_elements and extended_valid_elements in the config but neither work for iframe[class].
I'm running version 3.4.3. I downloaded 3.5.7 and the it seems to have the same problem. The behaviour is also exhibited on the demo on the tinyMCE website (http://www.tinymce.com/tryit/full.php) despite the docs for valid_elements stating that the class attribute is supported (http://www.tinymce.com/wiki.php/Configuration:valid_elements).
Here is the full config:
tinyMCE.init({
// General options
mode : "specific_textareas",
editor_selector : "formInputWysiwyg",
theme : "advanced",
plugins : "autolink,lists,pagebreak,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,inlinepopups,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,wordcount,advlist",
// Theme options
theme_advanced_buttons1 : "bold,italic,strikethrough,formatselect,styleselect,undo,redo,|,code,|,fullscreen,",
theme_advanced_buttons2 : "cut,copy,paste,pastetext,|,search,replace,|,bullist,numlist,|,blockquote,nonbreaking,|,charmap,media,|,link,unlink,anchor,image",
theme_advanced_buttons3 : "",
theme_advanced_buttons4 : "",
theme_advanced_toolbar_location : "top",
theme_advanced_toolbar_align : "left",
theme_advanced_statusbar_location : "bottom",
theme_advanced_resizing : true,
width : "500",
height : "600",
apply_source_formatting : true,
remove_linebreaks: true,
theme_advanced_blockformats : "p,blockquote,h1,h2,h3,h4,h5,h6",
forced_root_block : false,
plugin_preview_width : "1050",
plugin_preview_height : "800",
convert_urls : false,
extended_valid_elements : "figure,figcaption",
// Skin options
skin : "o2k7",
skin_variant : "silver",
// Example content CSS (should be your site CSS)
content_css : "/admin/includes/css/tinymce.css",
// Drop lists for link/image/media/template dialogs
template_external_list_url : "lists/template_list.js",
external_link_list_url : "lists/link_list.js",
external_image_list_url : "lists/image_list.js",
media_external_list_url : "lists/media_list.js",
// Style formats
style_formats : [
{title : 'Google Maps', selector : 'iframe', classes : 'google-maps-embed'},
{title : 'Intro', selector : 'p', classes : 'intro'},
{title : 'News Image', selector : 'img', classes : 'news-image'}
],
});
In \tinymce\jscripts\tiny_mce\plugins\media\editor_plugin_src.js, I've fixed this issue by removing the "class" from the rootAttributes in line 12 and then minifying using jscompress.com and replaced the contents of the editor_plugin.js file (in the same folder).
Changed:
var rootAttributes = tinymce.explode('id,name,width,height,style,align,class,hspace,vspace,bgcolor,type')
To:
var rootAttributes = tinymce.explode('id,name,width,height,style,align,hspace,vspace,bgcolor,type')
It's still an issue in 3.5.8, and have submitted it as a bug.
Have you got the 'media' plugin enabled? I'm seeing a similar problem, and I wonder whether the media plugin is interfering with the normal operation of the editor on HTML elements. I tried creating a style_formats option to manipulate the iframe, but without any luck.
For those who experience the media plugin conflict, but still need the media plugin, you can set the following option during tinymce initialization to remove the conflict:
media_live_embeds: false
Tested in tinymce v4.6.1

jQuery mobile: json processing before mobile enhancements

I'm starting to develop a mobile app with jQuery Mobile. The idea is to build HTML static pages, and before showing them, call to the server to obtain the i18n text for the input labels and buttons. I mark the HTML elements that are susceptible to change the inner text with an special attribute: "data-i18n":
For a label:
<label data-i18n="login.username" for="loginPaciente.username">login.username</label>
For a button:
<button data-i18n="login.submit" type="submit" data-theme="a">login.submit</button>
I call to the server using JSON:
$('#pageLogin').live('pagebeforeshow',function(event, ui){
var action = "/MyServerApp/namespace1/mobile_Action_Login_configPage.action";
$.getJSON(action, function(data) {
var resources = data.i18n_resources;
var id, text;
var $scope = $('#pageLogin');
for (i=0; i<resources.length; i++){
id = resources[i].id;
text = resources[i].text;
$scope.find('[data-i18n="' + id + '"]').html(text);
}
});
});
This works perfectly with the labels, because JQM doesn't modify these HTML elements. The problem comes with the button, because JQM hides the button I've defined, and creates a new span to render the button. When I read the JSON result, I can find and change the button I've defined, but not the new span that JQM has created, so the text that appears on screen is the old one: "login.submit".
Is there any way to execute the JSON call before JQM changes the HTML code?
P.D.: The reason for not building the whole HTML page dynamically (including i18n texts) is that in the future, I want to encapsulate the web app with PhoneGap or a similar shell, and I want to distribute the HTML pages, CSS and scripts inside the application, and minimize the data traffic with the server.
Thanks in advance:
Carlos.
EDIT: invoking $scope.trigger('create') after changing the text doesn't solve the problem.
Finally I've found the solution to my problems by myself, catching the event "pagebeforecreate".
I invoke this function on each page I need to internationalize, passing the server action I need to call and the page id:
function utils_loadConfigPage(action, pageid){
$(document).bind("pagebeforecreate", function(){
var $page = $('#' + pageid);
var _action = action;
var paramCallback = "jsoncallback=?";
var concat = "?";
if (_action.indexOf("?")!=-1){
concat = "&";
}
_action += concat + paramCallback;
$.ajaxSetup({"async": false});
$.getJSON(_action, function(data){
utilis_doConfigPage(data, $page);
});
$.ajaxSetup({"async": true});
});
}
Note that I force to use synchronous calls to the server, in order to avoid the page mobile enhancing before the i18n texts were ready.
This is the function that is invoked in the json callback:
function utils_doConfigPage(data, $scope){
utils_seti18nTexts(data, $scope);
utils_setPlaceholders($scope);
}
This function finds all i18n elements and override their inner html with the translated texts:
function utils_seti18nTexts(data, $scope){
var resources = data.i18n_resources;
var id, text;
for (i=0; i<resources.length; i++){
id = resources[i].id;
text = resources[i].text;
$scope.find('[data-i18n="' + id + '"]').html(text);
}
}
This function overrides the placeholder texts for the inputs:
function utils_setPlaceholders($scope){
$scope.find('div[data-role="fieldcontain"].ui-hide-label').each(function(){
var textLabel = $(this).find('label').html();
$(this).find('.placeholder').attr('placeholder', textLabel);
});
}
And finally, this is the jsp that produces the i18n resources. I use Struts2, so the jsp is not invoked directly. I invoke an action and the jsp is only the view. The i18n resources are obtained using Struts2 capabilities:
<%# page contentType="application/json; charset=UTF-8" pageEncoding="UTF-8" %>
<%# taglib prefix="s" uri="/struts-tags"%>
<s:property value="jsoncallback" />({
"i18n_resources":
[
{
"id" : "MOBILE_APP_NAME",
"text" : "<s:text name="APP_NAME" />"
}
,{
"id" : "TITLE_LOGIN",
"text" : "<s:text name="TITLE_LOGIN" />"
}
,{
"id" : "LOGIN_USERNAME",
"text" : "<s:text name="LOGIN_USERNAME" />"
}
,{
"id" : "LOGIN_PASSWORD",
"text" : "<s:text name="LOGIN_PASSWORD" />"
}
,{
"id" : "BUTTON_OK",
"text" : "<s:text name="BUTTON_OK" />"
}
,{
"id" : "MOBILE_APP_FOOTER",
"text" : "<s:text name="MOBILE_APP_FOOTER" />"
}
]
})
I don't know if this is the best way to internationalize a JQM application. Any suggestion will be apreciated.
You can just change the text of the <span> element with the ui-btn-text class:
$scope.find('[data-i18n="' + id + '"]').find('.ui-btn-text').html(text);
Or if you aren't sure if the element will have been initialized by jQuery Mobile you can check for the existence of the ui-btn-class first:
var $btn_text = $scope.find('[data-i18n="' + id + '"]').find('.ui-btn-text');
if ($btn_text.length > 0) {
$btn_text.html(text);
} else {
$scope.find('[data-i18n="' + id + '"]').html(text);
}