Reputation: 2319
I have a string[] containing individual words parsed out of a paragraph of text. I need to display each word in its own cell, and have each cell be assigned a dynamic width based on the word's length. I want to be able to have as many words as possible within the maximum width of each row.
In short, I'm trying to take a given paragraph of text and present it as a series of editable controls in a way which resembles how it might appear as a plain text document, with each word consuming only its required space on each "line".
I first tried using a DataList with RepeatLayout in Table mode and RepeatColumns to a set value of 10, with a Repeater within containing a Label control; this resulted in 10 words per row but each cell with a fixed width.
I've considered using a GridView with a single column which I would cram with as many words (in the form of Label controls) per row as will fit, adding new rows as necessary until the entire paragraph is built.
Could anyone please share an elegant way to do this?
Upvotes: 0
Views: 165
Reputation: 108491
The magic you're looking for is the "contenteditable" attribute. Works in IE, Firefox and Chrome.
I'm not sure what the hell you're doing with this, lmao... but this ought to work:
Your Code Behind:
protected void Page_Load(object sender, EventArgs e)
{
//creating some bogus collection of strings.
string[] parts = { "this", "is", "a", "test", "of", "the", "goofiest", "ui", "ever" };
//bind it to the repeater.
rptr.DataSource = parts;
rptr.DataBind();
//now we'll add them to a JavaScript array we can access client side.
StringBuilder sb = new StringBuilder();
sb.Append("document.stringItems = new Array();");
for (int i = 0; i < parts.Length; i++)
sb.AppendFormat("document.stringItems[{0}] = '{1}';", i, parts[i]);
ScriptManager.RegisterClientScriptBlock(this, GetType(), "someKey", sb.ToString(), true);
}
protected void btnTest_Click(object sender, EventArgs e)
{
//display the result just so we can see it's working.
lblResult.Text = hdnResult.Value;
}
Your .ASPX:
<asp:Repeater ID="rptr" runat="server">
<ItemTemplate>
<span contenteditable="true" style="border: solid 1px;" onkeyup="updateItem(event, <%#Container.ItemIndex%>)">
<%#Container.DataItem%></span>
</ItemTemplate>
</asp:Repeater>
<asp:HiddenField ID="hdnResult" runat="server" />
<asp:Button ID="btnTest" runat="server" Text="Test" OnClick="btnTest_Click" />
<script type="text/javascript" language="javascript">
//<![CDATA[
function updateItem(e, index) {
//get the source element. (magic here for cross browser lameness)
var src;
if(window.event) {
e = window.event;
src = e.srcElement;
}else{
src = e.target;
}
//update our item in our array.
document.stringItems[index] = src.innerHTML;
//update our hidden field.
var s = '';
var space = false;
for (var i = 0; i < document.stringItems.length; i++) {
if (space)
s += ' ';
else
space = true;
s += document.stringItems[i];
}
var hdnResult = document.getElementById('<%=hdnResult.ClientID%>');
hdnResult.value = s;
}
//]]>
</script>
<asp:Label ID="lblResult" runat="server"></asp:Label>
You'll have to add some javascript for the onkeypress too to make sure they're not adding carriage returns or spaces or whatever it is you don't want them putting in... but this is the basic idea.
I hope that helps. Good luck.
Upvotes: 1
Reputation: 17481
I'll start off by saying that, from a user interface perspective, I'm not entirely sure as to why you would need to do this, but if it must be done you'd do something along these lines:
List<List<string>>
List<string>
List<string>
to your List<List<string>>
(which contains your lines)Once this is done, you bind the list o' list to a repeater like this below (pseudo code; might be off a bit):
<asp:Repeater id="rpt1" runat="server">
<ItemTemplate>
<div>
<asp:Repeater id="rpt2" runat="server" DataSource='<%# Container.DataItem %>'>
<ItemTemplate>
<asp:TextBox id="txt1" runat="server" Text='<%# Container.DataItem %>' Width='<%# MyWidthAlgorithm(Container.DataItem) %>'
</ItemTemplate>
</asp:Repeater>
</div>
</ItemTemplate>
</asp:Repeater>
Upvotes: 1
Reputation: 12857
Best way I can think of approaching something like this is to simply use a repeater and float everything left.
<asp:Repeater runat="server" id="rptr">
<ItemTemplate>
<span style="float:left; height:22px; line-height:22px;"><%# Eval("Word") %></span>
</ItemTemplate>
</asp:Repeater>
Upvotes: 0