Upgrage a web component with SVG from MVC/Javascript to Blazor - c#

I need a piece of advice.
We have an existing system based on .Net core/MVC. And we're moving all frontend parts to Blazor. For now we have one part where we're not sure how to better solve the task.
We have a module, which controls rooms. It's a web page which loads an SVG scheme of a floor from the database. Each room in SVG is an < G > element with ID. Like < G room-id="15" >...
In the existing app, we have a javascript code, which runs after the page is loaded and this script appends to each element an "onclick" event with "room-id" parameter.
Also this script changes fill color of the element if there is no "room-id" to show inactive rooms.
Now, we have to move these functions to Blazor. But Blazor can't manipulate DOM directly. We can keep Javascript, of course. But it would be the worst solution.
We're ready to update backend as well. For example, one of our ideas is to use HtmlAgility package, parse SVG (which is XML by fact), and insert CSS class to inactive rooms. By this way we can solve our second problem (Maybe).
With OnClick events the only idea is again to parse SVG inside the Blazor component, and then rebuild the picture with code and add needed events.
But maybe somebody could find a better way to do these tasks.
Thanks a lot!
Dmitry

Finally, how I solved the task.
SVG elemens have options like "onMouseOver", "onClick" and so on.
So, couldn't completely avoid Javascript. But it's now minimal and easy to maintain.
xScheme = XDocument.Parse(roomScheme);
elements = xScheme.Descendants("{http://www.w3.org/2000/svg}g");
foreach (var el in elements)
{
var roomId= el.Attribute("data-room-id")?.Value;
if (roomId!= null)
{
Guid.TryParse(roomId, out var roomGuid);
var room = allRooms.FirstOrDefault(s => s.Id == roomGuid);
if (room != null)
{
el.SetAttributeValue("class", "thover");
el.SetAttributeValue("title", $" ...Hint details ...");
el.SetAttributeValue("data-placement", "top");
el.SetAttributeValue("data-html", "true");
var attr = new XAttribute("onClick", $"window.location.href = '/RoomDetails/{roomGuid}'");
el.Add(attr);
attr = new XAttribute("onMouseover", " $(function() {$('.thover').tooltip();});");
el.Add(attr);
}
else
{
el.SetAttributeValue("class", "inactive");
}
}
}
And then inside Razor part:
#((MarkupString)xScheme.ToString())

Related

React Getting Data Attribute from CSHTML parent element

Brand new to React today so apologies in advance.
I have googled but for whatever reason can't seem to find the answer which I know must be out there!
I'm trying to build a TEST component just to learn.
The component is basically going to consist of a header and a number of name value pairs set out in div blocks. So I'm starting with the header and trying to make the component generic by passing in a data attribute.
I have a cshtml page with this node (solution is a .NET Core MVC project in VS2019):
<div id="detailsHeaderText" data-headerText="Details"></div>
I have set up a jsx file which looks like this:
class Header extends React.Component {
render() {
return (
<div className="col-md-12 col-sm-12"><h5>{document.getElementById("detailsHeaderText").getAttribute("data-headerText")}</h5></div>
);
}
}
ReactDOM.render(<Header />, document.getElementById('detailsHeaderText'));
This works perfectly and returns a header with the word "Details" in it.
I now want to make it generic so I can do this elsewhere on the page:
<div class="detailsHeaderText2" data-id="2" data-headerText="Header2"></div>
<div class="detailsHeaderText3" data-id="3" data-headerText="Header3"></div>
<div class="detailsHeaderText4" data-id="4" data-headerText="Header4"></div>
etc
How can I output the header text based on a data-attribute input?
The idea being that I connect the React render output to the element along the lines of this pseudocode: document.getElementById("detailsHeaderText" + data-id)
I've looked at constructors and super(props) but nothing seems to work as most of the examples are to do with handlers and hence access the event target prop.
I've found many links to passing props between components.
But none for passing in data from the parent element on a cshtml page.
An answer or a pointer to a detailed answer on passing variables into React would be most helpful.
Thanks in advance.
So I'm 12 hours further down the line in terms of learning React and Googling.
And solved the problem.
Working code is:
function Header(props) {
return <div className="col-md-12 col-sm-12"><h5>{props.headertext}</h5></div>;
}
let elems = document.getElementsByClassName("headerText");
function renderToElements(toRender, elements, dataset) {
for (var i = 0; i < elements.length; i++) {
let passText = elements[i].dataset[dataset];
let renderEl = React.createElement(toRender, { headertext: passText })
ReactDOM.render(renderEl, elements[i]);
}
}
renderToElements(Header, elems, 'headertext')
Which renders all dom nodes of the following construct:
<div class="headerText" data-headertext="Details"></div>
It may seem like a pointless exercise to some in terms of what it is achieving but hopefully this may help others in grasping some basics as I/they can now build on this to construct more complex components.

