codemirror - ondblclick only affecting last element with class - javascript

http://jsfiddle.net/tZVsS/72/
if you double-click either of the first two elements with the class .code you'll notice that the setOptions will only be applied to the last element with the class .code. what i need to happen is when you double-click on each individual elements the setoption to be applied to that element, why is this not working and what can be done to fix it
(function () {
var codes = document.getElementsByClassName("code");
for (i = 0; i < codes.length; i++) {
var $this = codes[i];
var $unescaped = $this.innerHTML.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
var isspan = $this.nodeName.toLowerCase() == "span";
$this.innerHTML = "";
if (isspan) {
$this.style.display = "inline-block"
} else {
$this.style.display = "inline"
}
var editor = new CodeMirror($this, {
value: $unescaped,
mode: 'javascript',
lineNumbers: false,
readOnly: true
});
$this.ondblclick = function () {
editor.setOption("readOnly", false);
editor.setOption("lineNumbers", true);
}
}
})();
The HTML is below, NOTE: it's not much use, instead retrace what i've done on the fiddle for a good understanding
Some code <span class="code inline">function inline() { alert('inline code') }</span> inside
a sentence.
<div class="code">function test() { return false; }</div>

Just a scope issue
Updated Fiddle: http://jsfiddle.net/tZVsS/73/
(function () {
var codes = document.getElementsByClassName("code");
for (i = 0; i < codes.length; i++) {
(function ($this) {
var $unescaped = $this.innerHTML.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
var isspan = $this.nodeName.toLowerCase() == "span";
$this.innerHTML = "";
if (isspan) {
$this.style.display = "inline-block"
} else {
$this.style.display = "inline"
}
var editor = new CodeMirror($this, {
value: $unescaped,
mode: 'javascript',
lineNumbers: false,
readOnly: true
});
$this.ondblclick = function () {
console.log($this);
editor.setOption("readOnly", false);
editor.setOption("lineNumbers", true);
}
})(codes[i]);
}
})();

Related

Config based Hide Show Rules Processor in JavaScript

I am working on a library which does DOM hide and show based on other DOM elements.
I have written a basic structure for the library.
The below is the code to handle DOM elements hiding when a checkbox is checked and unchecked.
My overall goal is to make this library extensible and maintainable.
Am I following SOLID principles? Is there any better way to do it? Are there any design patterns to follow?
// basic data structure of config object
var rules = [
{
sourceId: 'mainCheckbox',
targetId: 'exampleDiv1',
ruleType: 'onlyOnChecked',
targetVisibilityOnChecked: 'hide', // show / hide
targetVisibilityOnUnchecked: 'show',
doNotReset: false
}
]
var ruleToProcessorMap = {
onlyOnChecked: OnlyOnCheckedRuleProcessor
}
var RuleEngine = {}
RuleEngine.run = function(rules) {
var ruleIndex
for (ruleIndex = 0; ruleIndex < rules.length; rules++) {
this.processRule(rules[ruleIndex])
}
}
RuleEngine.processRule = function(ruleObj) {
var ruleProcessor = new ruleToProcessorMap[ruleObj.ruleType](ruleObj)
ruleProcessor.process()
}
function OnlyOnCheckedRuleProcessor(options) {
this.options = options || {}
}
OnlyOnCheckedRuleProcessor.prototype.process = function() {
var $sourceId = $id(this.options.sourceId),
ctx = this
$sourceId.on('click', onSourceClick)
function onSourceClick() {
var elementVisibilityHandler = new ElementVisibilityHandler({
elementId: ctx.options.targetId,
doNotReset: ctx.options.doNotReset
}),
show = elementVisibilityHandler.show,
hide = elementVisibilityHandler.hide
var visibilityMap = {
show: show,
hide: hide
}
var onCheckedFunc = visibilityMap[ctx.options.targetVisibilityOnChecked]
var onUncheckedFunc = visibilityMap[ctx.options.targetVisibilityOnUnchecked]
if ($sourceId.is(':checked')) {
onCheckedFunc.call(elementVisibilityHandler)
} else {
onUncheckedFunc.call(elementVisibilityHandler)
}
}
}
function ElementVisibilityHandler(options) {
this.options = options || {}
this.$element = $id(options.elementId)
}
ElementVisibilityHandler.prototype.show = function() {
if (isContainerElement(this.$element)) {
if (this.options.doNotReset) {
simpleShow(this.$element)
} else {
showWithChildren(this.$element)
}
}
}
ElementVisibilityHandler.prototype.hide = function() {
if (isContainerElement(this.$element)) {
if (this.options.doNotReset) {
simpleHide(this.$element)
} else {
hideAndResetChildren(this.$element)
}
}
}
function simpleHide($element) {
return $element.hide()
}
function hideAndResetChildren($element) {
var $children = simpleHide($element)
.children()
.hide()
$children.find('input:checkbox').prop('checked', false)
$children.find('textarea, input').val('')
}
function simpleShow($element) {
return $element.show()
}
function showWithChildren($element) {
simpleShow($element)
.children()
.show()
}
function $id(elementId) {
return $('#' + elementId)
}
function isContainerElement($element) {
if (typeof $element === 'string') {
$element = $id($element)
}
return $element.prop('tagName').toLowerCase()
}
// execution starts here
RuleEngine.run(rules)

