Can I fill a websharper template's hole without knowing its name at compile time - asp.net-core

I am new using WebSharper and I am stuck in the current situation with WebSharper 4:
I have the following html template (some-template.html) :
<div class="container">
<div ws-replace="Content">
</div>
</div>
It defines a content hole with the name Content. Usually, one could fill it using the following in code (F#):
type SomeTemplate = WebSharper.UI.Templating.Template<"some-template.html">
let doc = SomeTemplate().Content(someElements)
In my scenario, I do not know the name of the template and the hole at compile time. Suppose I have a function:
let buildDom(tempalte : string, holeName : string, content : Doc list) : Doc =
let template = WebSharper.UI.Template<tempalte> // (1)
// template.FillHole(holeName, content) (2)
I do not know how to best deal with (1) -- creating the template, and (2) - locating and filling the hole. Reflection comes to mind, but I would like to know if there is a more elegant and performant approach.
A more general question -- is there a good way to have dynamic composition of html-templated sitelets? This is what I am trying to achieve, but if it is alredy done there could be no need to reinvent the wheel. I'd appreciate if you point me to such resources if available as well.

You can pass a dynamic template by passing a string to the constructor:
type SomeTemplate = WebSharper.UI.Templating.Template<"some-template.html">
let doc = SomeTemplate("<div>...</div>").SomeHole("some content").Doc()
but the holes are still typed statically based on the type provider. There is currently no API to implement dynamic holes.
This could be a nice and useful addition though; you should post a suggestion on github.

Related

Composing Programs in the Elm Architecture

Suppose I want to create a webpage with two components, say a Navbar and a Body. These two components do not interact with each other and can be developed independently. So, I have two elm files which have the following components in each of them:
type Model = ...
type Msg = ...
init : (Model, Cmd Msg)
update : Msg -> Model -> (Model, Cmd Msg)
view : Model -> Html Msg
Assumming that they both work fine, how do we compose them to make a program which has both these components?
I tried writing something like this:
type Model = {body : Body.Model , navbar : Navbar.Model}
type Msg = BodyMsg Body.Msg | NavbarMsg Navbar.Msg
view : Model -> Html Msg
view model = div [] [Body.view model.body, Navbar.view model.navbar]
update : Msg -> Model -> (Model, Cmd Msg)
update = ...
The above gets ugly quickly when I try to write this update function. In particular, once I extract the Msg's out of the Cmd's update functions from Navbar.update or Body.update, how do I extract them and feed them back to these functions again? Also, the view function above does not particularly look idiomatic.
What is the elm-architecture recommended way to solve this problem? Is this pattern idiomatic in elm-architecture?
I think #dwaynecrooks covered the technical aspects of the question. But I believe your problem implies a design aspect too.
How to grow Elm code?
As others pointed out: thinking in terms of components will almost certainly take you down a not so appealing path with Elm. (Many people start there. I and my team started there over 2 years ago, and it took us 3 apps/major redesigns to get to a point where I think we can be happy at least about the fundamentals.)
Instead of components, I suggest you should think of your Elm application as a tree. Each node of your tree represents a level of abstraction, and describes the behavior of your application on that level. When you have the feeling that there is too much detail for a given level, you can start thinking about how new, lower levels of abstraction could be introduced as child nodes.
In practice each node is implemented in its own Elm module: parents import their children. You may also consider that you don't have to stick to the usual model/update/view signatures, rather you should focus on the particularities of your app's domain. This is what – in my read – Richard Feldman is doing in his Real World SPA example app. And Evan's Life of a file talk is related to this question too.
The case of navbar + body
Regarding your particular case – it is not a rare case – here is my experience. If we say that our webapp has a navbar and then some body, this is a pretty static description of the app. This kind of description may fit a component based thinking, but it is less helpful if you want to end up with an elegant Elm app.
Instead, it is worth trying to describe the behavior of your app at this level of abstraction, which may sound something like this: The user can select x,y,z items in a navbar. Clicking on those items will affect the item in q way and also affect the body in either a, or b way. He can also click on v in the navbar, which would show a popup or do w, which logs him out of the app.
If you take this description and apply the logic that I described above, you should probably end up with some sort of a design where most of your navbar is described in your highest level of abstraction. This includes items x, y, z, v and behaviors a, b, w. Now, behavior a may mean that a specific, rich page must be displayed, which has its own detailed behavior that is described on a lower level of abstraction, whereas behavior b may mean that based on the selection some content must be loaded, and again the details of this loading process is worked out on a lower level of abstraction. And so on.
When we started approaching the problem this way, it became much more straight forward to find out how to split up logic, and how to deal with special cases.
We realized, for instance, that when someone said that a page wants to display some stuff "in the navbar", what she really meant was that the navbar should collapse (or transform) for a particular page so that page can display it's own header in that area.
Focusing on the app's behavior instead of static content areas helped with this.
Yes, you're on the right path.
In the view you need to use Html.map.
view : Model -> Html Msg
view model =
div []
[ Html.map BodyMsg (Body.view model.body)
, Html.map NavbarMsg (Navbar.view model.navbar)
]
Body.view model.body has type Html Body.Msg which requires us to use Html.map to get the correct type of Html Msg. Similarly for Navbar.view model.navbar.
And, for the update function you'd write it like so:
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
BodyMsg bodyMsg ->
let
(newBody, newCmd) = Body.update bodyMsg model.body
in
{ model | body = newBody } ! [ Cmd.map BodyMsg newCmd ]
NavbarMsg navbarMsg ->
let
(newNavbar, newCmd) = Navbar.update navbarMsg model.navbar
in
{ model | navbar = newNavbar } ! [ Cmd.map NavbarMsg newCmd ]
In the BodyMsg case, newBody has type Body.Model and so we can set the body field in model to it. However, newCmd has type Cmd Body.Msg and so before we can return we need to use Cmd.map to get the correct return type of Cmd Msg.
Similar reasoning can be used for the NavbarMsg case.
Also, the view function above does not particularly look idiomatic.
What bothers you about the view code?
N.B. This answer assumes you're using Elm 0.18.
That's basically the way to go, yes. There is a popular example for a larger SPA in Elm on GitHub. Here can you see the Main.elm that takes care of mapping the messages from each page: https://github.com/rtfeldman/elm-spa-example/blob/master/src/Main.elm
One thing that is missing from your example is the mapping of the message type that is absolutly required. I guess you left that out to have a smaller post, but from my experience that is the actual part where the boilerplate comes in.
However, you should try not to emulate a component approach like React. Just use functions. Separate pages in an SPA are one example where it makes sense to have a dedicatated message type and corresponding functions like you would with a program.
This article explains the general approach of scaling a larger Elm app and also mentions the point about not having dedicated messages for each component.

How do I pull in page's "url path" field, via php, into the theme?

I'm trying to apply the page's url as a <div> id to be able to target some css on each individual page. After some characters cleanup I'm hoping to get <div id="test-page">.
I have tried pulling it in from the object that I get via
ipContent()->getBreadcrumb()
Unfortunately they are all (including one I need) protected and cannot be echoed out.
[urlPath:protected] => test-page/
Is there a function that I've missed and can use to pull that in? Or a proper method of getting it from the object? Cheers.
And of course, as soon as I posted a question I've found the answer:
I could not get the protected value from [urlPath:protected] => test-page/ when doing this:
$a = ipContent()->getBreadcrumb();
$a = $a[0];
$a = $a->urlPath;
Solution: The way you can pull this is is by replacing $a->urlPath with $a->getUrlPath().
It will work for all the elements in object. Like: $a->updatedAt; needs to be $a->getUpdatedAt();

Get variables in Sphinx templates

I can't figure out how to get variables into Sphinx documents via a template. I am certainly making an elementary mistake, but while there is lots of documentation for using Jinja/Flask templates for web service and some documentation for Sphinx using it, I am having trouble doing the following. Maybe it's not possible and I'm barking up the wrong tree, but then this is fairly different from how variables work in general in web (as opposed to doc) templates?
I am working within a much larger project. Suppose in my project's conf.py I make a variable, say
LANGS = ['en', 'de', 'cn']
I know that this works because if I do the docbuild (we have a custom docbuild but I don't think it does anything really crazy other than a customized logger and eating a bunch of 'chatter') with the following line in conf.py
print len(LANGS)
it shows up during the docbuild.
But now of course I want to access this variable in my template. As far as I can tell, we override index.rst with templates/index.html, which inherits from the basic layout.html for Sphinx. And if I do
<p>We have {{ LANGS|len }} languages</p>
I get
We have 0 languages
Now, this is weird, because sometimes I can cause an error in the build by referring to variables not defined (though not consistently), so that somehow it 'knows' that the variable is defined but thinks it has length zero. Or does a "null" variable have length zero automatically?
How do I get this variable defined - or is it not possible?
What I want to do is then do something for each language in the list (make an outside link, in particular), but I figure there is no point in trying {% for %}/{% endfor %} or whatever if I can't get this working. Maybe Sphinx implements only a subset of Jinja?
Anyway, please help!
There are at least two ways to pass variables to a template:
Via html_context:
A dictionary of values to pass into the template engine’s context for all pages. Single values can also be put in this dictionary using the -A command-line option of sphinx-build.
Example:
# conf.py:
html_context = {'num_langs': len(LANGS)}
<!-- template: -->
<p>We have {{ num_langs }} languages</p>
Via the html_theme_options. This requires adding an option to theme.conf (you can create a theme by inheriting from a standard one):
[options]
num_langs = 1
Then you can set num_langs in conf.py via html_theme_options:
html_theme_options = {'num_langs': len(LANGS)}
and use it in a template:
<p>We have {{ theme_num_langs }} languages</p>

Rally print stories with parent feature name in the card generated

I've used Joel Krooswyk's Print All Backlog Story Cards solution for printing all stories in a backlog.
What I'd like to do is to extend this to have each card print the name of the parent feature that the card belongs to so I can print them all up and lay them on a table for a collaborative estimation session.
The issue is, I'm having trouble finding how to do it.
A snippet of his code in question:
queryArray[0] = {
key: CARD_TYPE,
type: 'hierarchicalrequirement',
query: '((Iteration.Name = "") AND (Release.Name = ""))',
fetch: 'Name,Iteration,Owner,FormattedID,PlanEstimate,ObjectID,Description,UserName',
order: 'Rank'
};
I can't seem to find the element to fetch!
Parent was listed on an example queries page(intended for use in the browser query functionality), with Parent.Name containing the actual text but so that hasn't worked - trying to find a reference that is clear about it seems to be eluding me.
I've looked at the type definition located at:
https://rally1.rallydev.com/slm/webservice/v2.0/typedefinition/?fetch=ObjectID&pagesize=100&pretty=true
Going to the hierarchical requirement's type definition from that page indicates it has a Parent field in one form or another.
I'm not even sure that that one will solve what I'm looking at.
A bit stuck, and I'm not sure what I'm trying to do is even possible with the hierarchical requirement object type.
Note: I assume even if I do find it I'll need to add some code to deal parentless stories- not worried about that though, that's easy enough to deal with once I find the actual value.
Many thanks to anyone who can help :)
I modified Joel's app to include PI/Feature's FormattedID to the cards when a story has a parent PI/Feature.
You may see the code in this github repo.
Parent field of a user story references another user story.
If you want to read a parent portfolio item of a user story, which is a Feature object, use Feature attribute or PortfolioItem attribute. Both will work:
if (data[i].PortfolioItem) {
//feature = data[i].PortfolioItem.FormattedID; //also works
//feature = data[i].Feature.Name; //also works
feature = data[i].Feature.FormattedID;
} else {
feature = "";
}
as long as the version of API is set in the code to 1.37 or above (up to 1.43).
PrintStoryCards app is AppSDK1 app.
1.33 is the latest version of AppSDK1.x
1.29, which the app is using is not aware of PortfoilioItems.
PortfolioItem was introduced in Rally in WS API version 1.37.
See API versioning section in the WS API documentation .
If you want to access Portfolio Items, or other features introduced in later versions of WS API up to 1.43 this syntax will allow it.
<script type="text/javascript" src="/apps/1.33/sdk.js?apiVersion=1.43"></script>
This has to be used with caution. One thing that definitely will break is around calculations of timebox start and end dates. That's why many legacy Rally App Catalog apps are still at 1.29.
This is due to changes in API Version 1.30.
Note that this method of setting a more advanced version of WS API for AppSDK1 does not work with v2.0 of WS API.
You should be able to add PortfolioItem to your fetch. Parent is the field used if the parent is a story. PortfolioItem is the field used if the parent is a Feature (or whatever your lowest level PI is).
Then in the results you can just get it like this:
var featureName = (story.PortfolioItem && story.PortfolioItem.Name) || 'None';

How to generate rdoc-style collapsable code sections?

I am creating internal documentation for a C++ project using Doxygen. I am having Doxygen include the source for methods, etc., but this makes the page kind of hard to scan. I'd like it to behave like rdoc and hide the source in a block that is collapsed by default.
I thought that HTML_DYNAMIC_SECTIONS might let me do this, but alas, the changelog says that option only affects diagrams and graphs.
Maybe I could do it by editing the LAYOUT_FILE?
Anyhow, smart people, how can I coerce Doxygen to generate collapsable code sections?
if includ[ing] the source for methods, etc, [...] makes the page kind of hard to scan, why don't you just link to it (SOURCE_BROWSER = YES) instead of including it (INLINE_SOURCES = YES)? this would make the pages easier to scan and faster to load, and the source would still be accessible (at the expense of one more source page load). depends on how often you actually need to access the source, i guess.
that being said, there is a way to generate collapsible code sections (you will have to modify the source and recompile Doxygen, though):
collapsible sections in Doxygen's HTML output are marked with two nested <div>s like so:
<div class="dynheader"><div class="dynsection">
[collapsible section]
</div></div>
included code sections are marked like so: <div class="fragment"><pre class="fragment">...</pre></div>
thus, to make the included code sections collapsible, you have to either
modify the code that generates the <div class="fragment"><pre class="fragment">...</pre></div> to generate <div class="dynheader"><div class="dynsection">...</div></div> (and probably adjust some css), or
change the javascript initDynSections() function that scans and collapses the collapsible sections to recognize <div class="fragment"><pre class="fragment"> as one of them.
the implementation (or going the SOURCE_BROWSER route :)) is left as an exercise for the reader. good luck!
oh, and if you should succeed with a patch, it would be great if you could submit it to dimitri so that he can include it in a future version. thanks!
coming along here using the search engine of my choice i just want to leave a note here that it is not absolutely necessary to modify any doxygen source.
When this question was asked there was probably no possibility to embed pure html using the htmlonly tag but with this in mind one is able to create foldable container sections abusing a function named toggleVisibility
function toggleVisibility(linkObj)
{
var base = $(linkObj).attr('id');
var summary = $('#'+base+'-summary');
var content = $('#'+base+'-content');
var trigger = $('#'+base+'-trigger');
var src=$(trigger).attr('src');
if (content.is(':visible')===true) {
content.hide();
summary.show();
$(linkObj).addClass('closed').removeClass('opened');
$(trigger).attr('src',src.substring(0,src.length-8)+'closed.png');
} else {
content.show();
summary.hide();
$(linkObj).removeClass('closed').addClass('opened');
$(trigger).attr('src',src.substring(0,src.length-10)+'open.png');
}
return false;
}
that is currently available every time the documentation is generated in a file called dynsections.js placed in the documentation root.
Regarding this code one gets to know the conditions to be able to create foldable code from his/her own documentation using Javascript avoiding inner execution faults in this function and preventing further javascript code from being uninterpreted.
dom element with a unique identifier id
another encapsulated dom element with unique identifier id-summary
another encapsulated dom element with unique identifier id-content
another encapsulated dom element with unique identifier id-trigger
the id-trigger element must contain a src attribute with at least 1 character
the class attributes of the main containers do not matter
With theese conditions in mind one can create the following code.
## Fold me
## <div id="example-div">
## <div id="example-div-summary"></div>
## <div id="example-div-content">
## <pre>
## foo
## bar
## </pre>
## </div>
## <div id="example-div-trigger" src="-"></div>
## </div>
## #htmlonly <script type="text/javascript">$("#example-div").ready(function() { toggleVisibility($("#example-div")); });</script> #endhtmlonly
The doxygen code above is used to document bash code using bash-doxygen so it might look a bit different from pure doxygen code. The first part involving the div containers is already described mentioning the conditions to fit the source of the function toggleVisibility and make it executable without any errors adjusting the doxygen comments for our needs.
The unique id prefix used in here is example-div. In line one there is a hyperref link setup to unfold a section using javascript directly in conjunction with some jQuery code.
What's left is the one liner at the end. It contains the jQuery script need to be run to initially fold the specific segment. For the bash-doxygen (and probably other languages) the block needs to be a one liner because of the script's block scope
Normally the contents between \htmlonly and \endhtmlonly is inserted as-is. When you want to insert a HTML fragment that has block scope like a table or list which should appear outside <p>..</p>, this can lead to invalid HTML. You can use \htmlonly[block] to make doxygen end the current paragraph and restart it after \endhtmlonly.
as noticed in the doxygen documentation and a comment below the right marked solution of the stackoverflow answer on including script tags in doxygen documentations.
Thank you for reading.
Hope this helps some people that come along here.