use parameter from function in a js.match(/(^|\s)here-\S+/g) - javascript

I got this to work as expected by hard-coding the class prefix directly into the match():
(function($){
jQuery.fn.extend({
removePrefixClass:function(classPrefix){
$(this).removeClass(function(index, css){
return(css.match(/(^|\s)notice-\S+/g) || []).join(' ');
});
}
});
})(jQuery);
How can I put the function parameter classPrefix inside the match()?
The usage in this case would be $(this).removePrefixClass('notice-') in order to remove any class that is named notice-success, notice-error, notice-warning so on and so forth...
I've seen some answers here where the use of RegExp is suggested. But can't seem to figure it out how to use it in my scenario.
Here is the part of the code where it's in use:
(/* ajax request* / > .done > if there's an existing #notice)
$(function(){
$("form.ajax").submit(function(e){
e.preventDefault();
if($('form[id]').length){ // make sure the form has a unique id
let $form = $('form#'+$(this).attr('id')); // use this specific form
let $formNotice = $form.find('#notice'); // locate #notice element
/* ajax request */
submitAjax($form) // personal wrapper function that just returns an $.ajax({...})-object
.done(function(data,statusText,jqXHR){
if($formNotice.length){ // update existing notice
/*--> */ $formNotice.removePrefixClass('notice-'); // remove class that starts with "notice-"
$formNotice.prependClass('notice-'+data['type']); // add new `notice-`class to the beginning to make it work
$formNotice.find('p').html(data['msg']); // add response message
} else { // set new #notice
$(setNotice(data['type'],data['msg'])).hide().prependTo($form).slideDown("slow"); // personal function that returns the `notice-`-html-element
}
})
.fail(function(){
console.log('fail : '+statusText);
})
.always(function(){
console.log('always');
});
//
} else {
console.log('form is missing id');
}
});
});

You need to build a RegExp object explicitly, like this:
removePrefixClass: function(classPrefix) {
var re = new RegExp('(^|\s)' + classPrefix + '\S+', 'g');
$(this).removeClass(function(index, css) {
return(css.match(re) || []).join(' ');
});
}

Related

Not able to call a jQuery function

I am trying to get the file input preview working.
I have a jquery script which works fine when I call the function normally.
$('#images').on("change", previewImages);
This works.
But when I put the call to the same function differently like following
$('#images').on("change", function(){
previewImages();
});
This doesn't work.
I need to write an if else statement to call a different function on else.
Valid question
Reason: this happens because of this which refers to file element when you are using first approach but in case of second approach this is referring to window element in which it is called. So pass this to function and your question is solved.
$('#images').on("change", function(e) {
/* issue is with this */
previewImages(e, this);
});
var count = 0;
function previewImages(evt, cur) {
var $fileUpload = $("input#images[type='file']");
count = count + parseInt($fileUpload.get(0).files.length);
if (parseInt($fileUpload.get(0).files.length) > 7 || count > 6) {
alert("You can only upload a maximum of 6 files");
count = count - parseInt($fileUpload.get(0).files.length);
evt.preventDefault();
evt.stopPropagation();
return false;
}
$("#taskbar").css("height", "auto");
var $preview = $('#preview').empty();
if (cur.files) $.each(cur.files, readAndPreview);
function readAndPreview(i, file) {
// if (!/\.(jpe?g|png|gif|mp4)$/i.test(file.name)){
// return alert(file.name +" is not an image");
// }
var reader = new FileReader();
$('#preview img').addClass('img-responsive');
$(reader).on("load", function() {
$preview.append($("<img/>", {
src: this.result,
height: 100
}));
});
reader.readAsDataURL(file);
}
}
Create a prePreviewImages function, and use that in your first approach. Inside that function, use the if-statement and call previewImages() or your other function.
The following should do..
$('#images').change(function(e) {
if(e == "some condition"){ // if else goes here
previewImages();
}else {
SomeOtherFun();
}
});
Both ways seem to work for me on the JSFiddle. Are you sure it is not a
browser compatibility issue?
If not are you getting errors logged in the console under developer tools?

When using the Microsoft Translator, Is there a way to remove the widget, but retain translation?