Can someone help me write this in javascript

I am trying to write this code in javascript from jquery
I already tried but cant seems to get equivalent to work.
$(document).ready(function() {
$('a').click(function() {
var selected = $(this);
$('a').removeClass('active');
$(selected).addClass('active');
});
var $a = $('.a'),
$b = $('.b'),
$c = $('.c'),
$d = $('.d'),
$home = $('.home'),
$about = $('.about');
$a.click(function() {
$home.fadeIn();
$about.fadeOut();
});
$b.click(function() {
$home.fadeOut();
$about.fadeIn();
});
});
The code works perfect in jQuery, but am trying to just use javascript. Its basically to add and remove class when a nav item is selected. I don't know if am explaining as clear as possible but am try to write the equivalent of this in javascript.
This is what I have tried.
var callback = function(){
var clickHandler1 = function() {
document.getElementById("home").classList.remove("home");
//var rem = document.getElementById("home");
//fadeOut(rem);
//alert("I am clicked B");
};
var anchors1 = document.getElementsByClassName("b");
for (var i = 0; i < anchors1.length; i++) {
var current = anchors1[i];
current.addEventListener('click', clickHandler1, false);
}
function fadeOut(el){
el.style.opacity = 1;
function fade() {
if ((el.style.opacity -= .1) < 0) {
el.style.display = "none";
} else {
requestAnimationFrame(fade);
}
})();
};
fadeIn(el, display){
el.style.opacity = 0;
el.style.display = display || "block";
(function fade() {
var val = parseFloat(el.style.opacity);
if (!((val += .1) > 1)) {
el.style.opacity = val;
requestAnimationFrame(fade);
}
})();
};
}
if ( document.readyState === "complete" || (document.readyState !== "loading" && !document.documentElement.doScroll)) {
callback();
} else {
document.addEventListener("DOMContentLoaded", callback);
}
The code in es6:
window.onload = function() {
const allLinks = document.querySelectorAll('a')
console.log(allLinks)
const removeAllClass = () => {
allLinks.forEach(link => {
link.classList.remove('active')
})
}
allLinks.forEach(element => {
element.addEventListener('click', event => {
removeAllClass()
element.classList.add('active')
})
})
let $a = document.querySelectorAll('.a'),
$b = document.querySelectorAll('.b'),
$home = document.querySelector('.home'),
$about = document.querySelector('.about');
$a.forEach(element => {
element.addEventListener('click', event => {
$about.classList.remove('fadeIn');
$home.classList.add('fadeIn');
})
})
$b.forEach(element => {
element.addEventListener('click', event => {
$home.classList.remove('fadeIn');
$about.classList.add('fadeIn');
})
})
}
you can see working on https://codepen.io/rwladyka/pen/qBBBpvy
document.getElementsByClassName('a') is the javascript equivalent of $('.a')

Refactoring repeated code in javascript prototype constructor

