Config based Hide Show Rules Processor in JavaScript - 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)

Related

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

redeclare javascript function

I hope that somebody can help me.
I want to redeclare js function by extension.
For example, there is the basic js function on website:
function foo(){
..something here..
}
i want to redeclare it by own function with the same name. how it will be easiest to do?
edit 1. i'll try to explain better.
there is a native code in website:
Notifier = {
debug: false,
init: function (options) {
curNotifier = extend({
q_events: [],
q_shown: [],
q_closed: [],
q_max: 3,
q_idle_max: 5,
done_events: {},
addQueues: curNotifier.addQueues || {},
recvClbks: curNotifier.recvClbks || {},
error_timeout: 1,
sound: new Sound('mp3/bb1'),
sound_im: new Sound('mp3/bb2')
}, options);
if (!this.initFrameTransport() && !this.initFlashTransport(options)) {
return false;
}
this.initIdleMan();
if (!(curNotifier.cont = ge('notifiers_wrap'))) {
bodyNode.insertBefore(curNotifier.cont = ce('div', {id: 'notifiers_wrap', className: 'fixed'}), ge('page_wrap'));
}
},
destroy: function () {
Notifier.hideAllEvents();
curNotifier.idle_manager.stop();
curNotifier = {};
re('notifiers_wrap');
re('queue_transport_wrap');
},
reinit: function () {
ajax.post('notifier.php?act=a_get_params', {}, {
onDone: function (options) {
if (options) {
curNotifier.error_timeout = 1;
this.init(options);
} else {
curNotifier.error_timeout = curNotifier.error_timeout || 1;
setTimeout(this.reinit.bind(this), curNotifier.error_timeout * 1000);
if (curNotifier.error_timeout < 256) {
curNotifier.error_timeout *= 2;
}
}
}.bind(this),
onFail: function () {
curNotifier.error_timeout = curNotifier.error_timeout || 1;
setTimeout(this.reinit.bind(this), curNotifier.error_timeout * 1000);
if (curNotifier.error_timeout < 256) {
curNotifier.error_timeout *= 2;
}
return true;
}.bind(this)
});
}
}
and function Sound
function Sound(filename) {
var audioObjSupport = false, audioTagSupport = false, self = this, ext;
if (!filename) throw 'Undefined filename';
try {
var audioObj = ce('audio');
audioObjSupport = !!(audioObj.canPlayType);
if (('no' != audioObj.canPlayType('audio/mpeg')) && ('' != audioObj.canPlayType('audio/mpeg')))
ext = '.mp3?1';
else if (('no' != audioObj.canPlayType('audio/ogg; codecs="vorbis"')) && ('' != audioObj.canPlayType('audio/ogg; codecs="vorbis"')))
ext = '.ogg?1';
else
audioObjSupport = false;
} catch (e) {}
// audioObjSupport = false;
if (audioObjSupport) {
audioObj.src = filename + ext;
var ended = false;
audioObj.addEventListener('ended', function(){ended = true;}, true);
audioObj.load();
this.playSound = function() {
if (ended) {
audioObj.load();
}
audioObj.play();
ended = false;
};
this.pauseSound = function() {
audioObj.pause();
};
} else {
cur.__sound_guid = cur.__sound_guid || 0;
var wrap = ge('flash_sounds_wrap') || utilsNode.appendChild(ce('span', {id: 'flash_sounds_wrap'})),
guid = 'flash_sound_' + (cur.__sound_guid++);
var opts = {
url: '/swf/audio_lite.swf?4',
id: guid
}
var params = {
swliveconnect: 'true',
allowscriptaccess: 'always',
wmode: 'opaque'
}
if (renderFlash(wrap, opts, params, {})) {
var swfObj = browser.msie ? window[guid] : document[guid],
inited = false,
checkLoadInt = setInterval(function () {
if (swfObj && swfObj.paused) {
try {
swfObj.setVolume(1);
swfObj.loadAudio(filename + ext);
swfObj.pauseAudio();
} catch (e) {debugLog(e);}
}
inited = true;
clearInterval(checkLoadInt);
}, 300);
self.playSound = function() {
if (!inited) return;
swfObj.playAudio(0);
};
self.pauseSound = function() {
if (!inited) return;
swfObj.pauseAudio();
};
}
}
}
Sound.prototype = {
play: function() {
try {this.playSound();} catch(e){}
},
pause: function() {
try {this.pauseSound();} catch(e){}
}
};
when i try to add injection with redeclaration function Sound it doesn't work.
if i create my own function, for example, xSound and сall it this way:
cur.sound = new xSound('mp3/bb1');
it's working.
You can do it like this, for example:
foo = function(args) {
// method body...
}
JavaScript is a programming language where functions are first-class citizens so you can manipulate them like other types.
UPDATE:
Make sure that this piece of code actually does the redefinition and not the first definition. (thanks to #jmort253)
function foo(){
// ..something else here..
}
Remember that an extension's Content Script code and the webpage code run in different execution contexts.
So if you want to redefine a function that exists in the webpage context, you'll have to inject your code into the webpage. Take a look at this answer by Rob W for different methods of doing that:
Insert code into the page context using a content script

JavaScript singleton patterns - differences?

This may seem like a silly question, but what are the functional differences, if any, between these two patterns? Is there no real functional difference and it's just a matter of organization preference? What are some instances when you would want to use one and not the other? I'm trying to find a design pattern I feel most comfortable with. Thanks!
$(function(){
Core.init();
});
var Core = {
init: function() {
//some initialization code here
}
_plugins: function() {
//instantiate some plugins here
}
_display: function() {
//some more code here
}
_otherfunctions: function() {
....
}
}
and
$(function(){
Core.init();
Plugins.init();
Display.init();
});
var Core = {
init: function() {
//some initialization code here
}
}
var Plugins = {
init: function() {
//start plugins
}
_modify: function() {
//more code
}
}
var Display = {
init: function() {
//some init code
}
}
The main organizational difference is that the first pattern pollutes the global namespace less.
If you do want to separate your code into packages like in the second example, then the better way, within your example, would be:
$(function(){
Core.init();
});
var Core = {
init: function() {
//some initialization code here
},
plugins: {
init: function() {
//start plugins
}
_modify: function() {
//more code
}
},
display: {
init: function() {
//some init code
}
}
}
and refer to the packages through your main namespace:
Core.plugins.init();
I am not saying that this is the best way to do so in general (some of it is a matter of preference, like private members and methods), but in your example - I'd prefer mine.
Have a look at this framework I have built. Seems to work pretty well.
var gtg = gtg || {};
(function () {
var _this = this;
this.registerNamespace = function (namespace) {
var root = window,
parts = namespace.split("."),
i;
for (i = 0; i < parts.length; i++) {
if (typeof root[parts[i]] === "undefined") {
root[parts[i]] = {};
}
root = root[parts[i]];
}
return this;
};
}).call(gtg);
// Register Namespaces
gtg.registerNamespace("gtg.core");
gtg.registerNamespace("gtg.infoBar");
gtg.registerNamespace("gtg.navBar");
gtg.registerNamespace("gtg.tabBar");
gtg.registerNamespace("gtg.utils");
(function () {
var _this = this;
this.initialize = function () { };
}).call(gtg.core);
(function () {
var _this = this,
$container,
$messageContainer,
$message;
function configureMessage(message) {
var className = "info",
types = ["error", "info", "warning"];
for (var i in types) {
$message.removeClass(types[i]);
}
switch (message.MessageType) {
case 0:
className = "error"
break;
case 1:
className = "info"
break;
case 2:
className = "warning"
break;
}
$message.addClass(className).html(message.Message);
}
this.initialize = function () {
$container = $(".info-bar-container");
$messageContainer = $container.find(".message-container");
$message = $messageContainer.find(".message");
$messageContainer.find(".close a").bind("click", function () {
_this.close();
});
};
this.close = function () {
$messageContainer.fadeOut(300, function () {
$container.slideUp(300);
});
};
this.show = function (message) {
if ($container.css("display") !== "none") {
$messageContainer.fadeOut(300, function () {
configureMessage(message);
$messageContainer.fadeIn(300);
});
} else {
$container.slideDown(300, function () {
configureMessage(message);
$messageContainer.fadeIn(300);
});
}
};
}).call(gtg.infoBar);
(function () {
var _this = this;
function initializeNavBar() {
var paths = window.location.pathname.split("/"),
navId;
$("#nav-bar ul.top-nav li a[data-nav]").bind("click", function () {
_this.switchNav($(this));
});
if (paths[1] != "") {
switch (paths[1]) {
case "Customer":
navId = "customers-nav";
break;
case "Order":
navId = "orders-nav";
break;
case "Product":
navId = "products-nav";
break;
case "Report":
navId = "reports-nav";
break;
case "Tool":
navId = "tools-nav";
break;
}
if (navId != "") {
_this.switchNav($('#nav-bar ul.top-nav li a[data-nav="' + navId + '"]'));
}
} else {
_this.switchNav($('#nav-bar ul.top-nav li a[data-nav="home-nav"]'));
}
}
this.initialize = function () {
initializeNavBar();
};
this.switchNav = function (navItem) {
$("#nav-bar ul.top-nav li a[data-nav]").each(function (i) {
$(this).removeClass("selected");
$("#" + $(this).data("nav")).hide();
});
navItem.addClass("selected");
$("#" + navItem.data("nav")).show();
};
}).call(gtg.navBar);
(function () {
var _this = this;
this.initialize = function () {
$(".tab-bar ul li a[data-tab-panel]").bind("click", function () {
_this.switchTab($(this));
});
};
this.switchTab = function (tab) {
$(".tab-bar ul li a[data-tab-panel]").each(function (i) {
$(this).removeClass("selected");
$("#" + $(this).data("tab-panel")).hide();
});
tab.addClass("selected");
$("#" + tab.data("tab-panel")).show();
};
}).call(gtg.tabBar);
(function () {
var _this = this;
this.focusField = function (fieldId) {
$("#" + fieldId).select().focus();
};
this.loadJQTemplate = function (templateName, callback) {
$.get("/Content/JQTemplates/" + templateName + ".html", function (template) {
callback(template);
});
};
}).call(gtg.utils);
$(document).ready(function () {
gtg.core.initialize();
gtg.infoBar.initialize();
gtg.navBar.initialize();
gtg.tabBar.initialize();
});

error when using AJAX in vm mynxx template by rockettheme in virtuemart /Joomla

I am getting error when using the script below in vm mynxx template by rockettheme in virtuemart Joomla 1.5 -
It works fine outside of mynxx
User inputs data into a html form- presses "Get Price" button and a price is returned to same form. Problem is that user is unable to submit to cart
firebug error -
callback is not a function callback(this.responseText);
my ajax script
function Ajax() {
this.instance = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
this.request = function(url, callback) {
this.instance.open('GET', url, true);
this.instance.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
callback(this.responseText);
}
}
this.instance.send(null);
}
}
function validate(form) {
(new Ajax).request('testform.php?width65=' + form.width65.value + '&length65=' + form.length65.value, function(respons) {
var prices = eval(respons);
form.price.value = prices[0];
form.otherprice.value = prices[1];
});
}
I think I have tracked the file down to theme.js and require some code to validate the function.
I am new at this and this is way above me - any help would be appreciated
Theme.js code - was packed - ie eval(function(p,a,c,k,e,r){e=function(c)...... I have unpacked it
var RokVM = {};
RokVM.autoHide = 3; // seconds before auto closing the Panel
RokVM.Base=
{
uri:window.templatePath,start:function()
{
RokVM.Base.quantityBox();
RokVM.Cart.init()
}
,featuredHeight:function(b)
{
b=$(b);
if(!b)
{
return RokVM.Base
}
var c=b.getElements(".home-featured-inner");
var d=0;
c.each(function(a)
{
d=Math.max(a.getSize().size.y,d)
}
);
c.setStyle("height",d)
}
,quantityBox:function()
{
var h=$$(".cart-quantity-box, .home-featured-cartblock");
if(h.length)
{
h.each(function(b)
{
var c=b.getElement(".quantity_box_button_up");
var d=b.getElement(".quantity_box_button_down");
var f=b.getElement(".inputboxquantity");
if(!c||!d||!f)
{
return
}
var g=f.getValue().toInt();
f.addEvent("keyup",function(e)
{
e=(new Event(e)).stop();
var a=this.value;
if(a<0)
{
a=0
}
if(isNaN(a))
{
this.value=1;
a=1
}
if(e.key=="up")
{
if($type(this.getValue().toInt())=="number")
{
this.value=++a
}
}
if(e.key=="down")
{
if(a>0&&$type(this.getValue().toInt())=="number")
{
this.value=--a
}
}
}
);
f.addEvent("mousewheel",function(e)
{
e=(new Event(e)).stop();
var a=this.value;
if(a<0)
{
a=0
}
if(isNaN(a))
{
this.value=1;
a=1
}
if(e.wheel==1)
{
if($type(this.getValue().toInt())=="number")
{
this.value=++a
}
}
if(e.wheel==-1)
{
if(a>0&&$type(this.getValue().toInt())=="number")
{
this.value=--a
}
}
}
);
c.addEvent("click",function(e)
{
(new Event(e)).stop();
if($type(f.getValue().toInt())=="number")
{
f.value=++f.value
}
}
);
d.addEvent("click",function(e)
{
(new Event(e)).stop();
if(f.getValue().toInt()>0&&$type(f.getValue().toInt())=="number")
{
f.value=--f.value
}
}
)
}
)
}
}
};
RokVM.Cart=
{
init:function()
{
RokVM.Cart.cartPanel=$("cart-panel");
RokVM.Cart.cartButton=$("cart-button");
RokVM.Cart.cartSurround=$("cart-panel-surround");
if(!RokVM.Cart.cartPanel||!RokVM.Cart.cartButton||!RokVM.Cart.cartSurround)
{
return RokVM.Cart
}
if(!RokVM.Cart.Fx)
{
RokVM.Cart.Fx=(new(Fx.Slide)(RokVM.Cart.cartPanel,
{
duration:400,transition:Fx.Transitions.Expo.easeOut
}
)).hide()
}
RokVM.Cart.cartSurround.setStyle("visibility","visible");
RokVM.Cart.cartButton.getFirst("a").addEvent("click",function(e)
{
(new Event(e)).stop();
if(!RokVM.Cart.cartPanel.getText().length&&!window.webkit)
{
return
}
if(!RokVM.Cart.cartPanel.innerHTML.clean().length&&window.webkit)
{
return
}
var a=RokVM.Cart.cartButton.getElement("strong");
if(!a||!a.getText().toInt()&&(!RokVM.Cart.cartPanel.getText().length&&!window.webkit))
{
return
}
RokVM.Cart.clicked=true;
if(window.fontFx&&window.fontFx.open)
{
window.fontFx.toggle()
}
if(window.loginFx&&window.loginFx.open)
{
window.loginFx.toggle()
}
RokVM.Cart.Fx.toggle()
}
);
RokVM.scrollWindow=new(Fx.Scroll)(window);
RokVM.Cart.getShortList();
RokVM.Cart.XHRify()
}
,XHRify:function()
{
var b=$$(".addtocart_form");
if(!b.length)
{
return RokVM.Cart
}
b.each(function(a)
{
a.addEvent("submit",RokVM.Cart.add.bindWithEvent(a,true))
}
)
}
,add:function(e,c)
{
(new Event(e)).stop();
(new Ajax(this.getProperty("action"),
{
data:$(this),evalScripts:true,onComplete:function(r)
{
var a=new Element('div').setHTML(r);
var b=a.getElement('.shop_tip');
RokVM.Cart.getShortList((r.length&&b)?r:false);
RokVM.Cart.clicked=c||false
}
}
)).request()
}
,getShortList:function(b)
{
var c=
{
onComplete:function(a)
{
RokVM.Cart.update(a,b)
}
,evalScripts:true,data:
{
only_page:1,page:"shop.basket_short",option:"com_virtuemart"
}
};
(new Ajax(RokVM.Base.uri+"index2.php",c)).request()
}
,handleError:function(a)
{
var b=RokVM.Cart.cartPanel;
var c=new Element('div').setHTML(a);
var d=b.getElement('.show-cart-button');
var e=c.getElement('.shop_tip').inject((d)?d:b,(d)?'before':'inside')
}
,update:function(a,b)
{
RokVM.Cart.cartPanel.setHTML(a);
var c=RokVM.Cart.cartPanel.getElement(".total_products"),total=0;
if(c)
{
total=c.innerHTML.split(" ")[0].toInt()
}
if(!total)
{
RokVM.Cart.cartButton.getFirst().setProperty("class","cart-button-desc")
}
else
{
RokVM.Cart.cartButton.getFirst().setProperty("class","cart-button-desc-full")
}
RokVM.Cart.cartButton.getElement("strong").setText(total);
if(b)RokVM.Cart.handleError(b);
if(RokVM.Cart.clicked&&a.length||b)
{
if(window.fontFx&&window.fontFx.open)
{
window.fontFx.toggle()
}
if(window.loginFx&&window.loginFx.open)
{
window.loginFx.toggle()
}
RokVM.scrollWindow.toTop();
RokVM.Cart.show();
RokVM.Cart.hide.delay(RokVM.autoHide*1000)
}
RokVM.Cart.clicked=false
}
,show:function()
{
RokVM.Cart.Fx.slideIn()
}
,hide:function()
{
RokVM.Cart.Fx.slideOut()
}
};
window.addEvent("domready",RokVM.Base.start);
window.addEvent(window.webkit?"load":"domready",function()
{
RokVM.Base.featuredHeight("home-featured")
}
);
var live_site = RokVM.Base.url;
Then following - this in the same theme.js file (this is not packed)
/// Following is VM stuff, kept for compatibility
/**
* This file holds javascript functions that are used by the templates in the Theme
*
*/
// AJAX FUNCTIONS
function loadNewPage( el, url ) {
var theEl = $(el);
var callback = {
success : function(responseText) {
theEl.innerHTML = responseText;
if( Lightbox ) Lightbox.init();
}
}
var opt = {
// Use POST
method: 'get',
// Handle successful response
onComplete: callback.success
}
new Ajax( url + '&only_page=1', opt ).request();
}
function handleGoToCart() { document.location = live_site + '/index.php?option=com_virtuemart&page=shop.cart&product_id=' + formCartAdd.product_id.value ; }
function handleAddToCart( formId, parameters ) {
formCartAdd = document.getElementById( formId );
var callback = function(responseText) {
updateMiniCarts();
// close an existing mooPrompt box first, before attempting to create a new one (thanks wellsie!)
/*if (document.boxB) {
document.boxB.close();
clearTimeout(timeoutID);
}
document.boxB = new MooPrompt(notice_lbl, responseText, {
buttons: 2,
width:400,
height:150,
overlay: false,
button1: ok_lbl,
button2: cart_title,
onButton2: handleGoToCart
});
setTimeout( 'document.boxB.close()', 3000 );*/
}
var opt = {
// Use POST
method: 'post',
// Send this lovely data
data: $(formId),
// Handle successful response
onComplete: callback,
evalScripts: true
}
new Ajax(formCartAdd.action, opt).request();
}
/**
* This function searches for all elements with the class name "vmCartModule" and
* updates them with the contents of the page "shop.basket_short" after a cart modification event
*/
function updateMiniCarts() {
var callbackCart = function(responseText) {
carts = $$( '.vmCartModule' );
if( carts ) {
try {
for (var i=0; i<carts.length; i++){
carts[i].innerHTML = responseText;
try {
color = carts[i].getStyle( 'color' );
bgcolor = carts[i].getStyle( 'background-color' );
if( bgcolor == 'transparent' ) {
// If the current element has no background color, it is transparent.
// We can't make a highlight without knowing about the real background color,
// so let's loop up to the next parent that has a BG Color
parent = carts[i].getParent();
while( parent && bgcolor == 'transparent' ) {
bgcolor = parent.getStyle( 'background-color' );
parent = parent.getParent();
}
}
var fxc = new Fx.Style(carts[i], 'color', {duration: 1000});
var fxbgc = new Fx.Style(carts[i], 'background-color', {duration: 1000});
fxc.start( '#222', color );
fxbgc.start( '#fff68f', bgcolor );
if( parent ) {
setTimeout( "carts[" + i + "].setStyle( 'background-color', 'transparent' )", 1000 );
}
} catch(e) {}
}
} catch(e) {}
}
}
var option = { method: 'post', onComplete: callbackCart, data: { only_page:1,page: "shop.basket_short", option: "com_virtuemart" } }
new Ajax( live_site + '/index2.php', option).request();
}
/**
* This function allows you to present contents of a URL in a really nice stylish dhtml Window
* It uses the WindowJS, so make sure you have called
* vmCommonHTML::loadWindowsJS();
* before
*/
function fancyPop( url, parameters ) {
parameters = parameters || {};
popTitle = parameters.title || '';
popWidth = parameters.width || 700;
popHeight = parameters.height || 600;
popModal = parameters.modal || false;
window_id = new Window('window_id', {className: "mac_os_x",
title: popTitle,
showEffect: Element.show,
hideEffect: Element.hide,
width: popWidth, height: popHeight});
window_id.setAjaxContent( url, {evalScripts:true}, true, popModal );
window_id.setCookie('window_size');
window_id.setDestroyOnClose();
}
I dont really know this template but in my opinion function callback() is something that should be specified in it's code to make an reaction when there is a positive response from the server (HTTP 200), so can you also give us:
that function
it's localization (ie. if it is located in the same file or not)
and when it's loaded to the DOM: before or after function Ajax() {}

restricting input tags to maximum 5

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);

Categories