I'm using the Microsoft Translation Widget, which I'd like to use to automatically translate a webpage without user interaction.
The problem is, I can't get rid of the widget that keeps popping up or hide it on document.ready because the CSS and JS get loaded from Microsoft's own script in the widget!
Does anyone know a way around this? I've looked everywhere and cannot find a solutuion for this.
Whoa, after some time playing around with that, I've finally achieved what you want.
It's kindda ugly, because of some needed workarounds, but it works, take a look at the fiddle.
The steps were:
Firstly, we must override the default addEventListener behavior:
var addEvent = EventTarget.prototype.addEventListener;
var events = [];
EventTarget.prototype.addEventListener = function(type, listener) {
addEvent.apply(this, [].slice.call(arguments));
events.push({
element: this,
type: type,
listener: listener
});
}
Then, we create a helper function removeEvents. It removes all the event listeners of an element.
var removeEvents = function(el, type) {
var elEvents = events.filter(function(ev) {
return ev.element === el && (type ? ev.type === type : true);
});
for (var i = 0; i < elEvents.length; i++) {
el.removeEventListener(elEvents[i].type, elEvents[i].listener);
}
}
When creating the script tag, in the way Microsoft says:
var s = d.createElement('script');
s.type = 'text/javascript';
s.charset = 'UTF-8';
s.src = ((location && location.href && location.href.indexOf('https') == 0) ? 'https://ssl.microsofttranslator.com' : 'http://www.microsofttranslator.com') + '/ajax/v3/WidgetV3.ashx?siteData=ueOIGRSKkd965FeEGM5JtQ**&ctf=True&ui=true&settings=Manual&from=';
var p = d.getElementsByTagName('head')[0] || d.dElement;
p.insertBefore(s, p.firstChild);
We must add a load event listener to that script, and the code below is fully commented:
s.addEventListener('load', function() {
// when someone changes the translation, the plugin calls the method TranslateArray
// then, we save the original method in a variable, and we override it
var translate = Microsoft.Translator.TranslateArray;
Microsoft.Translator.TranslateArray = function() {
// we call the original method
translate.apply(this, [].slice.call(arguments));
// since the translation is not immediately available
// and we don't have control when it will be
// I've created a helper function to wait for it
waitForTranslation(function() {
// as soon as it is available
// we get all the elements with an attribute lang
[].forEach.call(d.querySelectorAll('[lang]'), function(item, i) {
// and we remove all the mouseover event listeners of them
removeEvents(item, 'mouseover');
});
});
}
// this is the helper function which waits for the translation
function waitForTranslation(cb) {
// since we don't have control over the translation callback
// the workaround was to see if the Translating label is visible
// we keep calling the function, until it's hidden again
// and then we call our callback
var visible = d.getElementById('FloaterProgressBar').style.visibility;
if (visible === 'visible') {
setTimeout(function() {
waitForTranslation(cb);
}, 0);
return;
}
cb();
}
});
Update 1
After re-reading your question, it seems you want to hide all the widgets at all.
So, you must add the following code as soon as the translation is got:
waitForTranslation(function() {
document.getElementById('MicrosoftTranslatorWidget').style.display = 'none';
document.getElementById('WidgetLauncher').style.display = 'none';
document.getElementById('LauncherTranslatePhrase').style.display = 'none';
document.getElementById('TranslateSpan').style.display = 'none';
document.getElementById('LauncherLogo').style.display = 'none';
document.getElementById('WidgetFloaterPanels').style.display = 'none';
// rest of the code
});
I've created another fiddle for you, showing that new behavior.
Update 2
You can prevent the widget showing at all by adding the following CSS code:
#MicrosoftTranslatorWidget, #WidgetLauncher, #LauncherTranslatePhrase, #TranslateSpan, #LauncherLogo, #WidgetFloaterPanels {
opacity: 0!important;
}
And you can even prevent the before-translated text being showed, by hiding the document.body by default, and then showing it when the page is fully translated:
(function(w, d) {
document.body.style.display = 'none';
/* (...) */
s.addEventListener('load', function() {
var translate = Microsoft.Translator.TranslateArray;
Microsoft.Translator.TranslateArray = function() {
translate.apply(this, [].slice.call(arguments));
waitForTranslation(function() {
/* (...) */
document.body.style.display = 'block';
});
}
});
});
Take a look at the final fiddle I've created.
For me, this was the solution:
on your < style > section add this class
.LTRStyle { display: none !important }
Also, if you are invoking the translation widget this way:
Microsoft.Translator.Widget.Translate('en', lang, null, null, TranslationDone, null, 3000);
then add this to your callback (in this example is TranslationDone) function:
function TranslationDone() {
Microsoft.Translator.Widget.domTranslator.showHighlight = false;
Microsoft.Translator.Widget.domTranslator.showTooltips = false;
document.getElementById('WidgetFloaterPanels').style.display = 'none';
};