I have a open function that once triggered, simply plays video in a dedicated panel.
This function can be triggered in two ways - one with a click and another one with a page load (window load) with url that contains a valid anchor tag.
They all work fine but some codes of the window load handler are repetitive and I'm not too sure how I can keep this DRY.
Please take a look and point me in some directions on how I can write this better.
I commented in open function which is for which.
$.videoWatch.prototype = {
init: function() {
this.$openLinks = this.$element.find(".open");
this.$closeLinks = this.$element.find(".close");
this.open();
this.close();
},
_getContent: function(element) {
var $parent = element.parent(),
id = element.attr('href').substring(1),
title = $parent.data('title'),
desc = $parent.data('desc');
return {
title: title,
desc: desc,
id: id
}
},
open: function() {
var self = this;
//open theatre with window load with #hash id
window.onload = function() {
var hash = location.hash;
var $a = $('a[href="' + hash + '"]'),
content = self._getContent($a),
$li = $a.parents("li"),
$theatreVideo = $(".playing"),
$theatreTitle = $(".theatre-title"),
$theatreText = $(".theatre-text");
$(".theatre").attr('id', content.id);
$theatreTitle.text(content.title);
$theatreText.text(content.desc);
if ($theatreText.text().length >= 90) {
$(".theatre-text").css({
'overflow': 'hidden',
'max-height': '90px',
});
$moreButton.insertAfter($theatreText);
}
$a.parent().addClass("active");
$(".theatre").insertAfter($li);
$(".theatre").slideDown('fast', scrollToTheatre);
oldIndex = $li.index();
}
//open theatre with click event
self.$openLinks.on("click", function(e) {
// e.preventDefault();
if (curID == $(this).parent().attr("id")) {
$("figure").removeClass("active");
$("button.more").remove();
$(".theatre").slideUp('fast');
$('.playing').attr("src", "");
removeHash();
oldIndex = -1;
curID = "";
return false
} else {
curID = $(this).parent().attr("id");
}
var $a = $(this),
content = self._getContent($a),
$li = $a.parents("li"),
$theatreVideo = $(".playing"),
$theatreTitle = $(".theatre-title"),
$theatreText = $(".theatre-text");
$(".theatre").attr('id', content.id);
$theatreTitle.text(content.title);
$theatreText.text(content.desc);
if ($theatreText.text().length >= 90) {
$(".theatre-text").css({
'overflow': 'hidden',
'max-height': '90px',
});
$moreButton.insertAfter($theatreText);
}
if (!($li.index() == oldIndex)) {
$("figure").removeClass("active");
$(".theatre").hide(function(){
$a.parent().addClass("active");
$(".theatre").insertAfter($li);
$(".theatre").slideDown('fast', scrollToTheatre);
oldIndex = $li.index();
});
} else {
$(".theatre").insertAfter($li);
scrollToTheatre();
$("figure").removeClass("active");
$a.parent().addClass("active");
}
});
},
...
Simplified and refactored open method:
open: function() {
var self = this;
var serviceObj = {
theatreVideo : $(".playing"),
theatre: $(".theatre"),
theatreTitle : $(".theatre-title"),
theatreText : $(".theatre-text"),
setTheatreContent: function(content){
this.theatre.attr('id', content.id);
this.theatreTitle.text(content.title);
this.theatreText.text(content.desc);
if (this.theatreText.text().length >= 90) {
this.theatreText.css({
'overflow': 'hidden',
'max-height': '90px',
});
$moreButton.insertAfter(this.theatreText);
}
},
activateTeatre: function(a, li){
a.parent().addClass("active");
this.theatre.insertAfter(li);
this.theatre.slideDown('fast', scrollToTheatre);
oldIndex = li.index();
}
};
//open theatre with window load with #hash id
window.onload = function() {
var hash = location.hash;
var $a = $('a[href="' + hash + '"]'),
content = self._getContent($a),
$li = $a.parents("li");
serviceObj.setTheatreContent(content);
serviceObj.activateTeatre($a, $li);
}
//open theatre with click event
self.$openLinks.on("click", function(e) {
// e.preventDefault();
if (curID == $(this).parent().attr("id")) {
$("figure").removeClass("active");
$("button.more").remove();
$(".theatre").slideUp('fast');
$('.playing').attr("src", "");
removeHash();
oldIndex = -1;
curID = "";
return false
} else {
curID = $(this).parent().attr("id");
}
var $a = $(this),
content = self._getContent($a),
$li = $a.parents("li");
serviceObj.setTheatreContent(content);
if (!($li.index() == oldIndex)) {
$("figure").removeClass("active");
$(".theatre").hide(function(){
serviceObj.activateTeatre($a, $li);
});
} else {
$(".theatre").insertAfter($li);
scrollToTheatre();
$("figure").removeClass("active");
$a.parent().addClass("active");
}
});
},
1st of all there are variables that don't depend on the input, you could pull them to the class (I'll show just one example, as you asked for directions):
init: function() {
this.$theatreVideo = $(".playing");
All the variables that do depend on the input, like $li could be moved to a function:
var $a = $(this),
$dependsOnA = self.dependsOnA($a);
self.actionDependsOnA($dependsOnA); // see below
function dependsOnA($a) {
return {
a: $a,
li: $a.parents("li"),
content: self._getContent($a)
}
}
Also the code that "repeats" can be moved to a function:
function actionDependsOnA($dependsOnA)
$(".theatre").attr('id', $dependsOnA.content.id);
$theatreTitle.text($dependsOnA.content.title);
$theatreText.text($dependsOnA.content.desc);
}

