JSXGraph: Multiple boards with Moodle's Formulas and Stack - moodle

Sometimes it is handy to be able to control the placement of multiple JSXGraph boards on the html page, like on https://jsxgraph.org/wiki/index.php?title=Sine.
I know that it is possible to include more than one board in a Formulas question in Moodle, as described here: https://github.com/jsxgraph/moodleformulas_jsxgraph/blob/master/README.md#insert-more-than-one-board-into-a-question
My question is: Is it possible to gain control over the placement of boards in a Formulas question? And/or is that possible in a STACK question? – Thanks!

With STACK, it is possible to include more than one board into a question. For each JSXGraph block, STACK generates a div with an id stored in the divid variable. The divs for the boards then replace the JSXGraph blocks in the question text.
Board interaction
If you want the boards to interact with each other, you need to write the JavaScript code for the boards in a single JSXGraph block (the JavaScript code in a block is encapsulated). To do so, you should first place an empty JSXGraph block in the question text which will generate the first div with an id of the pattern "stack-jsxgraph-1". Then, you add a second block where you put in the code for the two boards. Since the naming for the divids is basically just counting up a number, you can access the divid for the first board with regular expressions in JavaScript.
Board placement
In order to control the placement, you can use some CSS and HTML. For example you can wrap two JSXGraph blocks in a div and make this div a flexbox with display: flex. The two boards will then align horizontally. You can also use a grid layout.
Example Code
The code for the question text could look like this:
<!-- Wrapper div flexbox -->
<div style="display: flex;">
<!-- Empty JSXGraph block for the first board-->
[[ jsxgraph width="200px" height="200px"]] [[/ jsxgraph ]]
<!-- JSXGraph block for the second board-->
[[ jsxgraph width="200px" height="200px"]]
/* divid variables */
const divid1 = divid.replace(/[0-9]+/g,divid.match(/[0-9]+/g)-1)
const divid2 = divid;
console.log(divid1, divid2);
/* init boards */
const board1 = JXG.JSXGraph.initBoard(divid1,{ boundingbox: [-5, 5, 5, -5], axis: true });
const board2 = JXG.JSXGraph.initBoard(divid2,{ boundingbox: [-5, 5, 5, -5], axis: true });
[[/ jsxgraph ]]
</div>
The STACK question then shows two boards:
stack question with two jsxgraph boards
This code creates two JSXGraph boards inside the second JSXGraph block that can interact with each other. The placement is done with a flexbox wrapper-div. I think this should also work for Formulas similarly. I hope this answers your question.

Following #bernhard759's hint to use CSS to steer the diagram's placement. The following CSS code produces a result that I like:
.jsxgraph-boards {
align-items: start;
justify-content: start;
margin: 0 0 1rem 0;
}
.jxgbox {
margin: 1rem 0 0 1rem;
}

Related

How to create custom UI for a MATLAB application?

