Consider the following HTML:
<div id="block-container">
<div id="some-background"></div>
<div id="text-div">Focus should be here when this HTML goes into the editor</div>
</div>
I want the caret be in the text-div -- more precisely in the first text element -- when it opens in the TinyMCE editor.
There could be a way to add some class like ".default-focused" to such element and set focus based on the class. Is there any other (generalized) way to achieve this?
The reason why I can't go with the ".default-focused" way:
1. It could be huge task to add class considering the amount of data I have and
2. More importantly, user can change the HTML and can remove the class.
Well, if you know in which element the caret is to be placed you may use this short function
// sets the cursor to the specified element, ed ist the editor instance
// start defines if the cursor is to be set at the start or at the end
setCursor: function (ed, element, start) {
var doc = ed.getDoc();
if (typeof doc.createRange != "undefined") {
var range = doc.createRange();
range.selectNodeContents(element);
range.collapse(start);
var win = doc.defaultView || doc.parentWindow;
var sel = win.getSelection();
sel.removeAllRanges();
sel.addRange(range);
} else if (typeof doc.body.createTextRange != "undefined") {
var textRange = doc.body.createTextRange();
textRange.moveToElementText(element);
textRange.collapse(start);
textRange.select();
}
},
Related
I have a div in my html:
.row(id="div_amount")
.col-sm-2
label(for="amount") Amount:
.col-sm-1
input(type="text", name="amount")
which is perfect as I expected. It displays in one line for both elements.
I have a radio button which have an onclick event for toggle the display of this div section.
function div_toggle() {
div_amount = document.getElementById('div_amount');
if (radio_value === 0) {
div_amount.style.display = "block";
} else {
div_amount.style.display = "none";
}
}
However, after click on the radio button, it always displays as two lines.
How could I fix it to always display in one line?
Please take a look at https://stackoverflow.com/help/mcve and try to include a reproducible example.
In bootstrap4, rows are displayed as flex, i.e., "display: flex;". So in your JavaScript if you change it to display as block, the columns within the row would be broken.
You can set its display to flex, like
if (radio_value === 0) {
div_amount.style.display = "flex";
} else {
div_amount.style.display = "none";
}
although setting HTML element styles in JavaScript is considered as bad practice IMO.
I want to get the element through javascript based on attribute value, as per the example I want to get element through attribute "doc-cid" and the value of "doc-cid" is dynamic.
<p align="center" style="font-family:times;" doc-cid="11303">
<font size="2" doc-cid="11304">55</font></p>
<p id="demo">Click the button to change the text of a list item.</p>
<button onclick="myFunction()">Try it</button>
<script>
function myFunction()
{
var list = document.getElementsByTagName("doc-cid=\"11303\"")
alert(list.getAttribute("doc-cid"));
}
</script>
I'll start with a few pointers about your above code, and follow through with a solution.
POINTERS
doc-cid is not a "TagName", it is a custom attribute. hence, your function trying to getElementsByTagName will always fail for "doc-cid".
doc-cid can by dynamic (or not) it doesn't matter. A lookup function will always get the CURRENT DOM value of your element (unless you specifically make it do otherwise).
I suggest you use the new "data-*" attribute in html, it keeps your markup valid (if that is important to you). The use would be as follows:
your content
SOLUTION
function getElementByAttribute (attribute, value, start) {
var start = start || document,
cache, //store found element
i;
function lookup(start) {
// if element has been found and cached, stop
if (cache) {
return;
} else if (start.getAttribute(attribute) === value) { // check if current element is the one we're looking for
cache = start;
return;
} else if (start.childElementCount > 0) { // if the current element has children, loop through those
lookup(start.children[0]);
} else if (start.nextElementSibling) { // if the current element has a sibling, check it
lookup(start.nextElementSibling);
} else {
return;
}
}
lookup(start);
return cache;
}
You simply give the function the attribute name you are looking up, the value you need to match and the starting point of the lookup (if no starting point is specified it'll start at the very beginning of your page (much slower).
Below is an example for your markup:
// you have no easy to get starting point, so we'll traverse the DOM
getElementByAttribute('doc-cid', '11303');
If you want to start at a better node, you can add a wrapper div element and give it id="wrapper" then you could call the function as follows:
var start = document.getElementById('wrapper');
getElementByAttribute('doc-cid', '11303', start);
Hope this helps.
I've got an issue where I'm using template.render to render an array of items based on a html template. Each item in the array also contains another array, that I want to bind to another template, within the parent element for the area. I know I can use a grid layout for groups, but I'm trying to accomplish this another way, so please, no suggestions to use a different control, I'm just curious as to why the following doesn't work correctly.
//html templates
<div id="area-template" data-win-control="WinJS.Binding.Template">
<h1 class="area-title" data-win-bind="innerHTML:title"></h1>
<div class="items">
</div>
</div>
<div id="item-template" data-win-control="WinJS.Binding.Template">
<h2 class="item-title" data-win-bind="innerHTML:title"></h2>
</div>
// JS in ready event
var renderer = document.getElementsByTagName('section')[0];
var area_template = document.getElementById('area-template').winControl;
var item_template = document.getElementById('item-template').winControl;
for (var i = 0; i < areas.length; i++) {
var area = areas.getAt(i);
area_template.render(area, renderer).done(function (el) {
var item_renderer = el.querySelector('.items');
for (var j = 0; j < area.items.length; j++) {
var item = area.items[j];
item_template.render(item, item_renderer).done(function (item_el) {
});
}
});
}
So what should happen, is that after it renders the area, in the "done" function the newly created element (el) gets returned, I'm then finding it's ".items" div to append the items to. However, this appends all the items to the first div created. If it was the last div, it might make more sense due to closures, but the fact it happens on the first one is really throwing me off!
What's interesting, is that if I replace my template render function using document.createElement and el.appendChild, it does display correctly e.g: (in the done of area render)
area_template.render(area, renderer).done(function (el) {
var item = area.items[j];
var h2 = document.createElement('h2');
h2.innerText = item.title;
el.appendChild(h2);
}
although I've realised this is el it is appending it to, not the actual .items div of the el
I'm not quite sure what could be going on here. It appears the value of el is getting updated correctly, but el.querySelector is either always returning the wrong ".items" div or it's getting retained somewhere, however debugging does show that el is changing during the loop. Any insight would be greatly appreciated.
thanks
I've worked out what is going on here. The "el" returned in the render promise is not the newly created element as I thought. It's the renderer and the newly created html together. Therefore el.querySelector('.items') is always bringing back the first '.items' it finds. I must have misread the docs, but hopefully someone else will find this information useful in case they have the same error.
I guess one way around this would be to do item_rendered = el.querySelectorAll('.items')[i] and return the numbered '.items' based on the position in the loop
e.g
for (var i = 0; i < areas.length; i++) {
var area = areas.getAt(i);
area_template.render(area, renderer).done(function (el) {
var item_renderer = el.querySelectorAll('.items')[i];
for (var j = 0; j < area.items.length; j++) {
var item = area.items[j];
var h2 = document.createElement('h2');
h2.innerText = item.title;
item_renderer.appendChild(h2);
}
});
}
in this example its replace the div container with other element but its get the other element from the yui function how can i make same example but with replace two divs in the html
HTML
<div id="demo">
<p><em>Click me.</em></p>
</div>
Script
YUI({ filter: 'raw' }).use("node", function(Y) {
var node = Y.one('#demo p');
var onClick = function(e) {
// e.target === node || #demo p em
var tag = e.target.get('parentNode.tagName');
// e.currentTarget === node
e.currentTarget.one('em').setContent('I am a child of ' + tag + '.');
};
node.on('click', onClick);
});
You mean, You'd like to replace another div or select another div?
In this example, em is selected and then its content is changed by setContent( "your new content" )
You can just select the e.currentTarget (the node or #demo p div) and setHTML() and build your div inside like string for example <div>content<div>, this is just one out of millions of ways to accomplish this.
have a look to this: http://www.jsrosettastone.com/
The WebBrowser control has a property called "IsWebBrowserContextMenuEnabled" that disables all ability to right-click on a web page and see a context menu. This is very close to what I want (I don't want anyone to be able to right-click and print, hit back, hit properties, view source, etc).
The only problem is this also disables the context menu that appears in TextBoxes for copy/paste, etc.
To make this clearer, this is what I don't want:
This is what I do want:
I would like to disable the main context menu, but allow the one that appears in TextBoxes. Anyone know how I would do that? The WebBrowser.Document.ContextMenuShowing event looks promising, but doesn't seem to properly identify the element the user is right-clicking on, either through the HtmlElementEventArgs parameter's "FromElement" and "ToElement" properties, nor is the sender anything but the HtmlDocument element.
Thanks in advance!
have you considered writing your own context menu in javascript? Just listen to the user right clicking on the body, then show your menu with copy and paste commands (hint: element.style.display = "block|none"). To copy, execute the following code:
CopiedTxt = document.selection.createRange();
CopiedTxt.execCommand("Copy");
And to paste:
CopiedTxt = document.selection.createRange();
CopiedTxt.execCommand("Paste");
Source:
http://www.geekpedia.com/tutorial126_Clipboard-cut-copy-and-paste-with-JavaScript.html
NOTE: This only works in IE (which is fine for your application).
I know its not bulletproof by any means, but here is a code sample that should get you started:
<html>
<head>
<script type = "text/javascript">
var lastForm = null;
window.onload = function(){
var menu = document.getElementById("ContextMenu");
var cpy = document.getElementById("CopyBtn");
var pst = document.getElementById("PasteBtn");
document.body.onmouseup = function(){
if (event.button == 2)
{
menu.style.left = event.clientX + "px";
menu.style.top = event.clientY + "px";
menu.style.display = "block";
return true;
}
menu.style.display = "none";
};
cpy.onclick = function(){
copy = document.selection.createRange();
copy.execCommand("Copy");
return false;
};
pst.onclick = function(){
if (lastForm)
{
copy = lastForm.createTextRange();
copy.execCommand("Paste");
}
return false;
};
};
</script>
</head>
<body oncontextmenu = "return false;">
<div id = "ContextMenu" style = "display : none; background: #fff; border: 1px solid #aaa; position: absolute;
width : 75px;">
Copy
Paste
</div>
sadgjghdskjghksghkds
<input type = "text" onfocus = "lastForm = this;" />
</body>
</html>
//Start:
function cutomizedcontextmenu(e)
{
var target = window.event ? window.event.srcElement : e ? e.target : null;
if( navigator.userAgent.toLowerCase().indexOf("msie") != -1 )
{
if (target.type != "text" && target.type != "textarea" && target.type != "password")
{
alert(message);
return false;
}
return true;
}
else if( navigator.product == "Gecko" )
{
alert(message);
return false;
}
}
document.oncontextmenu = cutomizedcontextmenu;
//End:
I hope this will help you Anderson Imes
A quick look at the MSDN documentation shows that none of the mouse events (click, button down/up etc) are supported to be used in your program. I'm afraid its either or: Either disable conetxt menus, or allow them.
If you disable them, the user can still copy & paste using keyboard shortcuts (Ctrl-C, Ctrl-V). Maybe that gives you the functionality you need.
We ended up using a combination of both of the above comments. Closer to the second, which is why I gave him credit.
There is a way to replace the context menu on both the client-side web code as well as through winforms, which is the approach we took. I really didn't want to rewrite the context menu, but this seems to have given us the right mix of control.