Imperavi Redactor 9 removes &nbsp ; character - special-characters

How to disable the Redactor editor auto remove &nbsp ; ? Please help.

In new version U may set "cleanSpaces" option to "false" for disabling of auto remove.
$('#redactor').redactor({ cleanSpaces: false });

The text and code you are seeing will be different between all the browsers and it's how contenteditable fields work. For example, some browsers insert UTF-8 characters for spaces some &nbsp.
RedactorJS don't gives methods to normalize the text, so you can parse the text manually. Check this:
var html = $('#redactor').redactor('get');
var sanitizeHtml = html.replace(/\u00a0/g, ' ').replace(/ /g, ' ');

to fix clean
open redactor.js
find
syncClean: function(html)
{
if (!this.opts.fullpage) html = this.cleanStripTags(html);
html = $.trim(html);
// removeplaceholder
html = this.placeholderRemoveFromCode(html);
// remove space
html = html.replace(/​/gi, '');
html = html.replace(/​/gi, '');
// html = html.replace(/ /gi, ' '); // COMMENT THIS!
...
}
comment replacing string
profit! :)

Related

more than one caption with featherlight?

i am using featherlight.js for image galleries and used this code for captions:
$.featherlightGallery.prototype.afterContent = function() {
var caption = this.$currentTarget.find('img').attr('alt');
this.$instance.find('.caption').remove();
$('<div class="caption">').text(caption).appendTo(this.$instance.find('.featherlight-content'));
};
now a client wants to add a second caption which contains only copyright-information on the right side of gallery-images. is it possible to have two captions, one named .caption and the second maybe .copyright?
I already tried with "data-caption=" and a simple copy of the above js-initial but it failed.
any ideas?
thank you in advance and merry christmas!
You could use a data attribute.
$.featherlightGallery.prototype.afterContent = function() {
var caption = this.$currentTarget.find('img').attr('alt');
this.$instance.find('.caption').remove();
$('<div class="caption">').text(caption).appendTo(this.$instance.find('.featherlight-content'));
var copyright = this.$currentTarget.find('img').data('copyright');
this.$instance.find('.copyright').remove();
$('<div class="copyright">').text(copyright).appendTo(this.$instance.find('.featherlight-content'));
};
Then in your markup add
<img src="..." alt="my caption text" data-copyright="my copyright text">
and in your css
.copyright {
float: right;
}
or something to suit.
If you need it to be conditional you can check for the defined-ness and/or length of the data-copyright attribute.

TinyMCE: wordcount plugin is not counting special characters as word