Fire function on loaded elements with particular class without events

I am using the combination of a data attribute and class name to fire a function to modify the content of the element with the particular class name.
Below function fires at $(document).ready
$('.accessControlled').each(function(){
var accessLevel = parseInt($(this).attr("data-accesslevel"));
if((user.role !== 0) && (accessLevel !== role)){
$(this).remove();
} else {
$(this).removeAttr('data-accesslevel');
$(this).removeClass('accessControlled');
}
});
Now I want to fire this function, on elements returned by ajax calls too.
I know I can bind the functions permanently by jquery on(), live(), delegate(), etc, but which event to use and how to go about it?
Just execute the code above against returned code:
eg:
function doit(obj){
$(obj).each( // rest of your function
}
// ...
$.get(...).done(function(data){
var obj = $(data);
doit(obj);
// rest of your injection
}
Try this:
// obviously user.role and role must be defined for this to work
function access(){
$('.accessControlled').each(function(){
var accessLevel = parseInt($(this).attr("data-accesslevel"));
if((user.role !== 0) && (accessLevel !== role)){
$(this).remove();
}
else{
$(this).removeAttr('data-accesslevel');
$(this).removeClass('accessControlled');
}
});
}
// assign each ajax call to a variable
var ajx1 = $.post({/*object stuff here*/});
// put the ajax variables in an Array
var ajxA = [ajx1, ajx2, ajx3, ajx4, ajx5, ajx6, ajx7];
$.each(ajxA, function(i, v){
v.done(access);
});
There is a function ajaxSuccess in jQuery which can be used to do something after all ajax calls.
$(document).ajaxSuccess(function() {
accessControl.checkAccessControl();
});

jQuery Example: Reseting an input file element in case of non-allowed file-extensions

If someone tries to upload a file with a non-allowed file-extension, this input-file-element should get "reseted".
That is the input-file-element
<input type="file" id="image1">
These are the corresponding jQuery-statements (document is ready) and I get "TypeError: myElement.clone is not a function" (while I am trying this solution here: Clearing <input type='file' /> using jQuery)
$(document).ready(function() {
$('#image1').change(function(event) {
checkExtensions(this.files[0].name, $(this).get());
});
function checkExtensions (fileName, element) {
var myElement = element;
var allowedExtensions = new Array ('pdf','gif','jpg','png');
var currentExtension = fileName.split('.').pop();
if ($.inArray (currentExtension, allowedExtensions) > -1) {
// everythins is OK, further instructions take place
} else {
// reset the file input element
myElement.replaceWith( myElement = myElement.clone( true ) );
}
}
});
You are passing the native DOM element to your function instead of the jQuery object containing the element. Native DOM elements do not have the function clone() (or replaceWith either). Try this instead:
$('#image1').change(function(event) {
checkExtensions(this.files[0].name, $(this)); // note, I removed .get()
});
function checkExtensions (fileName, $element) {
var allowedExtensions = new Array ('pdf','gif','jpg','png');
var currentExtension = fileName.split('.').pop();
if ($.inArray (currentExtension, allowedExtensions) > -1) {
// everything is OK, further instructions take place
} else {
// reset the file input element
$element.replaceWith($element.clone(true).val(''));
}
}
Example fiddle

check to see if word exists in external JSON

I am using tag-it so users can create tags for their posts.
It currently lets them type anything but I have a list of banned words in the form of JSON.
How could i implement this into the tagit plugin so when a users typed word matched one of the banned words it throws up an error.
How can i check to see if ui.tag exists in swearWords.json?
Here is my current code:
$('#methodTags_text').tagit({
availableTags: sampleTags,
tagLimit:3,
maximumInputLength: 10,
fieldName: "item[tags][]",
beforeTagAdded: function(event, ui) {
// if ui.tag exists in swearWords.json
// Then output error
$('#banned_error').html('You can use this word.')
}
});
swearWords.json
["word1","word2","word3","word4","word5"]
using François Wahl answer I managed to get a working solution...
$('#methodTags_text').tagit({
availableTags: sampleTags,
tagLimit:3,
maximumInputLength: 10,
removeConfirmation: true,
fieldName: "item[tags][]",
beforeTagAdded: function(event, ui) {
if (!ui.duringInitialization) {
var word = eventTags_text.tagit('tagLabel', ui.tag);
if($.inArray(word , words) > -1){
$('#banned_error').html('You cant use this word.');
$("#methodTags_url").tagit("removeTagByLabel", word);
} else {$('#banned_error').html('');}
}
}
});
ALSO to get external json in var
var words = (function () {
var words = null;
$.ajax({
'async': false,
'global': false,
'url': "swearWords.json",
'dataType': "json",
'success': function (data) {
words = data;
}
});
return words;
})();
Given the words are in an array you can use jQuery inArray() do this:
var words = ["word1","word2","word3","word4","word5"]
beforeTagAdded: function(event, ui) {
// if ui.tag exists in swearWords.json
// Then output error
var word = "word4"; // I'm assuming you get the word from some control though.
if($.inArray(word , words) > -1){
$('#banned_error').html('You can use this word.')
}
}
DEMO - Checking entered word is in array
Code from DEMO:
<input id="word" type="text"></input>
<button id="checkWord" type="button">Check Word</button>
var words = ["word1","word2","word3","word4","word5"]
$("#checkWord").on("click", function(){
var word = $("#word").val();
if($.inArray(word, words) > -1){
alert("You cannot use this word");
}
});
try this
swearWords.each(function(i,val){
if(ui.tag == val){
$('#banned_error').html("You can't use this word.")
}else{
//do your stuff
}
}
I think, you can use something like this:
beforeTagAdded: function(event, ui) {
if (!this._swearWords) {
// send synchonous XHR to load banned words.
var xhr = null;
if (window.XMLHttpRequest) {
xhr = new window.XMLHttpRequest();
}
else if (window.ActiveXObject) {
xhr = new window.ActiveXObject('Microsoft.XMLHTTP');
}
if (!xhr) {
return;
}
xhr.open('GET', 'swearWords.json', false);
xhr.send(null);
this._swearWords = JSON.parse(xhr.responseText);
}
if (tag in this._swearWords) { // I don't know how to get tag...
// if ui.tag exists in swearWords.json
// Then output error
$('#banned_error').html('You can use this word.')
}
}
It is better and faster to use Object, not Array for definition of banned words.
{'word1': 1, 'word2': 1, 'word3':1}
Then you can use in operator for detection. If you use Array you (or jQuery) have go through array in loop to check existence of the item. Remember that Array.indexOf is not implemented e.g. in IE8.
I am appending solution for cases where you are attaching tagit to class vs. id (as in repeaters i.e search results). When you are attaching to class you have to access tagit within context in order to be able to remove your tag if it fails validation, e.g.
$(".recTags").tagit({
afterTagAdded: function (event, ui) {
if (!ui.duringInitialization) {
// some validation
if (ui.tagLabel.length <= 50) {
$('#tag_error').html('');
// do something
} else {
$('#tag_error').html('Tag "'+ ui.tagLabel +'" is too long [50 character limit].');
ui.tag.parent().tagit("removeTagByLabel", ui.tagLabel);
}
}
}
});
Important piece for me was figuring out how to invoke removeTagByLabel, from which element:
ui.tag.parent().tagit("removeTagByLabel", ui.tagLabel);
I could not use beforeTagAdded event, because ui.tag.parent() does not exist at this point, since tag is not added to the DOM yet, hence check is within afterTagAdded. I am sure there are other ways to do this, but this works for me.

Categories