I am trying to work with a simple WYSIWYG editor. JSLint is saying it has "Bad escaping of EOL". Since I am new to javascript I am having a hard time figuring out what it means, since I am working with code found online. Can anyone tell me please what I should be doing instead of ending the line with a slash?
Here is the code in question: http://jsfiddle.net/spadez/KSA5e/9/
/*
* WYSIWYG EDITOR BASED ON JQUERY RTE
*/
// define the rte light plugin
(function ($) {
if (typeof $.fn.rte === "undefined") {
var defaults = {
content_css_url: "rte.css",
dot_net_button_class: null,
max_height: 350
};
$.fn.rte = function (options) {
$.fn.rte.html = function (iframe) {
return iframe.contentWindow.document.getElementsByTagName("body")[0].innerHTML;
};
// build main options before element iteration
var opts = $.extend(defaults, options);
// iterate and construct the RTEs
return this.each(function () {
var textarea = $(this);
var iframe;
var element_id = textarea.attr("id");
// enable design mode
function enableDesignMode() {
var content = textarea.val();
// Mozilla needs this to display caret
if ($.trim(content) === '') {
content = '<br />';
}
// already created? show/hide
if (iframe) {
console.log("already created");
textarea.hide();
$(iframe).contents().find("body").html(content);
$(iframe).show();
$("#toolbar-" + element_id).remove();
textarea.before(toolbar());
return true;
}
// for compatibility reasons, need to be created this way
iframe = document.createElement("iframe");
iframe.frameBorder = 0;
iframe.frameMargin = 0;
iframe.framePadding = 0;
iframe.height = 200;
if (textarea.attr('class')) iframe.className = textarea.attr('class');
if (textarea.attr('id')) iframe.id = element_id;
if (textarea.attr('name')) iframe.title = textarea.attr('name');
textarea.after(iframe);
var css = "";
if (opts.content_css_url) {
css = "<link type='text/css' rel='stylesheet' href='" + opts.content_css_url + "' />";
}
var doc = "<html><head>" + css + "</head><body class='frameBody'>" + content + "</body></html>";
tryEnableDesignMode(doc, function () {
$("#toolbar-" + element_id).remove();
textarea.before(toolbar());
// hide textarea
textarea.hide();
});
}
function tryEnableDesignMode(doc, callback) {
if (!iframe) {
return false;
}
try {
iframe.contentWindow.document.open();
iframe.contentWindow.document.write(doc);
iframe.contentWindow.document.close();
} catch (error) {
console.log(error);
}
if (document.contentEditable) {
iframe.contentWindow.document.designMode = "On";
callback();
return true;
} else if (document.designMode !== null) {
try {
iframe.contentWindow.document.designMode = "on";
callback();
return true;
} catch (error) {
console.log(error);
}
}
setTimeout(function () {
tryEnableDesignMode(doc, callback);
}, 500);
return false;
}
function disableDesignMode(submit) {
var content = $(iframe).contents().find("body").html();
if ($(iframe).is(":visible")) {
textarea.val(content);
}
if (submit !== true) {
textarea.show();
$(iframe).hide();
}
}
// create toolbar and bind events to it's elements
function toolbar() {
var tb = $("<div class='rte-toolbar' id='toolbar-" + element_id + "'><div>\
<p>\
<a href='#' class='bold'>Bold</a>\
<a href='#' class='italic'>Italic</a>\
<a href='#' class='unorderedlist'>List</a>\
</p></div></div>");
$('.bold', tb).click(function () {
formatText('bold');
return false;
});
$('.italic', tb).click(function () {
formatText('italic');
return false;
});
$('.unorderedlist', tb).click(function () {
formatText('insertunorderedlist');
return false;
});
// .NET compatability
if (opts.dot_net_button_class) {
var dot_net_button = $(iframe).parents('form').find(opts.dot_net_button_class);
dot_net_button.click(function () {
disableDesignMode(true);
});
// Regular forms
} else {
$(iframe).parents('form').submit(function () {
disableDesignMode(true);
});
}
var iframeDoc = $(iframe.contentWindow.document);
var select = $('select', tb)[0];
iframeDoc.mouseup(function () {
setSelectedType(getSelectionElement(), select);
return true;
});
iframeDoc.keyup(function () {
setSelectedType(getSelectionElement(), select);
var body = $('body', iframeDoc);
if (body.scrollTop() > 0) {
var iframe_height = parseInt(iframe.style['height']);
if (isNaN(iframe_height)) iframe_height = 0;
var h = Math.min(opts.max_height, iframe_height + body.scrollTop()) + 'px';
iframe.style['height'] = h;
}
return true;
});
return tb;
}
function formatText(command, option) {
iframe.contentWindow.focus();
try {
iframe.contentWindow.document.execCommand(command, false, option);
} catch (e) {
//console.log(e)
}
iframe.contentWindow.focus();
}
function setSelectedType(node, select) {
while (node.parentNode) {
var nName = node.nodeName.toLowerCase();
for (var i = 0; i < select.options.length; i++) {
if (nName == select.options[i].value) {
select.selectedIndex = i;
return true;
}
}
node = node.parentNode;
}
select.selectedIndex = 0;
return true;
}
function getSelectionElement() {
if (iframe.contentWindow.document.selection) {
// IE selections
selection = iframe.contentWindow.document.selection;
range = selection.createRange();
try {
node = range.parentElement();
} catch (e) {
return false;
}
} else {
// Mozilla selections
try {
selection = iframe.contentWindow.getSelection();
range = selection.getRangeAt(0);
} catch (e) {
return false;
}
node = range.commonAncestorContainer;
}
return node;
}
// enable design mode now
enableDesignMode();
}); //return this.each
}; // rte
} // if
$(".rte-zone").rte({});
})(jQuery);
EDIT: For bonus marks there are also two other errors which I haven't been able to squish -
Missing radix parameter
Height is better written in dot notation
JS didn't support end-of-line escaping with \ until ES5 - you can use multiple strings with a + operator instead, i.e.
"string 1" +
"string 2" +
"string 3"
Re: your other questions:
Use parseInt(n, 10) to force base (aka radix) 10, i.e. decimal
Use iframe.style.height instead of iframe.style['height']
You have two options:
1) activate multistr: true as suggested by #csharpfolk. (You can do it at file level by adding /*jshint multistr: true */ or add it in your linter config file (.jshintrc, .eslintrc, etc.)).
2) Replace your multistring as suggested by #Altinak or use an array and join:
["string 1",
"string 2",
"string 3",
].join('')
Related
i have this javascript that I called cookiebar.js, it shows a sticky bar message for cookies, (source code)
(function (context) {
"use strict";
var win = context,
doc = win.document;
var global_instance_name = "cbinstance";
function contentLoaded(win, fn) {
var done = false,
top = true,
doc = win.document,
root = doc.documentElement,
add = doc.addEventListener ? "addEventListener" : "attachEvent",
rem = doc.addEventListener ? "removeEventListener" : "detachEvent",
pre = doc.addEventListener ? "" : "on",
init = function (e) {
if (e.type == "readystatechange" && doc.readyState != "complete") return;
(e.type == "load" ? win : doc)[rem](pre + e.type, init, false);
if (!done && (done = true)) fn.call(win, e.type || e);
},
poll = function () {
try {
root.doScroll("left");
} catch (e) {
setTimeout(poll, 50);
return;
}
init("poll");
};
if (doc.readyState == "complete") fn.call(win, "lazy");
else {
if (doc.createEventObject && root.doScroll) {
try {
top = !win.frameElement;
} catch (e) {}
if (top) poll();
}
doc[add](pre + "DOMContentLoaded", init, false);
doc[add](pre + "readystatechange", init, false);
win[add](pre + "load", init, false);
}
}
var Cookies = {
get: function (key) {
return decodeURIComponent(doc.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
},
set: function (key, val, end, path, domain, secure) {
if (!key || /^(?:expires|max\-age|path|domain|secure)$/i.test(key)) {
return false;
}
var expires = "";
if (end) {
switch (end.constructor) {
case Number:
expires = end === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + end;
break;
case String:
expires = "; expires=" + end;
break;
case Date:
expires = "; expires=" + end.toUTCString();
break;
}
}
doc.cookie = encodeURIComponent(key) + "=" + encodeURIComponent(val) + expires + (domain ? "; domain=" + domain : "") + (path ? "; path=" + path : "") + (secure ? "; secure" : "");
return true;
},
has: function (key) {
return new RegExp("(?:^|;\\s*)" + encodeURIComponent(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=").test(doc.cookie);
},
remove: function (key, path, domain) {
if (!key || !this.has(key)) {
return false;
}
doc.cookie = encodeURIComponent(key) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (domain ? "; domain=" + domain : "") + (path ? "; path=" + path : "");
return true;
},
};
var Utils = {
merge: function () {
var obj = {},
i = 0,
al = arguments.length,
key;
if (0 === al) {
return obj;
}
for (; i < al; i++) {
for (key in arguments[i]) {
if (Object.prototype.hasOwnProperty.call(arguments[i], key)) {
obj[key] = arguments[i][key];
}
}
}
return obj;
},
str2bool: function (str) {
str = "" + str;
switch (str.toLowerCase()) {
case "false":
case "no":
case "0":
case "":
return false;
default:
return true;
}
},
fade_in: function (el) {
if (el.style.opacity < 1) {
el.style.opacity = (parseFloat(el.style.opacity) + 0.05).toFixed(2);
win.setTimeout(function () {
Utils.fade_in(el);
}, 50);
}
},
get_data_attribs: function (script) {
var data = {};
if (Object.prototype.hasOwnProperty.call(script, "dataset")) {
data = script.dataset;
} else {
var attribs = script.attributes;
var key;
for (key in attribs) {
if (Object.prototype.hasOwnProperty.call(attribs, key)) {
var attr = attribs[key];
if (/^data-/.test(attr.name)) {
var camelized = Utils.camelize(attr.name.substr(5));
data[camelized] = attr.value;
}
}
}
}
return data;
},
normalize_keys: function (options_object) {
var camelized = {};
for (var key in options_object) {
if (Object.prototype.hasOwnProperty.call(options_object, key)) {
var camelized_key = Utils.camelize(key);
camelized[camelized_key] = options_object[camelized_key] ? options_object[camelized_key] : options_object[key];
}
}
return camelized;
},
camelize: function (str) {
var separator = "-",
match = str.indexOf(separator);
while (match != -1) {
var last = match === str.length - 1,
next = last ? "" : str[match + 1],
upnext = next.toUpperCase(),
sep_substr = last ? separator : separator + next;
str = str.replace(sep_substr, upnext);
match = str.indexOf(separator);
}
return str;
},
find_script_by_id: function (id) {
var scripts = doc.getElementsByTagName("script");
for (var i = 0, l = scripts.length; i < l; i++) {
if (id === scripts[i].id) {
return scripts[i];
}
}
return null;
},
};
var script_el_invoker = Utils.find_script_by_id("cookiebanner");
var Cookiebanner = (context.Cookiebanner = function (opts) {
this.init(opts);
});
Cookiebanner.prototype = {
cookiejar: Cookies,
init: function (opts) {
this.inserted = false;
this.closed = false;
this.test_mode = false;
var default_text = "This site uses cookies.";
var default_link = "Detail";
this.default_options = {
cookie: "cookiebanner-accepted",
closeText: "✖",
cookiePath: "/",
debug: false,
expires: Infinity,
zindex: 255,
mask: false,
maskOpacity: 0.5,
maskBackground: "#000",
height: "auto",
minHeight: "21px",
bg: "#000",
fg: "#ddd",
link: "#aaa",
position: "bottom",
message: default_text,
linkmsg: default_link,
moreinfo: "http://www.examplesite123.com/cookie-policy/",
effect: null,
fontSize: "14px",
fontFamily: "arial, sans-serif",
instance: global_instance_name,
textAlign: "center",
acceptOnScroll: true,
};
this.options = this.default_options;
this.script_el = script_el_invoker;
if (this.script_el) {
var data_options = Utils.get_data_attribs(this.script_el);
this.options = Utils.merge(this.options, data_options);
}
if (opts) {
opts = Utils.normalize_keys(opts);
this.options = Utils.merge(this.options, opts);
}
global_instance_name = this.options.instance;
this.options.zindex = parseInt(this.options.zindex, 10);
this.options.mask = Utils.str2bool(this.options.mask);
if ("string" === typeof this.options.expires) {
if ("function" === typeof context[this.options.expires]) {
this.options.expires = context[this.options.expires];
}
}
if ("function" === typeof this.options.expires) {
this.options.expires = this.options.expires();
}
if (this.script_el) {
this.run();
}
},
log: function () {
if ("undefined" !== typeof console) {
console.log.apply(console, arguments);
}
},
run: function () {
if (!this.agreed()) {
var self = this;
contentLoaded(win, function () {
self.insert();
});
}
},
build_viewport_mask: function () {
var mask = null;
if (true === this.options.mask) {
var mask_opacity = this.options.maskOpacity;
var bg = this.options.maskBackground;
var mask_markup =
'<div id="cookiebanner-mask" style="' +
"position:fixed;top:0;left:0;width:100%;height:100%;" +
"background:" +
bg +
";zoom:1;filter:alpha(opacity=" +
mask_opacity * 100 +
");opacity:" +
mask_opacity +
";" +
"z-index:" +
this.options.zindex +
';"></div>';
var el = doc.createElement("div");
el.innerHTML = mask_markup;
mask = el.firstChild;
}
return mask;
},
agree: function () {
this.cookiejar.set(this.options.cookie, 1, this.options.expires, this.options.cookiePath);
return true;
},
agreed: function () {
return this.cookiejar.has(this.options.cookie);
},
close: function () {
if (this.inserted) {
if (!this.closed) {
if (this.element) {
this.element.parentNode.removeChild(this.element);
}
if (this.element_mask) {
this.element_mask.parentNode.removeChild(this.element_mask);
}
this.closed = true;
}
}
return this.closed;
},
agree_and_close: function () {
this.agree();
return this.close();
},
cleanup: function () {
this.close();
return this.unload();
},
unload: function () {
if (this.script_el) {
this.script_el.parentNode.removeChild(this.script_el);
}
context[global_instance_name] = undefined;
return true;
},
insert: function () {
this.element_mask = this.build_viewport_mask();
var zidx = this.options.zindex;
if (this.element_mask) {
zidx += 1;
}
var el = doc.createElement("div");
el.className = "cookiebanner";
el.style.position = "fixed";
el.style.left = 0;
el.style.right = 0;
el.style.height = this.options.height;
el.style.minHeight = this.options.minHeight;
el.style.zIndex = zidx;
el.style.background = this.options.bg;
el.style.color = this.options.fg;
el.style.lineHeight = el.style.minHeight;
el.style.padding = "5px 16px";
el.style.fontFamily = this.options.fontFamily;
el.style.fontSize = this.options.fontSize;
el.style.textAlign = this.options.textAlign;
if ("top" === this.options.position) {
el.style.top = 0;
} else {
el.style.bottom = 0;
}
el.innerHTML = '<div class="cookiebanner-close" style="float:right;padding-left:5px;">' + this.options.closeText + "</div>" + "<span>" + this.options.message + " <a>" + this.options.linkmsg + "</a></span>";
this.element = el;
var el_a = el.getElementsByTagName("a")[0];
el_a.href = this.options.moreinfo;
el_a.target = "_blank";
el_a.style.textDecoration = "none";
el_a.style.color = this.options.link;
var el_x = el.getElementsByTagName("div")[0];
el_x.style.cursor = "pointer";
function on(el, ev, fn) {
var add = el.addEventListener ? "addEventListener" : "attachEvent",
pre = el.addEventListener ? "" : "on";
el[add](pre + ev, fn, false);
}
var self = this;
on(el_x, "click", function () {
self.agree_and_close();
});
if (this.element_mask) {
on(this.element_mask, "click", function () {
self.agree_and_close();
});
doc.body.appendChild(this.element_mask);
}
if (this.options.acceptOnScroll) {
on(window, "scroll", function () {
self.agree_and_close();
});
}
doc.body.appendChild(this.element);
this.inserted = true;
if ("fade" === this.options.effect) {
this.element.style.opacity = 0;
Utils.fade_in(this.element);
} else {
this.element.style.opacity = 1;
}
},
};
if (script_el_invoker) {
if (!context[global_instance_name]) {
context[global_instance_name] = new Cookiebanner();
}
}
})(window);
I load it in this way in functions.php in Wordpress:
function wpb_hook_javascript() {
?>
<script defer type="text/javascript" id="cookiebanner" src="https://www.examplesite123.com/cookiebar.js"></script>
<?php
}
add_action('wp_head', 'wpb_hook_javascript');
It works fine.
Now i duplicate the same javascript code and i called it stickybar.js. I add some modifications, also change class with name "stickybar":
The code of the stickybar.js is here (i pasted it in jsfiddle because there is too much text for stackoverflow)
Then i show this second bar (stickybar.js) only on mobile device and after 8 second with this CSS:
.stickybar { display: none; }
#media only screen and (max-device-width:480px) {
.stickybar {
display: block;
animation: cssAnimation 0s 8s forwards;
visibility: hidden;
}
#keyframes cssAnimation {
to { visibility: visible; }
}
}
I load it in Wordpress with this code in functions.php:
function wpb_hook_javascript() {
?>
<script defer type="text/javascript" id="cookiebanner" src="https://www.examplesite123.com/stickybar.js"></script>
<?php
}
add_action('wp_head', 'wpb_hook_javascript');
It works fine.
If i load one by one of this codes, they work fine.
The problem is that when i load the two scripts together in this way in functions.php, only the first works:
function wpb_hook_javascript() {
?>
<script defer type="text/javascript" id="cookiebanner" src="https://www.examplesite123.com/cookiebar.js"></script>
<script defer type="text/javascript" id="cookiebanner" src="https://www.examplesite123.com/stickybar.js"></script>
<?php
}
add_action('wp_head', 'wpb_hook_javascript');
How can i load the two scripts together?
The comment thread on this question is semantically correct, you can only have one instance of each html id attribute, they must be unique, and your find_script_by_id methods are both searching for the same thing.
However, you're doing what's generally called "baking in" the scripts into your header which is at best, a faux pas, at least as far as WordPress is concerned. Properly Enqueueing Scripts (and styles) is very easy in WordPress, and your future self, web clients, and other people who look at your code will thank you for doing it.
It's not unlike how you're "baking in" the scripts now:
function wpb_hook_javascript() {
?>
<script defer type="text/javascript" id="cookiebanner" src="https://www.examplesite123.com/cookiebar.js"></script>
<script defer type="text/javascript" id="cookiebanner" src="https://www.examplesite123.com/stickybar.js"></script>
<?php
}
add_action('wp_head', 'wpb_hook_javascript');
But with a few things changed:
function enqueue_my_scripts(){
wp_enqueue_script( 'cookie-bar', 'https://www.examplesite123.com/cookiebar.js', array(), '1.0', true );
wp_enqueue_script( 'sticky-bar', 'https://www.examplesite123.com/stickybar.js', array(), '1.0', true );
}
add_action( 'wp_enqueue_scripts', 'enqueue_my_scripts' );
Namely, it uses the wp_enqueue_script() function on the wp_enqueue_scripts hook. This lets you defer the script to the footer, load in the header, add version numbers to prevent caching issues, add dependencies, allows you to dynamically add/remove them programatically,gives them unique ID's based on the handle, and much more. (You do still need to update your find_script_by_id functions to use these new handles instead cookie-bar, sticky-bar, change the global_instance_name, etc. (more on that in a second)
With that said, if the .js files are on your server, you'll want to use site_url(), plugins_url(), get_stylesheet_directory_uri(), or similar functions to grab the URL of the file instead of typing it out. If you're using a remote resource, don't worry about it, but if they're on you're site, you should swap out the baked in version for that so you don't have issues if you ever move your site, and it allows you easier methods to edit the version to prevent caching problems if you change them.
Back to your variables, you may also want to replace your find_script_by_id type functions with document.currentScript instead, to allow them to be more abstract and not rely on typo/duplicate prone element IDs, and instead reference the currently running <script> tag.
How I can update function _handlePaste() inside function paste?
$.FE.MODULES.paste = function(editor) {
var clipboard_html;
function _handlePaste(e) {
// Read data from clipboard.
if (e && e.clipboardData && e.clipboardData.getData) {
var types = '';
var clipboard_types = e.clipboardData.types;
if (editor.helpers.isArray(clipboard_types)) {
for (var i = 0; i < clipboard_types.length; i++) {
types += clipboard_types[i] + ';';
}
} else {
types = clipboard_types;
}
clipboard_html = '';
// HTML.
if (/text\/html/.test(types)) {
clipboard_html = e.clipboardData.getData('text/html');
}
// Safari HTML.
else if (/text\/rtf/.test(types) && editor.browser.safari) {
clipboard_html = e.clipboardData.getData('text/rtf');
} else if (/text\/plain/.test(types) && !this.browser.mozilla) {
clipboard_html = editor.html.escapeEntities(e.clipboardData.getData('text/plain')).replace(/\n/g, '<br>');
}
if (clipboard_html !== '') {
_processPaste();
if (e.preventDefault) {
e.stopPropagation();
e.preventDefault();
}
return false;
} else {
clipboard_html = null;
}
}
// Normal paste.
_beforePaste();
}
}
The function is the part of jquery plugin, so I would like to change the function outside of the plugin's files to be able further update it.
I am trying to change it like this:
(function ($) {
$.FE.MODULES.paste._handlePaste = function (e) {
// my implementation of _handlePaste
}
})(window.jQuery);
But I can't access _handlePaste this way.
I have been working on a formatting toolbar for a textarea, much like the toolbar for writing questions on this very site (with the bold, italic, underline buttons). The only difference is that I need the buttons to make the text actually bold not just add a bold tag. What I need is similar to the Instructables.com rich comment editor, or the newgrounds.com comment editor, or google docs. Does anyone have a clue how I can make some text in a textarea show up bold, italic, or underlined but keep the rest of it?
There are lots of implementations of javascript WYSIWYG eitors. FCKEditor (now CKEditor) was one of the first. TinyMCE was popular for a long time. I've recently used TinyEditor.
There's also nicedit, 10 editors listed and compared here, not to mention the answers previously provided here on SO to the question of what's available.
An they don't have to produce HTML - there are also editors producing Wiki markup
Why reinvent the wheel?
I found how to create own Rich Text Editor just like this :
(function ($) {
if (typeof $.fn.rte === "undefined") {
var defaults = {
content_css_url: "rte.css",
media_url: "images",
dot_net_button_class: null,
max_height: 350
};
$.fn.rte = function (options) {
$.fn.rte.html = function (iframe) {
return iframe.contentWindow.document.getElementsByTagName("body")[0].innerHTML;
};
var opts = $.extend(defaults, options);
return this.each(function () {
var textarea = $(this);
var iframe;
var myID = textarea.attr("id");
var settings = $.meta ? $.extend({}, opts, textarea.data()) : opts;
var sel = {
cmdBtnSelector: "." + settings.dot_net_button_class
};
function enableDesignMode() {
var content = textarea.val();
if ($.trim(content) == '') {
content = '<br />';
}
if (iframe) {
textarea.hide();
$(iframe).contents().find("body").html(content);
$(iframe).show();
$("#toolbar-" + myID).remove();
textarea.before(toolbar());
return true;
}
iframe = document.createElement("iframe");
iframe.frameBorder = 0;
iframe.frameMargin = 0;
iframe.framePadding = 0;
iframe.height = 200;
if (textarea.attr('class')) iframe.className = textarea.attr('class');
if (textarea.attr('id')) iframe.id = myID;
if (textarea.attr('name')) iframe.title = textarea.attr('name');
textarea.after(iframe);
var css = "";
if (settings.content_css_url) {
css = "<link type='text/css' rel='stylesheet' href='" + settings.content_css_url + "' />";
}
var doc = "<html><head>" + css + "</head><body class='frameBody'>" + content + "</body></html>";
tryEnableDesignMode(doc, function () {
$("#toolbar-" + myID).remove();
textarea.before(toolbar());
textarea.hide();
});
}
function tryEnableDesignMode(doc, callback) {
if (!iframe) {
return false;
}
try {
iframe.contentWindow.document.open();
iframe.contentWindow.document.write(doc);
iframe.contentWindow.document.close();
} catch (error) {
console.log(error)
}
if (document.contentEditable) {
iframe.contentWindow.document.designMode = "On";
callback();
return true;
} else if (document.designMode != null) {
try {
iframe.contentWindow.document.designMode = "on";
callback();
return true;
} catch (error) {
console.log(error)
}
}
setTimeout(function () {
tryEnableDesignMode(doc, callback)
}, 250);
return false;
}
function disableDesignMode(submit) {
var content = $(iframe).contents().find("body").html();
if ($(iframe).is(":visible")) {
textarea.val(content);
}
if (submit !== true) {
textarea.show();
$(iframe).hide();
}
}
function toolbar() {
var tb = $("<div class='rte-toolbar' id='toolbar-" + myID + "'><div>\
<p>\
<select>\
<option value=''>Block style</option>\
<option value='p'>Paragraph</option>\
<option value='h3'>Title</option>\
</select>\
</p>\
<p>\
<a href='#' class='bold'><img src='" + settings.media_url + "text_bold.png' alt='bold' title='Bold' /></a>\
<a href='#' class='italic'><img src='" + settings.media_url + "text_italic.png' alt='italic' title='Italicize' /></a>\
</p>\
<p>\
<a href='#' class='unorderedlist'><img src='" + settings.media_url + "text_list_bullets.png' alt='unordered list' title='Unordered List' /></a>\
<a href='#' class='link'><img src='" + settings.media_url + "link.png' alt='link' title='Hyperlink' /></a>\
<a href='#' class='image'><img src='" + settings.media_url + "image.png' alt='image' title='Image' /></a>\
<a href='#' class='disable'><img src='" + settings.media_url + "code.png' alt='close rte' title='View Code' /></a>\
</p></div></div>");
$('select', tb).change(function () {
var index = this.selectedIndex;
if (index != 0) {
var selected = this.options[index].value;
formatText("formatblock", '<' + selected + '>');
}
});
$('.bold', tb).click(function () {
formatText('bold');
return false;
});
$('.italic', tb).click(function () {
formatText('italic');
return false;
});
$('.unorderedlist', tb).click(function () {
formatText('insertunorderedlist');
return false;
});
$('.link', tb).click(function () {
var p = prompt("URL:");
if (p) formatText('CreateLink', p);
return false;
});
$('.image', tb).click(function () {
var p = prompt("image URL:");
if (p) formatText('InsertImage', p);
return false;
});
$('.disable', tb).click(function () {
disableDesignMode();
var edm = $('Enable design mode');
tb.empty().append(edm);
edm.click(function (e) {
e.preventDefault();
enableDesignMode();
$(this).remove();
});
return false;
});
if (settings.dot_net_button_class != null) {
var cmdBtn = $(iframe).parents('form').find(sel.cmdBtnSelector);
cmdBtn.click(function () {
disableDesignMode(true);
});
} else {
$(iframe).parents('form').submit(function () {
disableDesignMode(true);
});
}
var iframeDoc = $(iframe.contentWindow.document);
var select = $('select', tb)[0];
iframeDoc.mouseup(function () {
setSelectedType(getSelectionElement(), select);
return true;
});
iframeDoc.keyup(function () {
setSelectedType(getSelectionElement(), select);
var body = $('body', iframeDoc);
if (body.scrollTop() > 0) {
var iframe_height = parseInt(iframe.style['height']);
if (isNaN(iframe_height)) {
iframe_height = 0;
}
var h = Math.min(opts.max_height, iframe_height + body.scrollTop()) + 'px';
iframe.style['height'] = h;
}
return true;
});
return tb;
}
function formatText(command, option) {
iframe.contentWindow.focus();
try {
iframe.contentWindow.document.execCommand(command, false, option);
} catch (e) {
console.log(e)
}
iframe.contentWindow.focus();
}
function setSelectedType(node, select) {
while (node.parentNode) {
var nName = node.nodeName.toLowerCase();
for (var i = 0; i < select.options.length; i++) {
if (nName == select.options[i].value) {
select.selectedIndex = i;
return true;
}
}
node = node.parentNode;
}
select.selectedIndex = 0;
return true;
}
function getSelectionElement() {
if (iframe.contentWindow.document.selection) {
selection = iframe.contentWindow.document.selection;
range = selection.createRange();
try {
node = range.parentElement();
} catch (e) {
return false;
}
} else {
try {
selection = iframe.contentWindow.getSelection();
range = selection.getRangeAt(0);
} catch (e) {
return false;
}
node = range.commonAncestorContainer;
}
return node;
}
enableDesignMode();
});
};
}
})(jQuery);
The contentEditable DOM attribute is used make the document or a section of it editable. This doesn't work with a <textarea>; more often an <iframe> is created and the document inside of it used as an editor.
Mark Pilgrim has an article explaining it on the blog of the Web Hypertext Application Technology Working Group. It includes an example page showing some of the features in use.
I have got following jquery tags plugin.
I want to to restrict maxmimum 5 tags, so that user can not enter more than 5 words (separated by spaces).
Can someone please help me doing it?
Thanks.. Following is original plugin code:
(function($) {
var delimiter = new Array();
jQuery.fn.addTag = function(value,options) {
var options = jQuery.extend({focus:false},options);
this.each(function() {
id = $(this).attr('id');
var tagslist = $(this).val().split(delimiter[id]);
if (tagslist[0] == '') {
tagslist = new Array();
}
value = jQuery.trim(value);
if (value !='') {
$('<span class="tag">'+value + ' x</span>').insertBefore('#'+id+'_addTag');
tagslist.push(value);
$('#'+id+'_tag').val('');
if (options.focus) {
$('#'+id+'_tag').focus();
} else {
$('#'+id+'_tag').blur();
}
}
jQuery.fn.tagsInput.updateTagsField(this,tagslist);
});
return false;
};
jQuery.fn.removeTag = function(value) {
this.each(function() {
id = $(this).attr('id');
var old = $(this).val().split(delimiter[id]);
$('#'+id+'_tagsinput .tag').remove();
str = '';
for (i=0; i< old.length; i++) {
if (escape(old[i])!=value) {
str = str + delimiter[id] +old[i];
}
}
jQuery.fn.tagsInput.importTags(this,str);
});
return false;
};
jQuery.fn.tagsInput = function(options) {
var settings = jQuery.extend({defaultText:'add a tag',width:'300px',height:'100px','hide':true,'delimiter':',',autocomplete:{selectFirst:false}},options);
this.each(function() {
if (settings.hide) {
$(this).hide();
}
id = $(this).attr('id')
data = jQuery.extend({
pid:id,
real_input: '#'+id,
holder: '#'+id+'_tagsinput',
input_wrapper: '#'+id+'_addTag',
fake_input: '#'+id+'_tag',
},settings);
delimiter[id] = data.delimiter;
$('<div id="'+id+'_tagsinput" class="tagsinput"><div id="'+id+'_addTag"><input id="'+id+'_tag" value="" default="'+settings.defaultText+'" /></div><div class="tags_clear"></div></div>').insertAfter(this);
$(data.holder).css('width',settings.width);
$(data.holder).css('height',settings.height);
if ($(data.real_input).val()!='') {
jQuery.fn.tagsInput.importTags($(data.real_input),$(data.real_input).val());
} else {
$(data.fake_input).val($(data.fake_input).attr('default'));
$(data.fake_input).css('color','#666666');
}
$(data.holder).bind('click',data,function(event) {
$(event.data.fake_input).focus();
});
// if user types a comma, create a new tag
$(data.fake_input).bind('keypress',data,function(event) {
if (event.which==event.data.delimiter.charCodeAt(0) || event.which==13) {
$(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true});
return false;
}
});
$(data.fake_input).bind('focus',data,function(event) {
if ($(event.data.fake_input).val()==$(event.data.fake_input).attr('default')) {
$(event.data.fake_input).val('');
}
$(event.data.fake_input).css('color','#000000');
});
if (settings.autocomplete_url != undefined) {
$(data.fake_input).autocomplete(settings.autocomplete_url,settings.autocomplete).bind('result',data,function(event,data,formatted) {
if (data) {
d = data + "";
$(event.data.real_input).addTag(d,{focus:true});
}
});;
$(data.fake_input).bind('blur',data,function(event) {
if ($(event.data.fake_input).val() != $(event.data.fake_input).attr('default')) {
$(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:false});
}
$(event.data.fake_input).val($(event.data.fake_input).attr('default'));
$(event.data.fake_input).css('color','#666666');
return false;
});
} else {
// if a user tabs out of the field, create a new tag
// this is only available if autocomplete is not used.
$(data.fake_input).bind('blur',data,function(event) {
var d = $(this).attr('default');
if ($(event.data.fake_input).val()!='' && $(event.data.fake_input).val()!=d) {
event.preventDefault();
$(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true});
} else {
$(event.data.fake_input).val($(event.data.fake_input).attr('default'));
$(event.data.fake_input).css('color','#666666');
}
return false;
});
}
$(data.fake_input).blur();
});
return this;
};
jQuery.fn.tagsInput.updateTagsField = function(obj,tagslist) {
id = $(obj).attr('id');
$(obj).val(tagslist.join(delimiter[id]));
};
jQuery.fn.tagsInput.importTags = function(obj,val) {
$(obj).val('');
id = $(obj).attr('id');
var tags = val.split(delimiter[id]);
for (i=0; i<tags.length; i++) {
$(obj).addTag(tags[i],{focus:false});
}
};
})(jQuery);
best way is to count the number of "tag" classes already added, and then you can handle it differently, for example you can prevent showing the "add a tag" input once 5 tags inserted by defining maxTags and updating jQuery.fn.addTag and jQuery.fn.removeTag :
/*
jQuery Tags Input Plugin 1.0
Copyright (c) 2010 XOXCO, Inc
Documentation for this plugin lives here:
http://xoxco.com/clickable/jquery-tags-input
Licensed under the MIT license:
http://www.opensource.org/licenses/mit-license.php
ben#xoxco.com
*/
(function($) {
var delimiter = new Array();
var maxTags = 5;
jQuery.fn.addTag = function(value,options) {
var options = jQuery.extend({focus:false},options);
this.each(function() {
id = $(this).attr('id');
var tagslist = $(this).val().split(delimiter[id]);
if (tagslist[0] == '') {
tagslist = new Array();
}
value = jQuery.trim(value);
if (value !='') {
$('<span class="tag">'+value + ' x</span>').insertBefore('#'+id+'_addTag');
tagslist.push(value);
$('#'+id+'_tag').val('');
if (options.focus) {
$('#'+id+'_tag').focus();
} else {
$('#'+id+'_tag').blur();
}
}
jQuery.fn.tagsInput.updateTagsField(this,tagslist);
});
if($(".tag").length>maxTags-1){$('#'+id+'_addTag').hide()}
return false;
};
jQuery.fn.removeTag = function(value) {
this.each(function() {
id = $(this).attr('id');
var old = $(this).val().split(delimiter[id]);
$('#'+id+'_tagsinput .tag').remove();
str = '';
for (i=0; i< old.length; i++) {
if (escape(old[i])!=value) {
str = str + delimiter[id] +old[i];
}
}
jQuery.fn.tagsInput.importTags(this,str);
});
if($(".tag").length<maxTags){$('#'+id+'_addTag').show()}
return false;
};
jQuery.fn.tagsInput = function(options) {
var settings = jQuery.extend({defaultText:'add a tag',width:'300px',height:'100px','hide':true,'delimiter':',',autocomplete:{selectFirst:false}},options);
this.each(function() {
if (settings.hide) {
$(this).hide();
}
id = $(this).attr('id')
data = jQuery.extend({
pid:id,
real_input: '#'+id,
holder: '#'+id+'_tagsinput',
input_wrapper: '#'+id+'_addTag',
fake_input: '#'+id+'_tag',
},settings);
delimiter[id] = data.delimiter;
$('<div id="'+id+'_tagsinput" class="tagsinput"><div id="'+id+'_addTag"><input id="'+id+'_tag" value="" default="'+settings.defaultText+'" /></div><div class="tags_clear"></div></div>').insertAfter(this);
$(data.holder).css('width',settings.width);
$(data.holder).css('height',settings.height);
if ($(data.real_input).val()!='') {
jQuery.fn.tagsInput.importTags($(data.real_input),$(data.real_input).val());
} else {
$(data.fake_input).val($(data.fake_input).attr('default'));
$(data.fake_input).css('color','#666666');
}
$(data.holder).bind('click',data,function(event) {
$(event.data.fake_input).focus();
});
// if user types a comma, create a new tag
$(data.fake_input).bind('keypress',data,function(event) {
if (event.which==event.data.delimiter.charCodeAt(0) || event.which==13) {
$(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true});
return false;
}
});
$(data.fake_input).bind('focus',data,function(event) {
if ($(event.data.fake_input).val()==$(event.data.fake_input).attr('default')) {
$(event.data.fake_input).val('');
}
$(event.data.fake_input).css('color','#000000');
});
if (settings.autocomplete_url != undefined) {
$(data.fake_input).autocomplete(settings.autocomplete_url,settings.autocomplete).bind('result',data,function(event,data,formatted) {
if (data) {
d = data + "";
$(event.data.real_input).addTag(d,{focus:true});
}
});;
$(data.fake_input).bind('blur',data,function(event) {
if ($(event.data.fake_input).val() != $(event.data.fake_input).attr('default')) {
$(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:false});
}
$(event.data.fake_input).val($(event.data.fake_input).attr('default'));
$(event.data.fake_input).css('color','#666666');
return false;
});
} else {
// if a user tabs out of the field, create a new tag
// this is only available if autocomplete is not used.
$(data.fake_input).bind('blur',data,function(event) {
var d = $(this).attr('default');
if ($(event.data.fake_input).val()!='' && $(event.data.fake_input).val()!=d) {
event.preventDefault();
$(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true});
} else {
$(event.data.fake_input).val($(event.data.fake_input).attr('default'));
$(event.data.fake_input).css('color','#666666');
}
return false;
});
}
$(data.fake_input).blur();
});
return this;
};
jQuery.fn.tagsInput.updateTagsField = function(obj,tagslist) {
id = $(obj).attr('id');
$(obj).val(tagslist.join(delimiter[id]));
};
jQuery.fn.tagsInput.importTags = function(obj,val) {
$(obj).val('');
id = $(obj).attr('id');
var tags = val.split(delimiter[id]);
for (i=0; i<tags.length; i++) {
$(obj).addTag(tags[i],{focus:false});
}
};
})(jQuery);
How about adding something like this:
if($('.tag').length>=5){
$('#tags_tag').attr('disabled','true');
}
I put a little more flair into my demo.
Probably the easiest solution is to change line 89 of jquery.tagsinput.js from:
var skipTag = $(tagslist).tagExist(value);
to:
var skipTag = $(tagslist).length > 5 || $(tagslist).tagExist(value);
I am having Ajax issues with IE (6, 7 & 8).
I am using the Simple AJAX Code-Kit (SACK) v1.6.1 which works fine in FF, GC, Opera and Safiri.
In IE it throws the error:
System error: -1072896658.
Breaking on JS error on line 157 (self.response = self.xmlhttp.responseText;).
/* Simple AJAX Code-Kit (SACK) v1.6.1 */
/* 2005 Gregory Wild-Smith */
/* www.twilightuniverse.com */
/* Software licenced under a modified X11 licence,
see documentation or authors website for more details */
function sack(file) {
this.xmlhttp = null;
this.resetData = function() {
this.method = "POST";
this.queryStringSeparator = "?";
this.argumentSeparator = "&";
this.URLString = "";
this.encodeURIString = true;
this.execute = false;
this.element = null;
this.elementObj = null;
this.requestFile = file;
this.vars = new Object();
this.responseStatus = new Array(2);
};
this.resetFunctions = function() {
this.onloading = function() { };
this.onloaded = function() { };
this.onInteractive = function() { };
this.onCompletion = function() { };
this.onerror = function() { };
this.onFail = function() { };
};
this.reset = function() {
this.resetFunctions();
this.resetData();
};
this.createAJAX = function() {
try {
this.xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e1) {
try {
this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e2) {
this.xmlhttp = null;
}
}
if (! this.xmlhttp) {
if (typeof XMLHttpRequest != "undefined") {
this.xmlhttp = new XMLHttpRequest();
} else {
this.failed = true;
}
}
};
this.setVar = function(name, value){
this.vars[name] = Array(value, false);
};
this.encVar = function(name, value, returnvars) {
if (true == returnvars) {
return Array(encodeURIComponent(name), encodeURIComponent(value));
} else {
this.vars[encodeURIComponent(name)] = Array(encodeURIComponent(value), true);
}
}
this.processURLString = function(string, encode) {
encoded = encodeURIComponent(this.argumentSeparator);
regexp = new RegExp(this.argumentSeparator + "|" + encoded);
varArray = string.split(regexp);
for (i = 0; i < varArray.length; i++){
urlVars = varArray[i].split("=");
if (true == encode){
this.encVar(urlVars[0], urlVars[1]);
} else {
this.setVar(urlVars[0], urlVars[1]);
}
}
}
this.createURLString = function(urlstring) {
if (this.encodeURIString && this.URLString.length) {
this.processURLString(this.URLString, true);
}
if (urlstring) {
if (this.URLString.length) {
this.URLString += this.argumentSeparator + urlstring;
} else {
this.URLString = urlstring;
}
}
// prevents caching of URLString
this.setVar("rndval", new Date().getTime());
urlstringtemp = new Array();
for (key in this.vars) {
if (false == this.vars[key][1] && true == this.encodeURIString) {
encoded = this.encVar(key, this.vars[key][0], true);
delete this.vars[key];
this.vars[encoded[0]] = Array(encoded[1], true);
key = encoded[0];
}
urlstringtemp[urlstringtemp.length] = key + "=" + this.vars[key][0];
}
if (urlstring){
this.URLString += this.argumentSeparator + urlstringtemp.join(this.argumentSeparator);
} else {
this.URLString += urlstringtemp.join(this.argumentSeparator);
}
}
this.runResponse = function() {
eval(this.response);
}
this.runAJAX = function(urlstring) {
if (this.failed) {
this.onFail();
} else {
this.createURLString(urlstring);
if (this.element) {
this.elementObj = document.getElementById(this.element);
}
if (this.xmlhttp) {
var self = this;
if (this.method == "GET") {
totalurlstring = this.requestFile + this.queryStringSeparator + this.URLString;
this.xmlhttp.open(this.method, totalurlstring, true);
} else {
this.xmlhttp.open(this.method, this.requestFile, true);
try {
this.xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=ISO-8859-1;")
this.xmlhttp.setRequestHeader('User-agent' , 'Mozilla/4.0 (compatible) Naruki');
} catch (e) { }
}
this.xmlhttp.onreadystatechange = function() {
switch (self.xmlhttp.readyState) {
case 1:
self.onloading();
break;
case 2:
self.onloaded();
break;
case 3:
self.onInteractive();
break;
case 4:
if(self.xmlhttp.status==200){
**self.response = self.xmlhttp.responseText;**
//console.log(self.xmlhttp.responseText);
self.responseXML = self.xmlhttp.responseXML;
self.responseStatus[0] = self.xmlhttp.status;
self.responseStatus[1] = self.xmlhttp.statusText;
}
else{alert("Problem retrieving XML data")}
if (self.execute) {
self.runResponse();
}
if (self.elementObj) {
elemNodeName = self.elementObj.nodeName;
elemNodeName.toLowerCase();
if (elemNodeName == "input"
|| elemNodeName == "select"
|| elemNodeName == "option"
|| elemNodeName == "textarea") {
self.elementObj.value = self.response;
} else {
self.elementObj.innerHTML = self.response;
}
}
if (self.responseStatus[0] == "200") {
self.onCompletion();
} else {
self.onerror();
}
self.URLString = "";
/* These lines were added by Alf Magne Kalleland ref. info on the sack home page. It prevents memory leakage in IE */
delete self.xmlhttp['onreadystatechange'];
self.xmlhttp=null;
self.responseStatus=null;
self.response=null;
self.responseXML=null;
break;
}
};
this.xmlhttp.send(this.URLString);
}
}
};
this.reset();
this.createAJAX();
}
This IE error is probably related to the content-type header of the response sent from the server, where the charset may be invalid, or not what IE is expecting. A typical cause would be setting the charset to UTF8 instead of UTF-8.
Related article:
System error: -1072896658 in IE
The error message means that the encoding of the response is not supported.
Check the encoding of the page that you are getting. Most browsers are a bit relaxed about the syntax and accepts an encoding like UTF8, while IE demands the correct form UTF-8.
if you have charset=UTF8 change it to charset=utf-8 it will help... to solve your issue.