I'm having trouble with my function. I made a text editor with BBcode.
Its working very well but the cursor always get back to the end of the textarea.
Here is how it works;
var element = document.getElementById('textEdit');
var lastFocus;
$(document.body).on('click','.editBout', function(e) {
e.preventDefault();
e.stopPropagation();
var style = ($(this).attr("data-style"));
// Depending on the button I set the BBcode
switch (style) {
case 'bold':
avS = "[b]";
apS = "[/b]";
break;
}
if (lastFocus) {
setTimeout(function () { lastFocus.focus() }, 10);
var textEdit = document.getElementById('textEdit');
var befSel = textEdit.value.substr(0, textEdit.selectionStart);
var aftSel = textEdit.value.substr(textEdit.selectionEnd, textEdit.length);
var select = textEdit.value.substring(textEdit.selectionStart, textEdit.selectionEnd);
textEdit.value = befSel + avS + select + apS + aftSel;
textEdit = textEdit.value
textEdit = BBcoder(textEdit);
document.getElementById('editorPreview').innerHTML = textEdit;
}
return (false);
});
This last part here triggers the preview event
$(document.body).on('blur', '#textEdit', function() {
lastFocus = this;
});
So i want it to come back to last focus but at a given position computed out of my selection + added bbcode length.
Related
I'm using the 'timeupdate' event listener to sync a subtitle file with audio.
It is working currently, but I'd like to adjust it to where it is just highlighting the corresponding sentence in a large paragraph instead of deleting the entire span and replacing it with just the current sentence. This is the sort of functionality I am trying to replicate: https://j.hn/lab/html5karaoke/dream.html (see how it only highlights the section that it is currently on).
This is made complicated due to timeupdate constantly checking multiple times a second.
Here is the code:
var audioSync = function (options) {
var audioPlayer = document.getElementById(options.audioPlayer);
var subtitles = document.getElementById(options.subtitlesContainer);
var syncData = [];
var init = (function () {
return fetch(new Request(options.subtitlesFile))
.then((response) => response.text())
.then(createSubtitle);
})();
function createSubtitle(text) {
var rawSubTitle = text;
convertVttToJson(text).then((result) => {
var x = 0;
for (var i = 0; i < result.length; i++) {
if (result[i].part && result[i].part.trim() != '') {
syncData[x] = result[i];
x++;
}
}
});
}
audioPlayer.addEventListener('timeupdate', function (e) {
syncData.forEach(function (element, index, array) {
if (
audioPlayer.currentTime * 1000 >= element.start &&
audioPlayer.currentTime * 1000 <= element.end
) {
while (subtitles.hasChildNodes()) {
subtitles.removeChild(subtitles.firstChild);
}
var el = document.createElement('span');
el.setAttribute('id', 'c_' + index);
el.innerText = syncData[index].part + '\n';
el.style.background = 'yellow';
subtitles.appendChild(el);
}
});
});
};
new audioSync({
audioPlayer: 'audiofile', // the id of the audio tag
subtitlesContainer: 'subtitles', // the id where subtitles should show
subtitlesFile: './sample.vtt', // the path to the vtt file
});
So right now, I can dynamically create elements (2 rows of 12 blocks) and when I click on an individual block, I can change the color it as well.
However, I am having two main problems. When I click on the a block to have its color changed, the color picker will pop up beside it, no issues at all. But all the subsequent blocks that I click on, the color picker still pops up beside that first block that was clicked on.
I don't know why this is happening because I do bind the element that was clicked on to the color picker.
My second issue is a minor one but I am unsure of how to go about resolving it: the color picker sometimes appears behind the boxes.
Here is a link to what I have done so far:
http://codepen.io/anon/pen/bwBRmw
var id_num = 1;
var picker = null;
$(function () {
$(document).on('click', ".repeat", function (e) {
e.preventDefault();
var $self = $(this);
var $parent = $self.parent();
if($self.hasClass("add-bottom")){
$parent.after($parent.clone(true).attr("id", "repeatable" + id_num));
id_num = id_num + 1;
//picker = null;
} else {
$parent.before($parent.clone(true).attr("id", "repeatable" + id_num));
id_num = id_num + 1;
//picker = null;
}
});
});
$(".container").on("click", "a", function(e) {
var self = this;
console.log(this.id)
console.log(this)
if(!picker){
console.log("new picker initialized")
picker = new Picker(this)
}
else{
console.log("gets inside else case")
picker.settings = {
parent: this,
orientation: 'right',
x: 'auto',
y: 'auto',
arrow_size: 20
};
//.parent = this;
}
picker.show();
picker.on_done = function(colour) {
$(self).css('background-color',colour.rgba().toString());
picker.hide()
}
e.stopPropagation();
})
I want the buttons to change their color when they're clicked (a darker shade on mousedown and their original color on mouseup) and it works but only on the second click. Why is that? And how can I fix this?
Button id's are 1 through 10 (button1, button2...)
document.getElementById('main').addEventListener('click', function(e) {
var buttonNum = e.target.id.substring(6);
if (e.target.id.substring(0,6) === "button") {
e.target.addEventListener('mousedown', function() {mouseDown(buttonNum)}, false);
e.target.addEventListener('mouseup', function() {mouseUp(buttonNum)}, false);
// trying another way:
// mouseEventHandler(buttonNum);
result.innerHTML = e.target.innerHTML + " was clicked";
}
}, false);
var mouseupColors = ["#CE3737",
"#48935C",
"#FFD454",
"#26567C",
"#FF6528",
"#92898A",
"#AF9FA5",
"#9EA9AA",
"#989788",
"#7C7372"]
var mousedownColors = ["#B52D2D",
"#397A4A",
"#E5BF4B",
"#183F63",
"#E55B24",
"#777071",
"#96888D",
"#879091",
"#7F7E71",
"#635C5B"]
function mouseDown(buttonNum) {
var buttonId = "button" + buttonNum;
document.getElementById(buttonId).style.backgroundColor = mousedownColors[buttonNum - 1];
}
function mouseUp(buttonNum) {
var buttonId = "button" + buttonNum;
document.getElementById(buttonId).style.backgroundColor = mouseupColors[buttonNum - 1];
}
I've also tried creating a function that handles mousedown and mouseup. It has the same result.
var mouseEventHandler = function(buttonNum) {
var buttonId = "button" + buttonNum;
document.getElementById(buttonId).onmousedown = function() {
this.style.backgroundColor = mousedownColors[buttonNum - 1];
};
document.getElementById(buttonId).onmouseup = function() {
this.style.backgroundColor = mouseupColors[buttonNum - 1];
};
};
Here's the fiddle: https://jsfiddle.net/Lj8kyr7e/
mouseup and mousedown events are registered inside click event handler. So the first time the button is clicked, the two events aren't setup yet.
You need to add those events outside of the click handling function. E.g.
https://jsfiddle.net/Lj8kyr7e/6/
Before trying to build something, I would like to determine if it is possible.
Start with a text area which can be pre-populated with text and which the user can add/delete text. Now, There are some small elements to the side. They can either be images or HTML elements such as a button or anchor links, whatever is easier. The user can drag an elements into the text area, and it will be inserted at the mouse cursor location and take up text space by pushing the existing text around it (the nearby element will also remain so the user can drop a second). The elements will remain as an element which can later be dragged elsewhere in the document or outside of the view port in which it will be removed. When the elements are positioned as desired, the location of the elements can be identified through some means (regex, dom, etc) so that they can be replaced with different content.
Line breaks will be needed. Ideally, it will work with jQuery and IE7+, however, the IE7 desire might need to be changed.
I’ve come across the following which are close but not quite.
http://skfox.com/jqExamples/insertAtCaret.html
http://jsbin.com/egefi (reference jQuery Drag & Drop into a Text Area)
http://jqueryui.com/droppable/#method-option
If you think it could be built and you have suggestions where I should start, please advise.
I did something very similar yesterday so why not sharing :)
My goal was to drop elements of text onto my textarea, in the middle of two lines of text while showing an indicator to where it would be dropped. I believe it will be useful to you ! ;)
$(document).ready(function() {
var lineHeight = parseInt($('#textarea').css('line-height').replace('px',''));
var previousLineNo = 0;
var content = $('#textarea').val();
var linesArray = content.length > 0 ? content.split('\n') : [];
var lineNo = 0;
var emptyLineAdded = false;
$('.draggable').draggable({
revert: function(is_valid_drop) {
if (!is_valid_drop) {
$('#textarea').val(content);
return true;
}
},
drag: function(event, ui) {
lineNo = getLineNo(ui, lineHeight);
if (linesArray.length > 0 && previousLineNo != lineNo) {
insertWhiteLine(lineNo, linesArray);
}
previousLineNo = lineNo;
}
});
$("#textarea").droppable({
accept: ".draggable",
drop: function( event, ui ) {
appendAtLine(lineNo, linesArray, ui.draggable.text());
$(ui.draggable).remove();
content = $('#textarea').val();
linesArray = content.split('\n');
if (linesArray[linesArray.length - 1] == '')
linesArray.pop(); //remove empty line
}
});
$('#textarea').on('input', function() {
if (!emptyLineAdded) {
console.log('input !');
console.log($('#textarea').val());
content = $('#textarea').val();
linesArray = content.split('\n');
if (linesArray[linesArray.length - 1] == '')
linesArray.pop(); //remove empty line
}
});
});
//Returns the top position of a draggable element,
//relative to the textarea. (0 means at the very top of the textarea)
function getYPosition(element, lineHeight) {
var participantIndex = $(element.helper.context).index();
var initPos = participantIndex * lineHeight;
var actualPos = initPos + element.position.top;
return actualPos;
}
//Returns the line number corresponding to where the element
//would be dropped
function getLineNo(element, lineHeight) {
return Math.round(getYPosition(element, lineHeight) / lineHeight);
}
//Inserts a white line at the given line number,
//to show where the element would be dropped in the textarea
function insertWhiteLine(lineNo, linesArray) {
$('#textarea').val('');
$(linesArray).each(function(index, value) {
if (index < lineNo)
$('#textarea').val($('#textarea').val() + value + '\n');
});
emptyLineAdded = true;
$('#textarea').val($('#textarea').val() + '_____________\n'); //white line
emptyLineAdded = false;
$(linesArray).each(function(index, value) {
if (index >= lineNo)
$('#textarea').val($('#textarea').val() + value + '\n');
});
}
//Inserts content of draggable at the given line number
function appendAtLine(lineNo, linesArray, content) {
$('#textarea').val('');
$(linesArray).each(function(index, value) {
if (index < lineNo)
$('#textarea').val($('#textarea').val() + value + '\n');
});
$('#textarea').val($('#textarea').val() + content + '\n'); //content to be added
$(linesArray).each(function(index, value) {
if (index >= lineNo)
$('#textarea').val($('#textarea').val() + value + '\n');
});
}
http://www.kars4kids.org/charity/v2/nirangahtml/program_pop/meet_animals.asp
above link,
when I select one of icon at below.
it's change to selected states, but problem is I need to restrict hover effect and further selecting for that Icon . ( since I am using Image changing).
below is the my complete, jquery code.
$(document).ready(function(){
$('#animal_content_text_horse').css("display", "block");
$('#animal_pic_horse_span').css("display", "block");
$('#page_animal_img_horse').css("display", "block");
$('.animal_thumb_link').each(function() {
$(this).click(function(e) {
e.preventDefault();
default_set($(this).attr('id'));
$(".animal_thumb_link").removeClass("thumbselected");
$(this).addClass("thumbselected");
$(".animal_thumb_link").find('img').addClass("imgHoverable");
$(this).find('img').removeClass("imgHoverable");
});
});
// Change the image of hoverable images
$(".imgHoverable").hover( function() {
var hoverImg = HoverImgOf($(this).attr("src"));
$(this).attr("src", hoverImg).hide().fadeIn(0);
}, function() {
var normalImg = NormalImgOf($(this).attr("src"));
$(this).attr("src", normalImg).show();
}
);
function HoverImgOf(filename)
{
var re = new RegExp("(.+)\\.(gif|png|jpg)", "g");
return filename.replace(re, "$1_r.$2");
}
function NormalImgOf(filename)
{
var re = new RegExp("(.+)_r\\.(gif|png|jpg)", "g");
return filename.replace(re, "$1.$2");
}
});
function default_set(obj12){
var arr = ["horse_content", "camel_content", "peacock_content", "goat_content", "donkey_content", "rooster_content", "sheep_content", "alpacas_content", "cynthia_content", "rabbit_content", "cow_content"];
var arr2 = ["../images/horse_thumb.gif", "../images/camel_thumb.gif", "../images/peacock_thumb.gif", "../images/goat_thumb.gif", "../images/donkey_thumb.gif", "../images/rooster_thumb.gif", "../images/sheep_thumb.gif", "../images/alpacas_thumb.gif", "../images/cynthia_thumb.gif", "../images/rabbit_thumb.gif", "../images/cow_thumb.gif"];
for ( var i = 0; i <= arr.length; i++ ) {
if ( arr[ i ] === obj12 ) {
old_url = $("#" + obj12).children('img').attr('src');
new_url = old_url.replace(/thumb/,'thumb_r');
$("#" + obj12).children('img').attr('src',new_url);
}else{
$('#' +arr[ i ]).children('img').attr('src',arr2[ i ]);
}
}
}
function load_page(obj1,obj2,obj3){
/* detect current div if so hide */
current_pagepharadiv = document.getElementById("pagepharadiv_hidden").value;
current_pageheadertext = document.getElementById("pageheadertext_hidden").value;
current_pageimage = document.getElementById("pageimage_hidden").value;
$('#' + current_pagepharadiv).css("display", "none");
$('#' + current_pageheadertext).css("display", "none");
$('#' + current_pageimage).css("display", "none");
image_hover(obj1);
image_hover(obj2);
$('#' + obj3).fadeIn("fast");
//image_hover(obj3);
//$('#' + obj1).fadeIn("fast");
//$('#' + obj2).fadeIn("fast");
document.getElementById("pagepharadiv_hidden").value = obj1;
document.getElementById("pageheadertext_hidden").value = obj2;
document.getElementById("pageimage_hidden").value = obj3;
}
can you please advice guys,
cheers!
It seems to me that you're really making things more complicated than they need to be. Here's how I would implement the page:
Bottom squares as divs, make the images transparent pngs
Change bottom square color using css :hover
Generate the entire top content on the server for each animal in a div: so you have 11 divs one after the other, instead of having to hide/show things in 3 places. In my code example below I assume they have the class animal-content
Add the id of each top div as a html5 data attribute to the corresponding thumb link
This way all you need to do in jQuery is:
$(".animal_thumb_link").click(function() {
var topId = $(this).data("topId");
$(".animal_thumb_link").removeClass("thumbselected");
$(this).addClass("thumbselected");
$(".animal-content").toggle(function() { return this.id === topId; });
});