Access item inside Unity sharedassets.assets file programmatically in C# Mono

I'm working on a Cities: Skylines mod and I want to access the sharedassets.assets file(s) the game has in the Data folder programmatically to get a mesh/prefab.
I've found a tool called Unity Assets Bundle Extractor (UABE) and it is able to open up these files and extract the mesh.
Is there a way to extract a mesh from the sharedassets programmatically with C# code like UABE does?
I've looked in the Unity documentation but so far only have seen this page (not sure if relevant): https://docs.unity3d.com/ScriptReference/AssetBundle.LoadFromFile.html
I tried adapting the code from there but I haven't had any success so far, only have had not found error messages
var myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.dataPath, "sharedassets11"));
Is there a way to achieve this? Thanks
Look at the API for AssetBundle.LoadFromFile.
There is a second method AssetBundle.LoadAsset (or alternatively also maybe AssetBundle.LoadAllAssets) you will need:
var myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.dataPath, "sharedassets11"));
if (myLoadedAssetBundle == null)
{
Debug.Log("Failed to load AssetBundle!");
return;
}
var prefab = myLoadedAssetBundle.LoadAsset<GameObject>("NameOfTheAccordingObject");
Instantiate(prefab);
myLoadedAssetBundle.Unload(false);

Moving newly created publishing page to top in MOSS 2007 programmaticaly

I am stuck with this problem for nearly one day now:
In an application, I create a publishing page in code:
PublishingPage newPage = pages.Add(usableName, layout);
newPage.ListItem["Title"] = promoRecord.PromotionName;
newPage.ListItem["Description"] = string.Empty;
newPage.Update();
newPage.CheckIn("First draft");
So far so good. The problem is, I need the newly created page to appear at the top of the navigation. I was naive enough to think something as simple as this:
SPNavigationNodeCollection navigationNodes = pWeb.CurrentNavigationNodes;
SPNavigationNode newNode = null;
foreach (SPNavigationNode node in navigationNodes)
{
if (node.Url.Equals(prefix + newPage.Url, StringComparison.OrdinalIgnoreCase))
{
newNode = node;
}
}
newNode.MoveToFirst(navigationNodes);
would work. It doesn't, because the page is simply not there (in the CurrentNavigationNodes collection).
So I tried with:
newNode = new SPNavigationNode(promoRecord.PromotionName, prefix + newPage.Url);
navigationNodes.AddAsFirst(newNode);
with no luck either - here I got an exception saying that I can't add the page because it's in DRAFT state. Actually, the CurrentNavigation seems to get updated when I go to the frontend management (Manage Content And Structure / Site Administration / Navigation) - and the page appears there. Even if it's in DRAFT mode.
I tried a lot of things with no success... maybe you guys have an idea what I could try?
Thanks a lot in advance!

emulating a browser programmatically in C# / .Net