I have added the plugin wordcount to count the number of words entered in my TinyMCE texteditor.
plugins: "wordcount",
wordcount_cleanregex: /[.(),;:!?%#$?\x27\x22_+=\\/\-]*/g
It is counting letters and numbers but when I am giving a special character , it is not counting them.
for e.g ----
Hi I am 18 year old (for this it is giving me count 6)
Hi I am ## year old (for this it is giving me count 5)
Any idea what I need to do. I tried to remove:
%#$ from wordcount_cleanregex , but it didn't work.
Your issue is not with the wordcount_cleanregex setting but rather with the wordcount_countregex setting:
https://www.tinymce.com/docs/plugins/wordcount/#wordcount_countregex
If you look at the default one you will see why its skipping the characters that it is. Here is the exact regex:
https://regex101.com/r/wL4fL1/1
If you tweak that regex you can get it to count your ## as a word.
Note: There is some core cleaning that is done within the wordcount plugin that is done regardless of your configuration settings. In TinyMCE 4.4.1 it looks like this:
if (tx) {
tx = tx.replace(/\.\.\./g, ' '); // convert ellipses to spaces
tx = tx.replace(/<.[^<>]*?>/g, ' ').replace(/ | /gi, ' '); // remove html tags and space chars
// deal with html entities
tx = tx.replace(/(\w+)(&#?[a-z0-9]+;)+(\w+)/i, "$1$3").replace(/&.+?;/g, ' ');
tx = tx.replace(cleanre, ''); // remove numbers and punctuation
var wordArray = tx.match(countre);
if (wordArray) {
tc = wordArray.length;
}
}
...so some core things are still stripped from your content regardless of what you put in the wordcount_cleanregex and wordcount_countregex. If you want to change this core behavior you will need to modify the plugin's source code.
here is my wordcount plugin which I am adding externally , The function getCount returns the number of words perfectly when I run this function seprately on my .aspx page as javascript function, but when I am running under this plugin it is only counting letters (it is not counting any number/special characters)
tinymce.PluginManager.add('wordcount', function(editor) {
function update() {
editor.theme.panel.find('#wordcount').text(['Words: {0}', getCount()]);
}
editor.on('init', function() {
var statusbar = editor.theme.panel && editor.theme.panel.find('#statusbar')[0];
if (statusbar) {
tinymce.util.Delay.setEditorTimeout(editor, function() {
statusbar.insert({
type: 'label',
name: 'wordcount',
text: ['Words: {0}', getCount()],
classes: 'wordcount',
disabled: editor.settings.readonly
}, 0);
editor.on('setcontent beforeaddundo', update);
editor.on('keyup', function(e) {
if (e.keyCode == 32) {
update();
}
});
}, 0);
}
});
getCount = function () {
var body = editor.getBody().innerHTML;
text1 = body.replace(/<[^>]+>/g, '');
s = text1.replace(/ /g, ' ');
s = s.replace(/(^\s*)|(\s*$)/gi, "");//exclude start and end white-space
s = s.replace(/[ ]{2,}/gi, " ");//2 or more space to 1
s = s.replace(/\n /, "\n"); // exclude newline with a start spacing
return s.split(' ').length;
};
});

TinyMCE - applying a style over bullets and multiple paragraphs applies the style to each bullet & para - how do I avoid?

I'm trying to use the theme_advanced_styles command within TinyMCE to add classes to selections of text within the TinyMCE editor. The problem is that if the paragraph contains bullets, then the style is applied throughout them (as well as to each individual paragraph).
What I want is just for the entire selection I made to have the style class added to the start of it. Ie if my style class is 'expandCollapse' I want:
<p class="expandCollapse">some content... some content... some content... some content... som content... some content... some content...
<ul>
<li>asdsadsadsadsasda</li>
<li>asdsadsa</li>
<li>sada</li>
</ul>
asome content... some content... some content... some content... some content... some content... some content... some content... </p>
But what I get is:
<p class="expandCollapse">some content... some content... some content... some content... some content... some content... some content...
<ul>
<li class="expandCollapse">asdsadsadsadsasda</li>
<li class="expandCollapse">asdsadsa</li>
<li class="expandCollapse">sada</li>
</ul>
</p>
<p class="expandCollapse">asome content... some content... some content... some content... some content... some content... some content... some content... </p>
Any ideas anyone?!
So I had to answer my own question as I needed an answer very quickly. It appears the behaviour I was experiencing is intentional? and certainly not something that has been removed in the very latest versions of TinyMCE (both 3.x and 4.x after testing).
With this in mind I ended up having to make a plugin to do what I wanted.
I borrowed a huge amount of code by Peter Wilson, from a post he made here: http://www.tinymce.com/forum/viewtopic.php?id=20319 So thanks very much for this Peter!
I ended up slightly changing the rules from my original question in that my solution adds an outer wrapping div around all the content I want to select. This method also allowed me to reliably then grab the required areas of html with jQuery in my front-end site.
My version of Peter's code is just very slightly modified from the original in order to add a class to the DIV, rename it, use a different button etc.
The plugin works perfectly and allows for a div to be created wrapping any amount of content within TinyMCE. The divs inserted have the class name I need also applied to it.
Add 'customDiv' to your plugin AND button bar for it to appear.
(function() {
tinymce.create("tinymce.plugins.Div", {
init : function(editor, url) {
editor.addCommand("mceWrapDiv", function() {
var ed = this, s = ed.selection, dom = ed.dom, sb, eb, n, div, bm, r, i;
// Get start/end block
sb = dom.getParent(s.getStart(), dom.isBlock);
eb = dom.getParent(s.getEnd(), dom.isBlock);
// If the document is empty then there can't be anything to wrap.
if (!sb && !eb) {
return;
}
// If empty paragraph node then do not use bookmark
if (sb != eb || sb.childNodes.length > 1 || (sb.childNodes.length == 1 && sb.firstChild.nodeName != 'BR'))
bm = s.getBookmark();
// Move selected block elements into a new DIV - positioned before the first block
tinymce.each(s.getSelectedBlocks(s.getStart(), s.getEnd()), function(e) {
// If this is the first node then we need to create the DIV along with the following dummy paragraph.
if (!div) {
div = dom.create('div',{'class' : 'expandCollapse'});
e.parentNode.insertBefore(div, e);
// Insert an empty dummy paragraph to prevent people getting stuck in a nested block. The dummy has a '-'
// in it to prevent it being removed as an empty paragraph.
var dummy = dom.create('p');
e.parentNode.insertBefore(dummy, e);
//dummy.innerHTML = '-';
}
// Move this node to the new DIV
if (div!=null)
div.appendChild(dom.remove(e));
});
if (!bm) {
// Move caret inside empty block element
if (!tinymce.isIE) {
r = ed.getDoc().createRange();
r.setStart(sb, 0);
r.setEnd(sb, 0);
s.setRng(r);
} else {
s.select(sb);
s.collapse(1);
}
} else
s.moveToBookmark(bm);
});
editor.addButton("customDiv", {
//title: "<div>",
image: url + '/customdiv.gif',
cmd: "mceWrapDiv",
title : 'Wrap content in expand/collapse element'
});
}
});
tinymce.PluginManager.add("customDiv", tinymce.plugins.Div);
})();

The proper use of jsoup

I recently began to study how to use jsoup
Document doc = Jsoup.parse(responseString);
 Elements pngs = doc.select ("div.kk2");
To using jsoup made ​​a web page to put pictures of example I
<div class="kk2" id="12" style="border:2px solid #FFFF00; top:-1px; left:-203px; height:151px; width:200px"> <img src = "http:// kk.org / t / ea / ff.jpg "alt =" text "style =" fff "/> </ div>
After screening of the example
for(Element png : pngs){
sff2.append(png.attr("abs:href")).append(" ").append(png.text()).append("\n");
}
To obtain this value
init ~ kk.org ~ t / ea / ff.jpg ~ text
If I simply just want to get this value
http://kk.org/t/ea/ff.jpg
How can I do it??
I try to use
sff2.append (png.attr ("alt")). append (""). append (png.text ()). append ("\ n");
But without success
If I understand correctly, you just want to get the address of the image?
If so, this should do it.
Elements div = doc.select("div[class=kk2]");
Elements pngs = div.select("img");
for (Element png : pngs) {
String src = png.attr("abs:src");
src = src.replace(" ", ""); // Remove spaces
System.out.println(src);
}

How to highlight friends name in Facebook status update box (textarea)?

In Facebook status update box, when I type # and start typing and choose a name, say Steven Gerrard, from the friends list suggested by fb, my friend's name is highlighted in the textarea like this
I checked with Firebug and there's only
a div.highlighter which contains sort of formated text (Steven Gerrard is within b tags)
a textarea inside a div.uiTypeahead. Nothing interesting i could find
and a hidden input, that contains the actual text that will be posted: #[100001915747xxx:Steven Gerrard] is awesome
What is the secret trick behind this? Normal rich text editors like ckeditor usually have an iframe to display the text and an actual textarea to keep the original content. But in this case, I do not see anything. Someone please shed some lights?
I would like to make something like this but have no clue where to begin. Also, if I would like to display a small thumb next to my friend's name, is it possible at all?
Here is how it works:
You superpose the textarea (in front) and a div (behind) that will have the same size, and the same font size.
The textarea must have a transparent background, so we can see its text, but also see the div behind it.
The div behind it will have a white text and white background, so the text it contains will be transparent.
You set a hook on the textarea's keyup, and you process the text it contains as HTML: replace the line breaks by <br/>, replace the double spaces by , and also replace all the words that you want to highlight by a version surrounded by <span style="background-color: #D8DFEA;"></span>.
Since you can see the highlight div behind the textarea, and that the text the highlight div contains is perfectly aligned with the text in the textarea, and that the <span> is visible, you will have the illusion that the text in the textarea is highlighted.
I've written a quick example based on jquery so you can try it yourself, without too much code to analyze.
Here is a sample code you can just copy-paste-save and try:
This sample code will highlight a defined set of word, here: "hello" and "world".
I'll let you adapt it the way you want.
<html>
<head>
<title></title>
<!-- Load jQuery -->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
<!-- The javascript xontaining the plugin and the code to init the plugin -->
<script type="text/javascript">
$(function() {
// let's init the plugin, that we called "highlight".
// We will highlight the words "hello" and "world",
// and set the input area to a widht and height of 500 and 250 respectively.
$("#container").highlight({
words: ["hello","world"],
width: 500,
height: 250
});
});
// the plugin that would do the trick
(function($){
$.fn.extend({
highlight: function() {
// the main class
var pluginClass = function() {};
// init the class
// Bootloader
pluginClass.prototype.__init = function (element) {
try {
this.element = element;
} catch (err) {
this.error(err);
}
};
// centralized error handler
pluginClass.prototype.error = function (e) {
// manage error and exceptions here
//console.info("error!",e);
};
// Centralized routing function
pluginClass.prototype.execute = function (fn, options) {
try {
options = $.extend({},options);
if (typeof(this[fn]) == "function") {
var output = this[fn].apply(this, [options]);
} else {
this.error("undefined_function");
}
} catch (err) {
this.error(err);
}
};
// **********************
// Plugin Class starts here
// **********************
// init the component
pluginClass.prototype.init = function (options) {
try {
// the element's reference ( $("#container") ) is stored into "this.element"
var scope = this;
this.options = options;
// just find the different elements we'll need
this.highlighterContainer = this.element.find('#highlighterContainer');
this.inputContainer = this.element.find('#inputContainer');
this.textarea = this.inputContainer.find('textarea');
this.highlighter = this.highlighterContainer.find('#highlighter');
// apply the css
this.element.css('position','relative');
// place both the highlight container and the textarea container
// on the same coordonate to superpose them.
this.highlighterContainer.css({
'position': 'absolute',
'left': '0',
'top': '0',
'border': '1px dashed #ff0000',
'width': this.options.width,
'height': this.options.height,
'cursor': 'text'
});
this.inputContainer.css({
'position': 'absolute',
'left': '0',
'top': '0',
'border': '1px solid #000000'
});
// now let's make sure the highlit div and the textarea will superpose,
// by applying the same font size and stuffs.
// the highlighter must have a white text so it will be invisible
this.highlighter.css({
'padding': '7px',
'color': '#eeeeee',
'background-color': '#ffffff',
'margin': '0px',
'font-size': '11px',
'font-family': '"lucida grande",tahoma,verdana,arial,sans-serif'
});
// the textarea must have a transparent background so we can see the highlight div behind it
this.textarea.css({
'background-color': 'transparent',
'padding': '5px',
'margin': '0px',
'font-size': '11px',
'width': this.options.width,
'height': this.options.height,
'font-family': '"lucida grande",tahoma,verdana,arial,sans-serif'
});
// apply the hooks
this.highlighterContainer.bind('click', function() {
scope.textarea.focus();
});
this.textarea.bind('keyup', function() {
// when we type in the textarea,
// we want the text to be processed and re-injected into the div behind it.
scope.applyText($(this).val());
});
} catch (err) {
this.error(err);
}
return true;
};
pluginClass.prototype.applyText = function (text) {
try {
var scope = this;
// parse the text:
// replace all the line braks by <br/>, and all the double spaces by the html version
text = this.replaceAll(text,'\n','<br/>');
text = this.replaceAll(text,' ',' ');
// replace the words by a highlighted version of the words
for (var i=0;i<this.options.words.length;i++) {
text = this.replaceAll(text,this.options.words[i],'<span style="background-color: #D8DFEA;">'+this.options.words[i]+'</span>');
}
// re-inject the processed text into the div
this.highlighter.html(text);
} catch (err) {
this.error(err);
}
return true;
};
// "replace all" function
pluginClass.prototype.replaceAll = function(txt, replace, with_this) {
return txt.replace(new RegExp(replace, 'g'),with_this);
}
// don't worry about this part, it's just the required code for the plugin to hadle the methods and stuffs. Not relevant here.
//**********************
// process
var fn;
var options;
if (arguments.length == 0) {
fn = "init";
options = {};
} else if (arguments.length == 1 && typeof(arguments[0]) == 'object') {
fn = "init";
options = $.extend({},arguments[0]);
} else {
fn = arguments[0];
options = $.extend({},arguments[1]);
}
$.each(this, function(idx, item) {
// if the component is not yet existing, create it.
if ($(item).data('highlightPlugin') == null) {
$(item).data('highlightPlugin', new pluginClass());
$(item).data('highlightPlugin').__init($(item));
}
$(item).data('highlightPlugin').execute(fn, options);
});
return this;
}
});
})(jQuery);
</script>
</head>
<body>
<div id="container">
<div id="highlighterContainer">
<div id="highlighter">
</div>
</div>
<div id="inputContainer">
<textarea cols="30" rows="10">
</textarea>
</div>
</div>
</body>
</html>
Let me know if you have any question or if you need help with this code.
After reviewing the way of Facebook do this, I see that the text shown on the screen is:
<span class="highlighterContent"><b>Ws Dev</b> is good</span>
That span is put in a table (with lots of div container), which is style accordingly.
So I think this is the process:
When you type in the box, Facebook does have a textarea that capture what you type, but use javascript to show the typed HTML content in a table.
When you submit, the formatted content in a hidden input (that you already spot in the question) get submitted. It's like "#[100001915747xxx:Steven Gerrard] is awesome".
When the formatted message submit, it is saved to the database. Everytime the page get loaded, from the saved message the HTML is composed and return.
To get the similar effect, you can use any jQuery autocomplete plugin.