MATLAB possesses all features I need in my application, except for one - a 21st century look to the applications it builds. The old UI controls with the skin from the 90s just don't cut it anymore. Are there ways to customize the GUI of the compiled window itself? I know of App Designer for MATLAB (which is an alternative for GUIDE as I understood) but that's not close enough. For example, I want a complete flat design look with sprites/buttons/etc drawn in Photoshop for my built application.
Would an external C library/framework be able to build a custom GUI when compiling an application?
I've tried to google this question and it seems like nobody cares about design in the scientific community. I'm not quite sure how to phrase my question, apologies. I hope some of you have a bit of experience with this.
P.S.: Below is the look I'd like to achieve:
As described in my previous comment, and starting from R2019b, you can use uihtml components in new web-based uifigure (introduced in R2016a) to customize style of elements appearing on screen via css + javascript
Here below is a very simple example for a css-styled button:
First the matlab code (TestUiHtml.m):
function [] = TestUiHtml()
%[
% Create the figure and layout
fig = uifigure('Name', 'Test uihtml', 'Color', [1 1 1]);
grid = uigridlayout('Parent', fig, 'ColumnWidth', { '1x', '1x' }, 'RowHeight', {200, '1x' }, 'BackgroundColor', fig.Color);
% Add a uihtml element (that will act like a button using html+css+javascript)
button = uihtml('Parent', grid, 'HTMLSource', 'myway.html', 'DataChangedFcn', #(s,e)onBtnClicked(fig));
% Button layout
button.Layout.Row = 1; button.Layout.Column = [1 2];
%]
end
function [] = onBtnClicked(fig)
%[
uialert(fig, 'World!', 'Clicked', 'Icon', 'info');
%]
end
NB: Above code simply adds in the figure a uihtml component whose property HTMLSource points to the html content you want to have.
Here is the html code to describe the custom uihtml component content (myway.html):
<!DOCTYPE html>
<head>
<link rel="stylesheet" type="text/css" href="myway.css">
<script type="text/javascript" src="myway.js"></script>
</head>
<html>
<body>
<div class="container">
<button class="skewBtn blue" id="btn">Hello!</button>
</div>
</body>
</html>
NB: It is not mandatory to have a fully well-formed html code (i.e. just a <button style="...">Hello</button> would do).
The linked css code to style the html content (myway.css):
body {
background-color: transparent;
}
.container {
display: flex;
justify-content: space-evenly;
align-items: center;
flex-wrap: wrap;
height: 97vh;
}
.container .skewBtn {
width: 180px;
height: 80px;
outline: none;
cursor: pointer;
background: none;
transition: 0.5s;
font-size: 24px;
border-radius: 5px;
font-family: "Lato", sans-serif;
}
.container .skewBtn:hover {
border: none;
color: white;
font-size: 28px;
transform: scale(1.1);
}
.blue {
border: 2px solid #1976D2;
color: #1976D2;
}
.blue:hover {
background-color: #1976D2;
transition: all 0.3s ease-in-out;
}
And finally the javascript code for event/data marshalling between matlab and the html-based component ... or for more advanced programming logic, if any, for the html-content (myway.js):
function setup(htmlComponent)
{
document.getElementById("btn").addEventListener("click", function(event)
{
htmlComponent.Data = 1234; // dummy value to fire event on matlab side
});
}
Marshalling is ensure via the data property of a htmlComponent object which both sides (i.e. matlab/javascript) are listening to for changes. Matlab automatically uses jsonencode/jsondecode in the background so you can pass back and forth almost any structure/values you need directly.
And voilà ... a nice-and-responsive css-styled button in matlab's figure:
It would be of course better to refactor above code as a uibuttonex class modeled on existing uibutton property name/value pairs.
Sarting from R2021a it is eventually possible to add it to app designer library of components as described here (I personally don't use the designer and prefer to code interfaces programmatically).
Some remarks
It is not possible to directly style exiting uibutton, uipanel, uitab, etc... elements => Mathwork does not allow to access uifigure's html nor to inject css/javascript in it easily (see following undocumented-matlab thread and mlapptools project to try to cheat things). For instance a uibutton does not translate to directly <button> markup in uifigure's source but a lot of imbricated <div>, so it is very difficult to style (and will probably change from one release to another).
I would not recommend to create a single uihtml element in the figure and code everything in html+css+javascript, but I would rather recommend to create small and simple custom uibuttonex, etc elements ... else you'll have to deal with a single data blob to connect you interface with the matlab code which can be tricky and difficult to reuse.
Unfortunately it is yet not possible to create custom html-containers in which you can add other child ui-elements (custom or non-custom) ... say bye-bye to create containers similar to uix.GridFlex, uix.CardPanel from the wonderful GUI Layout toolbox or to creating nicely styled uitabex, etc... This is really a missing part !
Looking at source code of uifigure pages, custom ui-elements are also embedded in <iframe></iframe> markups, so it is not possible to inject some global css/javascript code (i.e. you'll have to repeat this for each uihtml element you create). It is not possible (or difficult) then to have multiple uihtml elements to interact with each-other (unless coding everything in a single page or passing through matlab code/events only).
Addendum : Here is a solution to get css-style from parent, unfortunately this does not solve one need to inject this css in the main uifigure source (well this can be done in javascript ... something like if !exist(parent.elements where id="mycss") => parent.document.inject(lalala))
Mathworks is going the good direction with uifigure and html in the background, but it's still a bit too locked for now and missing important containers from the GUI Layout toolbox.
NB: I tried the GUI Layout toolbox elements in uifigure ... some are working (with lot of resizing bugs), other are not working at all (GridFlex). Maybe a new version of the toolbox will come.
Charting
For modern charting you can use javascript libraries like D3js, SciChart, LightningChart, or others!!.
There is some example using D3 on fileexchange

TinyMCE - preserve style and function of selected element

I have decided to 'enhance' a textarea in a form with TinyMCE... however, doing so has interrupted the styling and jQuery functionality of the original element, as TinyMCE wraps that element in an iframe and a few divs. What I'd love to be able to do is to get the TinyMCE functionality (preserving text formatting, etc.) but not lose the styling and functions that I had associated with the original textarea. I looked through the TinyMCE documentation, but couldn't seem to find anything about this. Does anyone have any thoughts on how to accomplish this?
My form features the textarea like so:
<head>
<script>tinymce.init( { selector: 'textarea' } );</script>
</head>
<div class="form-element">
<div class="label-container">
<label for="body">Post</label><span class="warning">Please fill out this field</span>
</div>
<textarea id="body" class="input-field" name="body"></textarea>
</div>
but adding TinyMCE breaks the label/textarea relationship.
Also, jQuery functionality is broken, such as this validation script:
$("form").submit(function(e){
tinyMCE.triggerSave();
var inputFields = $(".input-field");
var proceed = true;
for(var i = 0; i < inputFields.length; i++){
if($(inputFields[i]).val() == ""){
$(inputFields[i]).css("border", "solid 3px #E86F3A");
$(inputFields[i]).prev().find(".warning").show();
var proceed = false;
e.preventDefault();
}
else{
$(inputFields[i]).css("border", "none");
$(inputFields[i]).prev().find(".warning").hide();
};
};
//OTHER STUFF...
});
since the textarea.input-field is no longer picked up in the inputFields variable.
So, in a nutshell, I'm looking for the TinyMCE wrapper to 'inherit' the styling and functionality of the element that it is attached to. Possible?
As you have correctly surmised when you invoke TinyMCE on a <textarea> the original <textarea> is no longer visible on the page and its replaced by an <iframe> and series of <div> elements.
If you want to keep the underlying <textarea> in sync you can use the tinymce.triggerSave() method. This will update all of the underlying <textarea> elements with the current value of the appropriate instance of TinyMCE.
You can do this when someone tries to save/submit the content or you can try to perform this when certain editor events happen (https://www.tinymce.com/docs/advanced/events/#editorevents). Unless you need real time accuracy of the contents of the <textarea> its far easier to call the triggerSave() method right before you perform you jQuery validation.
Note: Putting a border on the <textarea> won't have any impact on TinyMCE as you no longer see the underlying <textarea>. You can certainly try to add CSS to the editor's HTML in real time. The outer border of TinyMCE 4.4 has these classes attached:
class="mce-tinymce mce-container mce-panel"
...but do note that these classes could change over time so if you upgrade TinyMCE check to make sure your CSS still works before upgrading.

CSS multi-column layout of forms in Firefox

It looks like FireFox (my version is 19.0.2 - OSX) doesn't render forms properly using multicolumn layout. It renders normal paragraph text etc properly, but not forms.
The CSS:
fieldset {
-moz-column-count: 2;
column-count: 2;
-webkit-column-count: 2;
}
This is what it looks like in FireFox:
This is what it looks like in WebKit browsers:
Please view this sample code / live demo in FireFox to see that it doesn't render the multi-column layout for form elements.
Is this a bug, or is there something I can do to get it working in FireFox too?
Maybe the multi column attribute can't apply for the moment on this specific markup element that you use (namely fieldset).
Fieldset is dedicated to group some form fields, but I'm not sure it is already implemented to render in multi column...
So I should think that it is a bug that will be corrected in the future...
You can counter this by creating a simple div with flot left for the first form elements... Of course, with this option, you have to manually split the form elements that will be drawned on the left and on the right, you don't have the magic of equals length mutli-colmun anymore...
div#column1{
width : 400px;
float : left;
}
div#column2 {
float : left;
}
<div id="#column1">Your first fields</div>
<div id="#column2">Your second fields</div>

Split html string into multiple pages

I am trying to develop eBook reader kind of android application. I need to split long html string(sent by server at run-time) into pages on fly based on the screen space available. Html content is an article which could contain text, images, videos etc.I am using WebView to display the html.
Can anyone give me direction towards how this can be achieved.
Thanks in advance.
Doing any sort of HTML/DOM parsing is going to drive you up the wall, I think, and means that you're effectively starting to develop your own HTML layout engine.
It's a better idea to use the CSS3 column functions. Basically, get your content to render within a fixed width-and-height column. This becomes your page. Then shift your content position left to move between pages, and wrap it in a container that will hide overflow elements.
Our HTML will basically be:
<body>
<div id="container">
<div id="content">
CONTENT GOES HERE
<span id="endMarker"></span>
</div>
</div>
<div>
<button id="previous">Previous</button>
<span id="page">Page N of M</span>
<button id="next">Next</button>
</div>
</body>
Our basic CSS is:
#container {
width: 240px;
overflow: hidden;
background-color: yellow;
}
#content {
position: relative;
height: 30em;
-moz-column-width: 240px;
-webkit-column-width: 240px;
column-width: 240px;
-moz-column-gap: 10px;
-webkit-column-gap: 10px;
column-gap: 10px;
}
Now we will set the left CSS property for the #content to switch between pages, in multiples of -250px.
We've only got to work out how many columns our content takes, and we've got paging. How to get css3 multi-column count in Javascript gives a hint: we're going to find it from the left position of #endMarker.
Here's a working example http://lateral.co.za/pages.html, with the first chapter of Moby Dick. It works in Chrome and on Android, but not in Firefox - I think because of differences in the CSS columns implementations. Since we're interested in Android here, the code is good.
The important parts are:
The CSS settings as above.
The addition of a <span id="endMarker"></span> after the content (but within the #content div)
The addition of a #previous and #next button, and a #page span, all outside the #container.
This javascript after jQuery loads:
var _column = 0;
var _columnCount = 0;
var _columnWidth = 240;
var _columnGap = 10;
$(function() {
_columnCount = Math.floor($('#endMarker').position().left/(_columnWidth + _columnGap));
setColumn = function(i) {
_column = i;
document.getElementById('content').style.left = -1 * _column * (_columnWidth + _columnGap);
$('#page').html('Page ' + (_column+1) + ' of ' + (_columnCount+1));
}
$('#next').click(function() {
if (_column==_columnCount) return;
setColumn(_column+1);
});
$('#previous').click(function() {
if (0==_column) return;
setColumn(_column-1);
});
setColumn(0);
});
That's it.
There's room for work. One might want to think about that number of columns calculation, I sort of sucked it from the referenced SO post, but haven't actually thought it through... The width of the container seems to affect the column width of the content, which doesn't entirely make sense to me.
But at least everything seems to be working without having to do any HTML parsing and own layout, at least in Chrome and on Android.
You have to parse the HTML, best would be to use some library where you can access the DOM like in JavaScript. Then you can create a custom layout for the parsed content. Does WebView supports JavaScript? That would be a good start to try with.
Obviously you can not split at arbitrary locations of the HTML file, your have to consider the HTML-Tags. After modifying the DOM or splitting the html you can provide an custom CSS file for the content to display it in a way you like and add some pagination using your library or JavaScript.
Using <span style="display:none"></span> can help you to hide content in a website. Then you don't have to split is physically (it is in memory after loading the page anyway).
Hope that helped a bit. You will not get a full solution here, but maybe you got some ideas. If you find further more specific problems it will be easier to ask more specific questions.

Prevent EPiServer from wrapping content in <p> tags

I'm working on a site in EPiServer, and whenever I create a page property with the type set to "XHTML string" (which uses the WYSIWYG content editor in Edit mode), it wraps all content in <p> tags.
Is there any way to prevent this from happening? I can't remove the paragraph margins universally through my CSS (e.g. p {margin: 0 !important;}) since I do need the margins for actual paragraphs of text. I've even tried going to the HTML source view in the editor and manually deleting the <p> tags that it generates, but it immediately adds them back in when I save!
It doesn't happen when the property type is either a long or short string, but that's not always an option since the content might contain images, dynamic controls, etc.
This is becoming a real nuisance since it's very hard to achieve the layout I need when basically every element on the page has extra margins applied to it.
As Johan is saying, they are there for a reason - see more info here. That being said, it's not impossible to remove them. It can be done in one of two ways (taken from world.episerver.com:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
myEditor.InitOptions["force_p_newlines"] = "false";
}
or
<script type="text/javascript">
tinyMCE.init({
force_p_newlines: false
});
</script>
You can add your own custom TinyMCE-config that removes P-elements or strip them out using regular expressions either when saving the page or when rendering the property/page.
I think it's a bad idea though. P-elements are what the editors generate the most and in most cases their content is also semantically correct. Better to wrap your property in a div with a class and adjust margins using CSS like you mention.
If you're using a version of EPiServer with TinyMCE editors, you can insert <br /> elements instead of <p> elements if you type shift-enter instead of enter. This should eliminate your margin problems.
More info at the link below:
http://www.tinymce.com/wiki.php/TinyMCE_FAQ#TinyMCE_produce_P_elements_on_enter.2Freturn_instead_of_BR_elements.3F
EDIT: My comment below answers his question better.
I discovered that while I can't remove the <p> tags from the source view (because it adds them back in automatically), if I replace them with <div> tags, it'll leave things alone. It does mean that I've got an extra <div> wrapping some elements that I don't really need, but at least a <div> doesn't add margins like a <p> does, so...good enough!