I need to edit the value in an SP Rich Text field via the WinForms web browser control. Most other controls (input tags) are easy to get and we can change the value quite simply. However, not so simple with Rich Text. I headed over to:
http://blog.drisgill.com/2007_05_01_archive.html
and got some ideas. At first, I tried creatign a javascript function and adding it to the page:
function GetRichTextRange(strBaseElementID)
var docEditor=RTE_GetEditorDocument(strBaseElementID);
if (docEditor == null)
{ return; }
var selection = docEditor.selection;
var range = selection.createRange();
return range;
}
However, every time I call this, I always get a null value back. So I tried this instead:
object docEditor = document.InvokeScript("RTE_GetEditorDocument", new object[] { fieldName });
IHTMLDocument2 doc = (IHTMLDocument2)docEditor;
IHTMLSelectionObject selection = doc.selection;
IHTMLTxtRange textRange = (IHTMLTxtRange)selection.createRange();
textRange.pasteHTML(value);
Well, now I am getting an error on the second line: "Unable to cast object of type 'System.DBNull' to type 'mshtml.IHTMLDocument2"
I am not even sure if I am casting to the correct object type anyway, but in any case, it seems what I am getting back from the RTE_GetEditorDocument function is of System.DBNull.
All I want to do is say something like myRichTextHtmlElement.SetAttribute("value", html); but that obviously cannot be done.
To make things worse, I am completely new to javascript and I'm more of a WinForms guy, so my HTML is not exactly hot stuff. Below is the HTML for my RichText field:
<tr>
<td nowrap="true" valign="top" width="190px" class="ms-formlabel">
<h3 class="ms-standardheader">
<nobr>RichText</nobr>
</h3>
</td>
<td valign="top" class="ms-formbody">
<!-- FieldName="RichText"
FieldInternalName="RichText"
FieldType="SPFieldNote"
-->
<span dir="none">
<div class='ms-rtestate-field ms-rtefield' style=''>
<div id='ctl00_m_g_29d60052_5630_4981_8452_850a87a50b56_ctl00_ctl05_ctl07_ctl00_ctl00_ctl04_ctl00_ctl00_TextField_inplacerte_label'
style='display:none'>Rich text editor
</div>
<div class=' ms-rtestate-write ms-rteflags-0'
id='ctl00_m_g_29d60052_5630_4981_8452_850a87a50b56_ctl00_ctl05_ctl07_ctl00_ctl00_ctl04_ctl00_ctl00_TextField_inplacerte'
style='min-height:84px'
aria-labelledby='ctl00_m_g_29d60052_5630_4981_8452_850a87a50b56_ctl00_ctl05_ctl07_ctl00_ctl00_ctl04_ctl00_ctl00_TextField_inplacerte_label'
contentEditable='true' >
<div class="ExternalClassD74B4D64D01941CDB34619757AAA30D8">
<html>
<body>
<h4>A Definition List:</h4>
<dl>
<dt>Coffee</dt>
<dd>Black hot drink</dd>
<dt>Milk</dt>
<dd>White cold drink</dd>
</dl>
</body>
</html>
</div>
</div>
<div style="clear:both;"></div>
</div>
<span dir="ltr">
<input name="ctl00$m$g_29d60052_5630_4981_8452_850a87a50b56$ctl00$ctl05$ctl07$ctl00$ctl00$ctl04$ctl00$ctl00$TextField_spSave"
type="HIDDEN"
id="ctl00_m_g_29d60052_5630_4981_8452_850a87a50b56_ctl00_ctl05_ctl07_ctl00_ctl00_ctl04_ctl00_ctl00_TextField_spSave" />
</span>
</span>
</td>
</tr>
Anyone got any ideas? Thanks!
do you have to use a winforms webbrowser control? One could use whatever html code editor they wanted in a winform and capture the results and use the sharepoint web services or object model(depending on use case) to update the item as an alternative option.
Well, after a lot of pulling hair out, I got the answer and it was simpler than I thought. Once I got the correct HtmlElement (the div with id ".....TextField_inplacerte") then all I needed to do was this:
HtmlElement element = document.GetRichTextFieldCell(fieldName);
if (element != null)
{
element.InnerHtml = value;
element.SetAttribute("value", value);
}
I probably don't need the SetAttribute bit, so I will attempt the same thing later without that line.
Thanks anyway guys. :-)
Related
I am working on a bootstrap environnement with classic asp.
I have a dynamically generated input fields
<input type="number" size="5" name="montantafacturer_<%=irs("INSPECTIONID")%>">
<button onclick="_EVENTSPARAM('events_ajouteralafacturation','<%=irs("INSPECTIONID")%>');">add</button>
There can be up to 100 dynamically generated fields on one page.
The basics are that i should fill the field montantafacturer_<%=irs("INSPECTIONID")%> with a numeric value and click on add to insert value in the database in a postback method
I am wondering if i can insert a javascript code to check if my field is filled rather than getting the field empty error from postback response... to gain time
ie :
<input type="number" size="5" name="montantafacturer_<%=irs("INSPECTIONID")%>">
<button onclick="**IF montantafacturer_<%=irs("INSPECTIONID")%>" IS NOT EMPTY THEN** _EVENTSPARAM('events_ajouteralafacturation','<%=irs("INSPECTIONID")%>');">add</button>
I wonder if this can be done via inline javascript.
Please advise how.
iid = irs("INSPECTIONID")
if iid <> "" then %>
<input type="number" size="5" name="montantafacturer_<%=iid%>">
<button onclick="_EVENTSPARAM('events_ajouteralafacturation','<%=iid%>');">add</button>
<$ end if %>
That way if your recordset is empty, no HTML is output. If you move the IF/THEN to just before the Button tag, then no button will be created for an empty value.
First of all, welcome to StackOverflow
Secondly ... It's been a very long while when I stopped using Classic ASP (more than 15 years ago), it's nice to see that he still has a small place out there :)
Last, but not the least... your question
as you have input and buttons, I'm sure you have a for loop and outside I will assume you have a <form> tag wrapping all inputs and buttons
To accomplish what you're trying to do, and making use of better code techniques, I would most likely end up with something as (and assuming that you can use jQuery to lift a bit of the javascript... let me know if you can't, and I'll re-write without it)
<form action="/yourpage.asp" method="POST">
<table class="table">
<tbody>
<% For ... %>
<tr class="tr-<%=irs("INSPECTIONID")%>">
<td>
<input
type="number"
size="5"
id="montantafacturer_<%=irs("INSPECTIONID")%>"
name="montantafacturer_<%=irs("INSPECTIONID")%>">
</td>
<td>
<button
class="btn"
data-event="events_ajouteralafacturation"
data-input="<%=irs("INSPECTIONID")%>"
>add</button>
</td>
</tr>
<% Next %>
</tbody>
</table>
</form>
<script>
$(function() {
// for every button with class "btn", fire "onButtonClick" fn upon click
$(".btn").on("click", onButtonClick);
});
function onButtonClick(evt) {
evt.preventDefault();
var btn = $(evt.currentTarget); // the clicked button
var btnEvent = btn.data("event");
var btnInput = btn.data("input");
// your logic
var input = $("#montantafacturer_" + btnInput).val();
if(input.length === 0) {
// show the error in any way you prefer
return;
}
// if we reach here, we have data in the input
_EVENTSPARAM(btnEvent, btnInput);
// you can now fire some code to submit the form
// or just this value, or even disable the button while it
// is being used to send the data (prevent double click), etc.
}
</script>
the <tr class="tr-<%=irs("INSPECTIONID")%>"> was a technique that I used back then so I could add a class that would mark that row with another color, to give some feedback to the user that something was happening with that row data, for example
$(".tr-" + btnInput).addClass("updating");
I've also added id to the input to use $("#...") instead of search by name
Small rant on using JS inline
Why would you ever use inline JS? It really isn't practical or readable - highly recommend moving that into an external source.
How to use JS inline (pls don't)
But if there is absolutely no way around for you, you can always just throw all your normal JS code inside an inline event like onclick.
<button onclick="
// this makes me sad
const allInputs = document.querySelectorAll('[name^=montantafacturer_]');
allInputs.forEach(input => {
if (input.value.length > 0 && !isNaN(input.value)) {
// number
} else {
// empty / Not a Number
}
});
">
add
</button>
This is about what you are looking for.
Mentions
Really, don't use inline JS
As pointed out by another user - you may want to use the HTML property required
In a sharepoint site I have the following div that I need to call it. Problem is in SP sites the id is dynamic and it is bad idea to use, but I don't know any other way to call the div?
Any suggestion?
<span dir="none">
<div class='ms-rtestate-field ms-rtefield' style=''>
<div id='_ctl00_TextField_inplacerte_label' style='display:none'>Rich text
editor no & (Title)</div>
<div class=' ms-rtestate-write ms-rteflags-0'
id='_ctl00_TextField_inplacerte' style='min-height:42px' aria-
labelledby='_TextField_inplacerte_label' contentEditable='true' >
<div class="ms-rtestate-field"> no & (Title) field value.
</div>
</div>
<div style="clear:both;"></div></div>
<span dir="ltr">
Try with below line.You can get same also from class name
var divId = $('.ms-rtestate-write').attr('id');
console.log(divId);
Now you can do whatever you want with this Id or you can do same manipulation from class also.
let me know if it solve your problem.If you have multiple parrallel div with this div then let me know i will share it.
One way I used long time back -
$(window).load(function(){
var getDivFromitsPositioninLayout = $(".parent-div-class div:(n)th-child")
})
Got hold of the div based on the layout, but not sure if that fits in your criteria.
I have some HTML that looks like this:
<td class="targetTD">
<a href="http://foo.com">
<span>content</span>
</a>
**Text I want to modify**
<span>more content</span>
</td>
targetTD iterates a dynamic number of times depending on the content being rendered. For each iteration, I need to remove a substring of ": " from the beginning of the code in the text block. Unfortunately it's not in its own element and I don't have the ability to wrap it in a neat and tidy id/class. I did some searching and found some js I thought might do the trick:
<script>
var myString = $('.targetTD').html();
myString = myString.replace(': ','');
$('.targetTD').html(myString);
</script>
But that spits out a console error:
Unable to get property 'replace' of undefined or null reference.
Final Update (Solution)
Thanks to #Vaibhav for coming up with a fix! This script did the trick:
<script type="text/javascript">
$(function() {
$('.targetTD').each(function () {
$(this).html($(this).html().replace(/\:\s/g, ''));
});
});
</script>
Update 1
Thanks to #BenM I was able to stop the error from producing by using the following code:
<script>
$(function() {
$('.targetTD').html(function() { $(this).html().replace(': ', ''); });
});
</script>
Although I now don't get an error message, this still isn't removing the ": " from the text block. Any ideas on why this might be?
Update 2
To provide some SharePoint specifics broadly, in response to a comment from #ElvisLikeBear:
The specific task I'm trying to accomplish is hiding the column name from a grouped by list. In SP2010 this was easy to do by hiding the ms-gb class. In 2013, Microsoft has lumped in the expand/collapse button with this class so hiding it wholesale is not an option. I've successfully hid the span with the column name (in my code above, the span wrapped in the a), but the ": " is unhelpfully still in the text block, and now it's just floating there at the beginning of each category name.
The code is being deployed at the page level as a snippet, using the Script Editor web part.
Brendan, issue with your code is you are replacing the ':' with '' but you are not assigning it to the same td again.
Replace(':','') function replaces only first occurance of ':'.Please follow my code. it will replace all the ':' with ''.
With reference from "targetTD iterates a dynamic number of times depending on the content being rendered"
I assume you need foreach loop to iterate over all the Tds.
Html :-
<table>
<tr>
<td class="targetTD">
<a href="http://foo.com">
<span>content</span>
</a>
Test:Test1
<span>more content</span>
</td>
</tr>
<tr>
<td class="targetTD">
<a href="http://foo.com">
<span>content</span>
</a>
Test:Test1:test2
<span>more content</span>
</td>
</tr>
<tr>
<td class="targetTD">
<a href="http://foo.com">
<span>content</span>
</a>
Test:Test1:test3:test4
<span>more content</span>
</td>
</tr>
</table>
Jquery :-
<script type="text/javascript">
$(function() {
$('.targetTD').each(function () {
$(this).html($(this).html().replace(/\:/g, ''));
});
});
</script>
Script is tested and works fine.
Make sure the DOM is ready:
<script>
$(function() {
$('.targetTD').html(function() { $(this).html().replace(': ', ''); });
});
</script>
Your tag indicates that this is executing on a SharePoint site which is why your code isn't firing. You need to deploy it properly for SharePoint.
You can do this in a solution or feature, or if it's a one page script you should use a script web part (called the Content Editor webpart in SharePoint 2010 and 2007), you could also add a code snippet to the page in SharePoint 2013.
You could also add the script into the tag via SharePoint designer however I do not believe that would be best practice except in some very specific scenarios (however it would be the easiest approach for a non-SharePoint Devleoper).
I am making an HTA wizard using HTML and VB.
This is some VB code that I was given. I need to take the value that SN2 is set to in this and make it appear as the default text in my html code as the computer name.
I'm not sure how to call the VB code to display into my wizard's Computer Name textbox. Is this possible to do?
VB Code
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colBIOS = objWMIService.ExecQuery _
("Select * from Win32_BIOS")
For each objBIOS in colBIOS
MF=objBIOS.Manufacturer
SN=objBIOS.SerialNumber
Next
intCharacters = 7
SN2 = RIGHT(SN, intCharacters)
WScript.Echo SN2
WScript.Echo MF
I tried the above, but I also tried taking all of that, and making a Sub out of it, like so:
Sub SN2
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colBIOS = objWMIService.ExecQuery _
("Select * from Win32_BIOS")
For each objBIOS in colBIOS
MF=objBIOS.Manufacturer
SN=objBIOS.SerialNumber
Next
intCharacters = 7
SN2 = RIGHT(SN, intCharacters)
‘WScript.Echo SN2
'WScript.Echo MF
End Sub
And then I tried to call it in my HTML code by setting value=SN2, using both the above methods. But obviously that just makes the HTML text box show "SN2" every time:
<table cellpadding="0" border=0 style="position:relative; left:1%">
<tr valign=bottom style="text-align:right">
<td class="hideextra">
<img src="comp.png"></img>
<b>New Computer Details</b>
</td>
</table><br>
<table cellpadding="0" border=0>
<tr valign=middle style="text-align:left">
<td>
<b>Computer Name</b><br><br>
</td>
<th style="text-align:left">
<input type=text id="ComputerName" name=ComputerName value=SN2 /><br><br>
</select>
</th>
</table>
I was trying to research a way to set the value to a string set in the VB portion of the script, but wasn't coming up with anything. Is this possible to do?
Please note that this HTA is for use in Windows PE so while I can utilize VB and, as it seems, some JS, there aren't all the packages for using other languages or updated versions like HTML5, etc... *
Update!
By putting the original VB code [first code sequence shown above] in a separate .vbs document, the code runs perfectly and returns the machine name. I was able to call the .vbs from the .hta, but I'm curious as to what it is that makes the code work in a .vbs file, but not in a .hta.
So the machine name comes up in a pop-up window, and that's now working. From here, I want to make the machine name appear in the HTML input box in my .hta, like I originally intended, rather than the pop-up as is now.
You need to wire-up your code to DOM events. You'll want to change SN2 into a Function (instead of a Sub) which returns the computer name, and then call it in the window.load event (or do it all inline)
VBScript has no inherent or intrinsic notion of events (technically neither does Javascript), so the platform designers decided to use a "magic" naming convention to handle events, it's clunky. It uses underscores in names to bind functions/subs to DOM object events, the same way how VB6 worked by binding Button1_Click to the Click event of Button1.
There are other ways of binding event-handlers in IE VBScript, none of them pretty. This is documented here: https://msdn.microsoft.com/en-us/library/ms533023(v=vs.85).aspx
Anyway, you'll want this:
<html>
<head>
<script language="VBScript">
Option Explicit
Sub Window_onload
Dim computerNameStr, wmiService, biosRows, biosRow, serialNumber
computerNameStr = "."
Set wmiService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & computerNameStr & "\root\cimv2")
Set biosRows = objWMIService.ExecQuery("SELECT * FROM Win32_BIOS")
For Each biosRow in biosRows
serialNumber = biosRow.SerialNumber
If Len( serialNumber ) > 0 Then
window.computerName.value = serialNumber
Exit For
End If
Next
End Sub
</script>
</head>
<body>
<input type="text" id="computerName" />
</body>
</html>
I am a bit new to javascript/web programming and I've been having some issues that should probably have simple solutions but that I am having an extreme amount of trouble with. I basically just want to drag text from a cell in one table to a cell in another table. My questions are as follows:
I cannot seem to make anything but an (a href) type link drag and drop. If I try to set the draggable=true option on a div it remains undraggable (in firefox). In my searches, I haven't really seen any fixes for firefox ( i have added css rules for webkit, however).
To work around this, I was trying to drag an (a href) -apologies for parentheses, there is a limit on the amount of link tags i can use - item from one table's cell to a text input field in another table's cell and its default action is to just drag the link. What I'd like it to drag would be the contents of the tag (e.g. for Some Text I'd like it to return "Some Text" or "draggable" or any other customizable text). I have tried handling this in the ondragstart/ondrop events through e.datatransfer.setData("Text", "My Custom Text") and e.datatransfer.getData("Text") however I still receive the same results. Would anybody have any suggestions for this? I have been looking at this for a while and cannot figure it out at all.
Thank you very much in advance for your help.
EDIT: I do not have access to the computer I was using atm but I'll try to get the basic gist of what I was doing across..
onDrop(e){ //onDrop is assigned to the drophandler of a text input field
var text = e.dataTransfer.getData('Text');
this.Text = text;
e.preventDefault();
}
onDragOver(e){
e.preventDefault();
}
onDragStart(e){
e.dataTransfer.setData('Text', 'My String');
}
....
<table>
<tr>
<td><a id="ident" href="#" draggable="true">Text Content</a></td>
</tr>
<table>
<table>
<tr>
<td><input ondrop="onDrop(e)" type="text" /></td>
</tr>
<table>
Here's a complete code sample I did that works, based on your skeleton above:
<html>
<head>
<title>drag and drop example</title>
<script type="text/javascript">
function onDrop(e){
e.preventDefault();
var text = e.dataTransfer.getData("text/plain");
var input = document.getElementById("destination");
input.value = text;
}
function onDragOver(e){
e.preventDefault();
}
function onDragStart(e){
e.dataTransfer.setData("text/plain", event.target.textContent);
}
</script>
</head>
<body>
<table>
<tr>
<td>
<span id="ident" draggable="true" ondragstart="onDragStart(event)">Text Content</span>
</td>
</tr>
<table>
<table>
<tr>
<td>
<input id="destination" ondragover="onDragOver(event)" ondrop="onDrop(event)" type="text" />
</td>
</tr>
<table>
</body>
</html>
Several things to note:
The format you pass to setData and getData needs to be "text/plain" not "Text" (see: http://dev.w3.org/html5/spec/dnd.html#dom-datatransfer-getdata)
You needed to actually call OnDragOver and OnDragStart (perhaps this was just missing from the sample you added from memory)
It would be good to give your input element an ID, as I did, so you can change the value to the dragged item
To read more about this topic, I wrote a blog you may find helpful: A Drag and Drop Planning Board with HTML5