Search for word and highlight with jquery - javascript

I have written a javaScript file in jQuery that provides a search function. I am trying to figure out how to highlight the word aswell. Bellow is the code.
Filter.js:
(function ($) {
// custom css expression for a case-insensitive contains()
jQuery.expr[":"].Contains = jQuery.expr.createPseudo(function(arg) {
return function( elem ) {
return jQuery(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
};
});
function listFilter(header, list, title) {
// header is any element, list is an unordered list, title is any element
// create and add the filter form to the header
// create a button for collapse/expand to the title
var form = $("<form>").attr({"class":"filterform","action":"#"}),
button = $("<input>").attr({"class":"rest", "type":"submit", "value":"Collapse All", "id":"switch"}),
input = $("<input>").attr({"class":"filterinput","type":"text", "placeholder":"Search"});
$(form).append(input).appendTo(header); //add form to header
$(title).append(button); //add button to title
//on click function for collapse/expand all
$("#switch").click(function(){
if($(this).val() == "Collapse All"){
$(".filterinput").val("");
$(this).val("Expand All");
$("div.content div.markdown").parent().parentsUntil(list).hide();
$(list).find("span.path").parentsUntil(list).show();
$(list).find("ul.endpoints").css("display", "none");
}
else{
$(".filterinput").val("");
$(this).val("Collapse All");
$("div.content div.markdown").parent().parentsUntil(list).hide();
$(list).find("span.path").parentsUntil(list).show();
}
});
$(input)
.change( function () {
var filter = $(this).val();
if(filter) {
// this finds a single string literal in div.markdown,
// and hides the ones not containing the input while showing the ones that do
$(list).find("div.content div.markdown:not(:Contains(" + filter + "))").parent().parentsUntil(list).hide();
$(list).find("div.content div.markdown:Contains(" + filter + ")").parent().parentsUntil(list).show();
}
else {
$("div.content div.markdown").parent().parentsUntil(list).hide();
$(list).find("span.path").parentsUntil(list).show();
$(list).find("ul.endpoints").css("display", "none");
}
return false;
})
.keyup( function () {
// fire the above change event after every letter
$(this).change();
});
}
//ondomready
setTimeout(function () {
listFilter($("#header"), $("#resources"), $("#api_info"));
}, 250);
}(jQuery));
The html that I would like to manipulate is being dynamically created by another JS file so I need to manipulate the DOM after it has been completely rendered.. The html that I will be focusing on gets rendered as bellow, specifially the words in (div class="markdown").
Index.html:
<div class="content" id="connectivitypacks_get_connectivitypacks_content">
<h4>Description</h4>
<div class="markdown"><p>Response will return details for the connectivity packs based on the ID.</p>
<h2 id="keywords">Keywords</h2>
<p> foo, bar, helloWorld, java</p>
</div>
</div>

Here is an example that used your markdown.
Create a regex with that word your searching for.
Get the html of your .markdown
replace the word with <span class="marker">"+ word +"</span>. So this creates a span tag around the word your searching for.
Create css to style the word as needed.
function highlight(word) {
var element = $('.markdown');
var rgxp = new RegExp(word, 'g');
var repl = '<span class="marker">' + word + '</span>';
element.html(element.html().replace(word, repl));
}
highlight('details');
.marker {
background-color: yellow;
font-weight: bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="content" id="connectivitypacks_get_connectivitypacks_content">
<h4>Description</h4>
<div class="markdown">
<p>Response will return details for the connectivity packs based on the ID.</p>
<h2 id="keywords">Keywords</h2>
<p>foo, bar, helloWorld, java</p>
</div>
</div>

Have a look at mark.js. It can highlight such search terms in a specific context. In your example the JavaScript would look like:
var searchTerm = $("#theInput").val();
// Search for the search term in your context
$("div.markdown").mark(searchTerm, {
"element": "span",
"className": "highlight"
});
and the CSS part:
span.highlight{
background: yellow;
}

Related

Avoid certain combinations on a Math.random() function

I have to list of words:
<div class="first-word-list">
<span>apple</span>
<span>sea</span>
<span>ship</span>
</div>
<div class="second-word-list">
<span>duck</span>
<span>tale</span>
<span>jewelry</span>
</div>
the client can add any word to these list so it's not only going to be these 6 words.
I'm using a function that when on click event, it changes the word creating a combination between these two lists on this structure:
<div class="first-word"></div><div class="second-word"></div>
$('.first-word').click(function(){
$('.first-word').text($(".first-word-list span").eq(Math.floor(Math.random()*firstWordLength)).text());
});
$('.second-word').click(function(){
$('.second-word').text($(".second-word-list span").eq(Math.floor(Math.random()*firstWordLength)).text());
});
So, if the user clicks on .first-word and on .second-word it displays this:
<div class="first-word">sea</div><div class="second-word">tale</div>
but lets say I want to block/avoid to display the combination of ship and jewelry. Since I'm using a random function and like I wrote before, the word list will grow I need a way to control which words combinations won't be shown. Any idea how to do this?
Update
The client will write the banned combinations on two new custom fields which will output on a new list like this:
<div class="banned-combinations">
<div><span>ship</span><span>jewelry</span></div>
<div><span>apple</span><span>duck</span></div>
</div>
Here is a snippet that allows you to dynamically add words to either list, and to select words from those lists in order to mark them as forbidden combinations. Once you have everything entered as you want to have it, you can click the two random words to have them replaced by a new random word (which could be just the same word again), taking into account the forbidden combinations:
// Allow adding words to either word list:
$(".add-word").on("change keydown", function (e) {
if (e.which && e.which != 13) return;
$(this).before($("<span>").text($(this).val()));
$(this).val('');
});
// Allow selecting words by clicking them
$(".word-list").on("click", "span", function () {
$(".selected", $(this).parent()).removeClass("selected");
$(this).addClass("selected");
showButton();
});
// Allow forbidding pairs of selected words:
$("#forbid").click(function () {
$(".forbidden").append(
$("<div>").append(
$(".selected").removeClass("selected").clone(),
$("<button>").addClass("del").text("Del")
)
);
showButton();
});
// Remove forbidden pair:
$(document).on("click", ".del", function () {
$(this).parent().remove();
});
// Hide/show button depending on whether we have enough selected words:
function showButton() {
$("#forbid").toggle($(".selected").length == 2);
}
// Main algorithm:
$(".random-word").click(function () {
var index = $(this).index(".random-word");
// Get word that is not clicked:
var otherword = $(".random-word").eq(1-index).text();
// Get all words from corresponding list
var words = $("span", $(".word-list").eq(index)).map(function () {
return $(this).text();
}).get();
// Get list of forbidden words that are linked with the other (non-clicked) word
var forbidden = $('.forbidden div').filter(function () {
return $('span', this).eq(1-index).text() == otherword;
}).map(function () {
return $('span', this).eq(index).text();
}).get();
// Derive the list of allowed words, taking all words, filtering out what is forbidden
var allowed = words.filter(function (txt) {
return forbidden.indexOf(txt) == -1;
});
// Pick a random from these allowed words:
$(this).text(allowed.length
? allowed[Math.floor(Math.random() * allowed.length)]
: "(none)"
);
});
showButton();
// *** Upon special request following was added ***
// Algorithm for choosing random pair in one go:
$("#choose").click(function () {
// Get all words from both lists
var words = $(".word-list").get().map(function (list) {
return $("span", list).get().map(function (span) {
return $(span).text();
});
});
// Get list of forbidden words pairs
var forbidden = $('.forbidden div').get().map(function (div) {
return $('span', div).get().map(function (span) {
return $(span).text();
});
});
// Derive the list of allowed pairs, taking all pairs, filtering out what is forbidden
var allowed = words[0].reduce(function (pairs, word) {
// Get list of forbidden second words, given the first word
var exclude = forbidden.filter(function(pair) {
return pair[0] == word;
}).map(function (pair) {
return pair[1]; // extract second word of the pair
});
// Filter all second words, excluding those that are forbidden pairs with first word.
return pairs.concat(words[1].filter(function (word2) {
return exclude.indexOf(word2) == -1;
}).map(function (word2) {
return [word, word2];
}));
}, []);
// Pick a random pair from these allowed pairs:
var randomPair = allowed.length
? allowed[Math.floor(Math.random() * allowed.length)]
: ["(none)", "(none)"];
// Display the pair
$(".random-word").each(function (i) {
$(this).text(randomPair[i]);
});
});
span {margin-left: 2px; margin-right: 2px}
span.selected {background-color: yellow}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<b>First word list:</b>
<div class="word-list">
<span>apple</span>
<span>sea</span>
<span>ship</span>
<input class="add-word" size=10>
</div>
<b>Second word list:</b>
<div class="word-list">
<span>duck</span>
<span>tale</span>
<span>jewelry</span>
<input class="add-word" size=10>
</div>
<button id="forbid">Add combination as forbidden</button><br>
<b>Forbidden combinations:</b>
<div class="forbidden">
</div>
<b>Random Pair (click a word to reselect a random, allowed word):</b>
<div class="random-word">sea</div><div class="random-word">tale</div>
<button id="choose">Random Pick Both</button>
I'm not sure how you want to handle adding banned options but if everything needs to be dynamic then you could always utilize a dictionary (object).
var bannedOptions = {
'ship': {
'jewelry': true
}
};
When you go to check if an option is valid you can simply do something like:
// Here I'm using truthy checks,you can always add a != null
// if you want false or something to be a valid value
if(bannedOptions[word1] && bannedOptions[word1][word2]) {
// It's invalid
} else {
// Valid
}
When you want to add a new invalid option you could
if(!bannedOptions[newWord]) bannedOptions[newWord] = {};
bannedOptions[newWord][invalidWord] = true;
If you wanted to remove an invalid option you could do:
bannedOptions[word1][word2] = false;
or
delete bannedOptions[word1][word2];
Using a dictionary allows you to have super fast checks when you want to see if a combination is invalid.
It's super dynamic so you don't have to worry about indices or anything because the words themselves are keys... and as long as the word is accessed as a string you can have symbols like -,',/, etc. in the words.

Using checkboxes to update UI in realtime

I'm currently in the process of trying to develop a smarter UI for one of my clients. However the only code I can use to develop this 'feature', is pure JS. I have no access to the source HTML or CSS files the only access I have is the ability to inject JavaScript through an external .js file.
I'm not too familiar with JS, but I can work my way around a basic script or two.
Scenario
What we're doing is allowing users to edit PDF Templates online using a software called Core Create. The UI accessed through the browser is quite cluttered and I would like to provide an option to hide and show UI elements <textareas>/<inputs> through the use of checkboxes.
Here is a very basic JS Fiddle that I have built with the
intention of hiding and displaying UI.
The page in question
Above is a screen grab of the page I am working with, on the left you can see the UI and its composition on the right within the 'Inspect Element' tool.
I have come to the conclusion that I need to iterate through the highlighted selection and link them accordingly with seven checkboxes. The result would then be a selection of checkboxes that would hide / display the correct UI element.
The Caveat
In realizing I cannot edit or introduce new HTML I noticed the lack of on-click attributes. So I'm a bit lost on how to invoke the JavaScript I will eventually build.
My Question
With my limited knowledge of JS I don't know how I would iterate though div elements editoraccvar - editoraccvar6 picking out the ones I need to manipulate.
Due to the lack of ID's / Names (I assume it would have to be done using Parent/Child rules somehow, as the classes are widley used by the rest of the UI. I would appreciate a small example demonstrating how I could achieve this, so I can learn from it.
I should clarify, I have already added the checkboxes to the page, I just need to build the JS link between the Checkbox and the UI element I'm attempting to target. You can find all attributes linking to these checkboxes included in the JS Fiddle.
EDIT // A Working Simplified Example;
Due to some confusion I have 'frankensteined' some code together to show the final result I am after. A working example of sorts. The actual result needs to target 7 Checkboxes and 7 Divisions. I'll list thier common properties below.
// This script is already in place and constructed by the system.
// Written inside script tags and located straight after 'editopt1'.
// $(document).ready(function() {
// $('#checkboxopt1').click(function() {
// if ($('#checkboxopt1').val() == 'true') {
// $('#opt1').val('false');
// $('#checkboxopt1').val('false');
// $('#checkboxopt1').prop('checked', false);
// $('#previewrefresh').trigger('click');
// } else {
// $('#opt1').val('true');
// $('#checkboxopt1').val('true');
// $('#checkboxopt1').prop('checked', true);
// $('#previewrefresh').trigger('click');
// };
// });
// });
function exFunction() {
// Check the function is called
console.log("200 : OK");
// grab all elements with the class, .field-summernote
var uiblocks = document.querySelectorAll('.field-summernote');
for (var i = 0; i < uiblocks.length; i++) {
var current = uiblocks[i];
if (current.className.indexOf('editoraccvar') < 0) //not found: -1
return;
// check elements in the array
console.log(current);
// control the elemets in the array.
if (document.getElementById('checkboxopt1').checked) {
uiblocks[0].style.display = 'block'; // display the element
} else {
uiblocks[0].style.display = 'none'; // hide the element
}
}
};
// Trigger the collection the check, and the control.
var x = document.getElementById("checkboxopt1");
x.addEventListener("click", function() {
console.log("Opt");
exFunction();
});
.editoraccvar1 {
width: 300px;
background: #0ff;
padding: .5em;
}
.editoropt1 {
width: 300px;
background: #ff0;
padding: .5em;
}
textarea {
display: block;
width: 95%;
resize: none;
padding: .5em;
}
<!-- I'm trying to hide & show this entire division... -->
<div class="seq-box-form-field field-summernote editoraccvar1 ">
<label for="accvar1">Ground Floor Info</label>
<div class="clearfix"></div>
<textarea id="richaccvar1" name="richaccvar1" class="summernote"></textarea>
<input type="hidden" name="accvar1" id="accvar1" value="" />
</div>
<!-- Using only what the system has supplied. -->
<div class="seq-box-form-field editoropt1 ">
<label for="opt1"><span style="padding-right: 10px; vertical-align: 1px;">Ground Floor </span>
<input type="checkbox" name="checkboxopt1" id="checkboxopt1" value="true" checked="true" />
<input type="hidden" name="opt1" id="opt1" value="true" />
</label>
</div>
Divisions <div class=""></div>
* editoraccvar,
editoraccvar1,
editoraccvar2,
editoraccvar3,
editoraccvar4,
editoraccvar5,
editoraccvar6*
Checkboxes <input id=""></input>
* checkboxopt,
checkboxopt1,
checkboxopt2,
checkboxopt3,
checkboxopt4,
checkboxopt5,
checkboxopt6,*
As far as I can see, your problem boils down to link checkboxes (that seem to have been generated in some way) to "division" parts of your html that you want to hide. Plus, you have to inject javascript code in the page (so I guess the less code the better).
One approach could be as follows:
// Wrap the code in an anonymus function, to avoid clustering the global space.
(function (domElements) {
// This is the callback that will fire when a checkbox is clicked.
function clickCallback() {
// the context of this callback is the DOM element thus we can access its attributes through this.
// extract the checkNumber of the class of the element. This number is the link to the division that we want to hide/show.
var checkNumber = ((/ editoropt(\d*) /).exec(this.className))[1],
checkBox = document.getElementById('checkboxopt' + checkNumber),
division = document.querySelectorAll('.editoraccvar' + checkNumber)[0];
// Hide/show division, update checkBox state.
toggleElements(division, checkBox, window.getComputedStyle(division).display === 'none');
}
function toggleElements(division, checkBox, isShown) {
// Toggle the division (show/hide) accordingly.
division.style.display = isShown ? 'block' : 'none';
// Due to the fact that the event listener is attached to the parent of the checkBox, we need to maintain consistency manually.
checkBox.checked = isShown;
}
// Remove from the array of DOMElements those that aren't checkboxes and add a click event listener to each of them.
domElements
.filter(function (el) {
return el.className.indexOf('editoropt') !== -1;
})
.forEach(function (el) {
el.addEventListener('click', clickCallback, false);
});
// Call the function passing the dom elements with class '.seq-box-form-field' as argument. Checkboxes are contained within them. Also, transform the nodelist
// into a proper array so that methods defined in Array.prototype can be used.
})([].slice.call(document.querySelectorAll('.seq-box-form-field')));
The code is commented and (I think) quite self-explanatory. However, if you have any doubt or want me to elaborate any point further, please, let me know.
Finally, here's the working fiddle.
UPDATE
Same function (more or less) but now it accepts an array of values that will correspond to the initial state of the checkboxes:
(function (domElements, cbState) {
function clickCallback() {
toggleElements(this.className);
}
function toggleElements(className, initialShow) {
var checkNumber = ((/ editoropt(\d*) /).exec(className))[1],
checkBox = document.getElementById('checkboxopt' + checkNumber),
division = document.querySelectorAll('.editoraccvar' + checkNumber)[0],
isShown = initialShow === undefined ? window.getComputedStyle(division).display === 'none' : initialShow;
division.style.display = isShown ? 'block' : 'none';
checkBox.checked = isShown;
}
domElements
.filter(function (el) {
return el.className.indexOf('editoropt') !== -1;
})
.forEach(function (el, index) {
el.addEventListener('click', clickCallback, false);
toggleElements(el.className, cbState[index]);
});
// Initial state of the checkboxes goes in the second parameter. The index in the array correspond to the checkbox position in the page.
})([].slice.call(document.querySelectorAll('.seq-box-form-field')), [false, false]);
Here's the Fiddle to play with. Hope it helps.
The other half of your problem, not addressed in the other answer has to do with events. Generally, adding an "onclick" attribute to the actual HTML is considered bad practice. You can attach event handlers with Javascript.
var a = document.getElementById("checkboxopt1");
a.addEventListener("click", exFunction, false);
See the manual for more info about how to use this.
Looks like that you need the elements that have the class "field-summernote", but not the class "editorbdyvar".
You can use a query selector to get elements by class name using the default tools from Javascript:
var items = document.querySelectorAll('.field-summernote');
for(var i = 0; i<items.length; i++){
var current = items[i];
if( current.className.indexOf('editoraccvar') < 0) //not found: -1
return;
//now you can manipulate the current element
console.log(current);
}
well ... you should either learn javascript, DOM, HTML and CSS or hire an somebody that can do it.
in my opinion the latter would come cheaper.
if not,
here goes something to put in your script.js file.
the checkboxes must have the id="toggleTextareas" respectively id="toggleInputs".
(function isolateScope() {
tryInit();
function tryInit() {
if(document.readyState!="complete"){
setTimeout(tryInit, 100);
}else{
createUI();
init();
}
}
function createUI(){
var div=document.createElement("div");
div.className="addon-floating-toolbar"
div.style.position="fixed";
div.style.zIndex="999999";
div.style.background="#EEE";
div.style.padding="5px";
div.innerHTML='<input type="checkbox" id="toggleTextareas">toggle Textareas<br>'
+'<input type="checkbox" id="toggleInputs">toggle Inputs';
document.body.appendChild(div);
}
function init() {
var tta=document.getElementById("toggleTextareas");
var ti=document.getElementById("toggleInputs");
var textareaVisible=true;
var inputVisible=true;
tta.onclick=toggleTextareas;
ti.onclick=toggleInputs;
function toggleTextareas() {
var elms=document.querySelectorAll("textarea");
textareaVisible=!textareaVisible;
if (textareaVisible) {
show(elms);
}else{
hide(elms);
}
}
function toggleInputs() {
var elms=document.querySelectorAll("input");
inputVisible=!inputVisible;
if (inputVisible) {
show(elms);
}else{
hide(elms);
}
}
function show(collection) {
for (var i = 0; i < collection.length; i++) {
collection[i].style.display="";
}
}
function hide(collection) {
for (var i = 0; i < collection.length; i++) {
collection[i].style.display="none";
}
}
}
})();
let me know if it works,
cheers.
You can traverse all your fields and generate a checkbox that will toggle it open/close for each of your fields. Also set the checkbox label as innerText of the corresponding field.
// Block to be run
generateCheckboxes = function() {
var button = document.getElementById("generateButton");
button.parentNode.removeChild(button);
// grab all elements with the class, .field-summernote
var uiblocks = [].slice.call(document.querySelectorAll('.field-summernote')).filter(function(x) {
return x.className.indexOf('editoraccvar') >= 0
});
if (!uiblocks.length) return;
var chcontainer = document.createElement('div');
chcontainer.style.display = "inline-block";
document.body.insertBefore(chcontainer, document.body.children[0]);
uiblocks.forEach(function(x) {
var cdiv = document.createElement('div');
var clabel = document.createElement('label');
clabel.innerHTML = x.innerText.trim();
var cinput = document.createElement('input');
cinput.type = 'checkbox';
cinput.checked = true;
cinput.onchange = function(ev) {
var checked = this.checked;
x.style.display = checked ? "" : "none";
}
cdiv.appendChild(clabel);
cdiv.appendChild(cinput);
cdiv.appendChild(document.createElement('br'));
chcontainer.appendChild(cdiv);
})
};
#container {
width: 150px;
}
input {
float: left;
}
label {
width: 120px;
display: block;
float: right;
text-align: left;
}
<button onclick="generateCheckboxes()" id="generateButton">Generate Checkboxes</button>
<div id="example" class="field-summernote editoraccvar">
<br/>
<br/>
<span>Zero</span>
<br/>
<textarea></textarea>
</div>
<div id="example1" class="field-summernote editoraccvar1">
<br/>
<br/>
<span>One</span>
<br/>
<textarea></textarea>
</div>
<div id="example2" class="field-summernote">
<br/>
<br/>
<span>Two</span>
<br/>
<textarea></textarea>
</div>
Fiddle

jQuery Custom events for data attribute

I'm building a custom widget system for an app I'm working on. What I want to have happen is the ability for one widget to update another widget by changing out the data attributes value. On page load, the initial data is loaded into this data-attr via PHP and using jQuery to switch out the data after the fact.
For instance, one widget would work as follows:
PHP loads json data into DOM element
jQuery function is passed the elements ID and retrieves data from data-attr and uses it to produce a graph for example
Based on user interaction, another widget sends data to element's data-attr while also firing a custom jQuery event
Initial function gets the new data and updates it's graph
I've started a demo:
// Ranomize Number & Replace Variable
$(function() {
$('#random').click(function(e) {
e.preventDefault();
num = Math.random() + 100;
$('#data').attr('data-receiver', num);
});
});
// Receive Data & Output
$(function() {
var output = $('#output');
var received = $('#data').attr('data-receiver');
output.html(received);
// Not sure what to do next
});
#content {
background: #efefef;
margin: 40px auto;
display: block;
padding: 50px;
width: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="content">
<div id="data" data-receiver="10"></div>
<strong>Output:</strong>
<span id="output"></span>
<br/>
<br/>
Randomize
</div>
But to be honest I'm not sure how to start. I have some code putting a random value into the receiving DOM element, but not sure how to setup the event or write another function to receive and update the #output div.
I'm happy to answer questions or write more code to help better explain my goal. Thanks in advance.
Try utilizing .queue() , .promise() to create a "subscriber" , "publisher" pattern
var output = $("#output");
var process = function process(next) {
// `this`:`#data`
var num = Math.random() * 100;
$(this).data("receiver", num);
return next()
};
var update = function update() {
// `this`:`#data`
$(this).promise("process").then(function(received) {
// `received`:`#data`,
// do stuff with `received`
console.log(received.data("receiver"));
output.html(received.data("receiver"));
received.queue("process", process);
// add `process` to `received` `"process"` queue
console.log(received, received.queue("process"));
});
};
// queue first call to `process`
$("#data").queue("process", process);
$("#random").click(function (e) {
e.preventDefault();
update.call($("#data").dequeue("process"));
});
jsfiddle http://jsfiddle.net/jev4wuej/2/
I prefer to use custom events which allows for the code to be more decoupe and independent of each other.
jsfiddle
JS
var toolbar = {
init: function() {
$('.data-randomizer').click(this.handleRandomizer);
},
handleRandomizer: function() {
var number = Math.random() + 100;
$.event.trigger('update-request.storage-widget', [number]);
}
};
var output = {
init: function() {
$(document).on('updated.storage-widget', this.handleDisplay);
$.event.trigger('data-request.storage-widget', this.handleDisplay);
},
handleDisplay: function(event, number) {
$('.data-output-widget #output').text(number);
},
requestOut: function() {
}
};
var storage = {
init: function() {
$(document).on('update-request.storage-widget', this.handleUpdateRequest);
$(document).on('data-request.storage-widget', this.handleDataRequest);
},
handleUpdateRequest: function(event, number) {
$('.data-storage-widget').attr('data-receiver', number);
$.event.trigger('updated.storage-widget', [number]);
},
handleDataRequest: function(event, callback) {
var number = $('.data-storage-widget').data('receiver');
callback(event, number);
}
};
toolbar.init();
storage.init();
output.init();
HTML
<div id="content">
<div class="data-storage-widget" data-receiver="10"></div>
<div class="data-output-widget">
<strong>Output:</strong>
<span id="output"></span>
</div>
<div class="tool-bar-widget">
Randomize
</div>
</div>

CKEditor 4 shortcode replacement

I'm trying to make a shortcode "plugin" - similar to what Wordpress uses with TinyMce. I'd like user to be able to insert a shortcode (like [gallery id="3"] or [image id="9"]) via a button and then show a placeholder instead of the actual shortcode. I'll put all the code to github once I get it to work.
Current setup
I have a button which inserts html to the editor using insertHtml() like this:
// Custom button code
CKEDITOR.instances['editor_instance_name'].insertHtml '<div class="media-library-gallery">[gallery id=' + gallery_id + ']</div>'
and I've added extraAllowedContent to allow div with the classes I need:
// CKEditor configuration (config.js)
config.extraAllowedContent = 'div(media-library-image,media-library-gallery)';
I managed to replace div.media-library-gallery with an image using the code below:
(function() {
CKEDITOR.plugins.add('media_gallery', {
init: function(editor) {
CKEDITOR.addCss('.media_gallery{background: #f2f8ff url("/assets/gallery.png") no-repeat scroll center center; border: 1px dashed #888; display: block; width:100%; height: 250px;}');
},
afterInit: function( editor ) {
var dataProcessor = editor.dataProcessor;
var dataFilter = dataProcessor && dataProcessor.dataFilter;
dataFilter.addRules({
elements: {
'div': function(element) {
if (element.attributes.class == "media-library-gallery") {
var fakeElement = editor.createFakeParserElement(element, 'media_gallery', 'div', false);
return fakeElement;
}
}
}
})
}
})
})();
The problem
Currently the replacement nests a div inside the paragraph tag:
<p>
<div class="media-library-gallery">[gallery id="5"]</div>
</p>
I don't want to change the enterMode from the default CKEDITOR.ENTER_P but I want to get rid of the surrounding p. Can I do this using insertHtml or write a rule that would do that for me? Any other suggestions are welcome.
I've been digging around http://docs.ckeditor.com/ for a solution/inspiration but had little luck.
A bit late, but try to insert your div as an element:
var element = CKEDITOR.dom.element.createFromHtml('<div class="media-library-gallery">[gallery id=' + gallery_id + ']</div>');
CKEDITOR.instances['editor_instance_name'].insertElement(element);

Get numerical value from parent with id like 'post-1' and use it in jQuery function

I'm trying to figure out the following.
I have following jQuery code:
var as = "";
var bPlay = 0;
audiojs.events.ready(function() {
as = audiojs.createAll();
$(".audiojs .play-pause").click(function() {
var e = $(this).parents(".audiojs").index(".audiojs");
$.each(as, function(t, n) {
if (t != e && as[t].playing) {
as[t].pause()
}
})
bPlay = !bPlay;
if (bPlay == 1) {
$(".bar").each(function(i) {
fluctuate($(this));
});
} else {
$(".bar").stop();
}
})
});
In a nutshell it preforms list of things when someone clicks particular .audiojs instance on a page. 1) checks if there is any other instance playing, if there is pauses it. And if it is playing applies fluctuate function to elements on a page that have class="bar". This is the issue! I don't want to apply it to all .bar's on a page, but only to a specific group that is associated with particular .audiojs instance (the one that is being clicked and is playing).
I thought of the following solution. Each .audiojs instance is inside a div tag that has id like "post-1", "post-2" etc.. where numerical value is post id from database. I can add this numerical id to bar, so it would be like bar-1, bar-2 etc... However after this I'm having issues.
For javascript to work I need to retrieve numerical value from "post-[id]" associated with audiojs instance that is being clicked and than store it somehow, so I can use it like this afterwards
bPlay = !bPlay;
if (bPlay == 1) {
$(".bar-[value retrieved from post-...]").each(function(i) {
fluctuate($(this));
});
} else {
$(".bar-[value retrieved from post...]").stop();
}
Could someone explain to me how it can be achieved?
Honestly, the easiest way would be to stick it in a custom data-* attribute on the <div id="post-X"> element, like so:
<div id="post-1" data-bar="bar-1">...</div>
Then, you said your .audiojs element is inside that <div>, so just go from this inside the event handler to that <div> element (using .closest()) and get the value of it:
var barId = $(this).closest('[id^="post-"]').attr('data-bar');
Then when you need to use it:
$("." + barId).each(function(i) {
fluctuate($(this));
});
Instead of embedding the value in a class or ID, use a data-* attribute:
<div class="audiojs" data-fluctuate-target="bar-1">
<button type="button" class="play-pause">
<!-- ... -->
</button>
</div>
<div class="bar-1">
<!-- ... -->
</div>
In your click event handler, use the following to fluctuate or stop the correct elements:
var fluctuateClass = $(this).closest('.audiojs').attr('data-fluctuate-target');
$('.' + fluctuateClass).each(function () {
if (bPlay == 1) {
fluctuate($(this));
} else {
$(this).stop();
}
});

Categories

Resources