We would like to automate certain tasks in a website, like having a user 'login', perform some functionality, read their account history etc.
We have tried emulating this with normal POST/GETs, however the problem is that for example for 'login', the website uses javascript code to execute an AJAX call, and also generate some random tokens.
Is it possible to literally emulate a web-browser? For example:
Visit 'www.[test-website].com'
Fill in these DOM items
DOM item 'username' fill in with 'testuser'
DOM item 'password' fill in with 'testpass'
Click' button DOM item 'btnSubmit'
Visit account history
Read HTML (So we can parse information about each distinct history item)
...
The above could be translated into say the below sample code:
var browser = new Browser();
var pageHomepage = browser.Load("www.test-domain.com");
pageHomepage.DOM.GetField("username").SetValue("testUser");
pageHomepage.DOM.GetField("password").SetValue("testPass");
pageHomepage.DOM.GetField("btnSubmit").Click();
var pageAccountHistory = browser.Load("www.test-domain.com/account-history/");
var html = pageAccountHistory.GetHtml();
var historyItems = parseHistoryItems(html);
You could use for example Selenium in C#. There is a good tutorial: Data Driven Testing Using Selenium (webdriver) in C#.
I would suggest to instantiate a WebBrowser control in code and do all your work with this instance but never show it on any form. I've done this several times and it works pretty good. The only flaw is that it makes use of the Internet Explorer ;-)
Try JMeter, it is a nice too for automating web requests, also quite popularly used for performance testing of web sites
Or just try System.Windows.Forms.WebBrowser, for example:
this.webBrowser1.Navigate("http://games.powernet.com.ru/login");
while (webBrowser1.ReadyState != WebBrowserReadyState.Complete)
System.Windows.Forms.Application.DoEvents();
HtmlDocument doc = webBrowser1.Document;
HtmlElement elem1 = doc.GetElementById("login");
elem1.Focus();
elem1.InnerText = "login";
HtmlElement elem2 = doc.GetElementById("pass");
elem2.Focus();
elem2.InnerText = "pass";

How to register a client script resource at the bottom of webpage to enhance loading time

I really hate the way Extender controls, Asp.net script controls that emit javascript all at the top of the web page and just was rethinking of any other way to emit it at the bottom similar to what,
ClientScriptManager.RegisterStartupScript. On looking into this post by DanWahlin i think it is possible but i would have to handle all dirty work of seeing of script is included twice and making sure all necessary scripts are included in order. So my question boils down to this
"I am developing custom controls, Extender controls and i want all my scripts emitted to be at bottom of webpage, What options do you suggest and Why"
Note:
These scripts and also css are embedded as web resources
As long as we are talking about MS AJAX Toolkit there is an option in the Toolkit ScriptManager that is called "LoadScriptsBeforeUI". Setting this to "false" would allow you to get your UI loaded before the scripts, if this is your goal.
I am generally wondering why having scripts in the top of a webpage would bother you, for it is a general practice and you see any impact only if your connection is extremely slow.
AFAIK you have to handle the OnRender part of the page.
I was doing something similar but to move the viewstate of the page for SEO thing
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
System.IO.StringWriter stringWriter = new System.IO.StringWriter();
HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);
base.Render(htmlWriter);
string html = stringWriter.ToString();
int startPoint = -1;
int endPoint = -1;
startPoint = html.IndexOf("<input type=\"hidden\" name=\"__VIEWSTATE\"");
if (startPoint >= 0)
{
endPoint = html.IndexOf("/>", startPoint) + 2;
string viewstateInput = html.Substring(startPoint, endPoint - startPoint);
html = html.Remove(startPoint, endPoint - startPoint);
int FormEndStart = html.IndexOf("</form>") - 1;
if (FormEndStart >= 0)
html = html.Insert(FormEndStart + 1, viewstateInput);
}
}
Maybe you can do the same lokking for script tag. Other way I can thing of is to put a <%=MyVar%> at the end of the page, so you can set it from the code behind, but I guess is too much couplig with the page
Actually speaking you can't with the current implementation of the ajax extender controls. So i managed to rely on client script dependency framework like script.js instead. I did achieve that i wanted.

Categories

Resources