Bad escaping of EOL

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('')

Javascript's Callback Function

I am using Lazy Load Jquery plugin here on my test page: http://bloghutsbeta.blogspot.com/2012/03/testing-2_04.html
And this is the minified script for lazyload:
Code:
<script src="http://files.cryoffalcon.com/javascript/jquery.lazyload.min.js" type="text/javascript" charset="utf-8"></script>
this one is to trigger lazy load:
Code:
<script type="text/javascript" charset="utf-8">
$(function() {
$("img").lazyload({
effect : "fadeIn"
});
});
</script>
In the above script I have added fadeIn effect to it, I don't know if I have done it right according to script writting I am not good in scripts ^^ So, I would like have an advise if it's well written or there is some comma mistake.
But that is not my important question, all of the above lazy load plugin is used with QuickSand Jquery plugin that I am using for sorting.
QuickSand Jquery Plugin requires callback function if it's tooltip or Lazy Load, So can someone kindly tell me how to make lazy load work together with quicksand jquery.
Here is the quicksand's script:
Code:
<script type="text/javascript">
(function(cash) {
$.fn.sorted = function(customOptions) {
var options = {
reversed: false,
by: function(a) {
return a.text();
}
};
$.extend(options, customOptions);
$data = $(this);
arr = $data.get();
arr.sort(function(a, b) {
var valA = options.by($(a));
var valB = options.by($(b));
if (options.reversed) {
return (valA < valB) ? 1 : (valA > valB) ? -1 : 0;
} else {
return (valA < valB) ? -1 : (valA > valB) ? 1 : 0;
}
});
return $(arr);
};
})(jQuery);
$(function() {
var read_button = function(class_names) {
var r = {
selected: false,
type: 0
};
for (var i=0; i < class_names.length; i++) {
if (class_names[i].indexOf('selected-') == 0) {
r.selected = true;
}
if (class_names[i].indexOf('segment-') == 0) {
r.segment = class_names[i].split('-')[1];
}
};
return r;
};
var determine_sort = function($buttons) {
var $selected = $buttons.parent().filter('[class*="selected-"]');
return $selected.find('a').attr('data-value');
};
var determine_kind = function($buttons) {
var $selected = $buttons.parent().filter('[class*="selected-"]');
return $selected.find('a').attr('data-value');
};
var $preferences = {
duration: 800,
easing: 'easeInOutQuad',
adjustHeight: 'dynamic'
};
var $list = $('#data');
var $data = $list.clone();
var $controls = $('ul#gamecategories ul');
$controls.each(function(i) {
var $control = $(this);
var $buttons = $control.find('a');
$buttons.bind('click', function(e) {
var $button = $(this);
var $button_container = $button.parent();
var button_properties = read_button($button_container.attr('class').split(' '));
var selected = button_properties.selected;
var button_segment = button_properties.segment;
if (!selected) {
$buttons.parent().removeClass('selected-0').removeClass('selected-1').removeClass('selected-2');
$button_container.addClass('selected-' + button_segment);
var sorting_type = determine_sort($controls.eq(1).find('a'));
var sorting_kind = determine_kind($controls.eq(0).find('a'));
if (sorting_kind == 'all') {
var $filtered_data = $data.find('li');
} else {
var $filtered_data = $data.find('li.' + sorting_kind);
}
if (sorting_type == 'size') {
var $sorted_data = $filtered_data.sorted({
by: function(v) {
return parseFloat($(v).find('span').text());
}
});
} else {
var $sorted_data = $filtered_data.sorted({
by: function(v) {
return $(v).find('strong').text().toLowerCase();
}
});
}
$list.quicksand($sorted_data, $preferences, function () { $(this).tooltip (); } );
}
e.preventDefault();
});
});
var high_performance = true;
var $performance_container = $('#performance-toggle');
var $original_html = $performance_container.html();
$performance_container.find('a').live('click', function(e) {
if (high_performance) {
$preferences.useScaling = false;
$performance_container.html('CSS3 scaling turned off. Try the demo again. <a href="#toggle">Reverse</a>.');
high_performance = false;
} else {
$preferences.useScaling = true;
$performance_container.html($original_html);
high_performance = true;
}
e.preventDefault();
});
});
</script>
you can use this:
$list.quicksand($sorted_data, $preferences, function(){
$(this).tooltip ();
$("img").lazyload({
effect : "fadeIn"
});
});

Categories