This is a reference layout (colors only for highlighting the bounds) I created using HTML and CSS. Here is the code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.message {
padding: 5px;
background-color: red;
}
.text-field {
margin: 0;
padding: 5px;
background-color: gray;
color: black;
display: inline-block;
}
.max-size {
max-width: 60%;
}
.align-right {
text-align: right;
}
.align-right p {
text-align: left;
}
</style>
</head>
<body>
<div class="message">
<div class="msg-header">
<p class="text-field max-size">Sender</p>
</div>
<div class="msg-content">
<p class="text-field max-size">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</p>
</div>
</div>
<div class="message">
<div class="msg-header align-right">
<p class="text-field max-size">You</p>
</div>
<div class="msg-content align-right">
<p class="text-field max-size">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</p>
</div>
</div>
</body>
</html>
I try to achieve the same layout using c++ and wxWidgets. Ignoring the 60% max size I tried the following.
MainFrame::MainFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(NULL, wxID_ANY, title, pos, size) {
this->InitialiseComponents();
}
void MainFrame::InitialiseComponents() {
...
this->panelChat = new wxScrolledWindow(this->splitterChatLog, MFID_LIST_BOX_CHAT, wxDefaultPosition, wxSize(850, 100));
this->panelChat->SetBackgroundColour(wxColour(255, 255, 255));
this->panelChat->SetScrollRate(5, 5);
this->sizerChat = new wxBoxSizer(wxVERTICAL);
this->panelChat->SetSizer(this->sizerChat);
...
}
void MainFrame::AddChatMessage(std::string addr, std::string str, bool sent) {
wxPanel *panelMsg = new wxPanel(this->panelChat, wxID_ANY);
panelMsg->SetBackgroundColour(wxColour(255, 0, 0));
wxStaticText *textAddr = new wxStaticText(panelMsg, wxID_ANY, addr);
wxStaticText *textMsg = new wxStaticText(panelMsg, wxID_ANY, str);
wxBoxSizer *sizerMsgHeader = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *sizerMsgContent = new wxBoxSizer(wxVERTICAL);
sizerMsgHeader->Add(textAddr, 0, (sent ? wxALIGN_RIGHT : 0));
sizerMsgContent->Add(textMsg, 0, (sent ? wxALIGN_RIGHT : 0));
wxBoxSizer *sizerMsg = new wxBoxSizer(wxVERTICAL);
sizerMsg->Add(sizerMsgHeader, 0, wxEXPAND);
sizerMsg->Add(sizerMsgContent, 0, wxEXPAND | wxBOTTOM, 5);
panelMsg->SetSizer(sizerMsg);
this->sizerChat->Add(panelMsg, 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, 5);
}
The problems are:
Calling AddChatMessage multiple times does not stack the messages they lay on top of each other.
Each message panel is a 20x20 red square. It's neither expanding horizontally nor wrapping its content.
I think you just need to add a call to Layout(); or panelChat->Layout(); at the end of the MainFrame::AddChatMessage method. This will force the panelChat window to rearrange all its children according to the sizer flags given to it when the children were added.
However, wxWidgets does offer the wxWebView control. If you already have a chatlog in html format, using that control might be the best way to display it.
You can restrict the text area to 60% on the right or left of the chat window. One way to do this is to use a flexible spacer set to take up 40% of the width and set the message panel to take up the remaining 60%. I think this version of the AddChatMessage should do that.
void MainFrame::AddChatMessage(std::string addr, std::string str, bool sent) {
wxPanel *panelMsg = new wxPanel(this->panelChat, wxID_ANY);
panelMsg->SetBackgroundColour(wxColour(255, 0, 0));
wxStaticText *textAddr = new wxStaticText(panelMsg, wxID_ANY, addr);
wxStaticText *textMsg = new wxStaticText(panelMsg, wxID_ANY, str);
textMsg->Wrap(60 * GetClientSize().GetWidth() / 100);
wxBoxSizer *sizerMsg = new wxBoxSizer(wxVERTICAL);
sizerMsg->Add(textAddr, 0, (sent ? wxALIGN_RIGHT : 0));
sizerMsg->Add(textMsg, 0, (sent ? wxALIGN_RIGHT : 0));
panelMsg->SetSizer(sizerMsg);
// Create a new horizontal sizer and add a spacer either before or after
// taking up 40% of the horizontal space.
wxBoxSizer* newChatSizer = new wxBoxSizer(wxHORIZONTAL);
if ( sent )
{
newChatSizer->AddStretchSpacer(2);
}
newChatSizer->Add(panelMsg, 3, wxEXPAND);
if ( !sent )
{
newChatSizer->AddStretchSpacer(2);
}
this->sizerChat->Add(newChatSizer, 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, 5);
panelChat->Layout();
}
In this case this adds a space (either on the left or right) with a proportion of 2. The the message panel is added with a proportion of 3. Since the total proportion is 5, the spacer is given 2/5=40% of the space leaving the remainging 60% of the space for the message.
Note: I also removed the textAddr and textMsg sizers and instead just added the static texts to the sizerMsg. Usually a sizer containing only one item isn't necessary, and I didn't see what those two sizers were doing.
Related
As the title suggests I am looking to build a regex (JS flavour for VSCode find in file) that finds matches that start with [vc_ or [/vc and end with "] or ]. I am attempting to clean up data coming from WP Bakery so it can be imported into the WordPress TinyMCE editor. And example of the exported content is as follows (apologies for the length, but its to give an idea of the strings I am working with):
<content:encoded>
<![CDATA[[vc_row type="in_container" full_screen_row_position="middle" column_margin="default" column_direction="default" column_direction_tablet="default" column_direction_phone="default" scene_position="center" text_color="dark" text_align="left" row_border_radius="none" row_border_radius_applies="bg" overlay_strength="0.3" gradient_direction="left_to_right" shape_divider_position="bottom" bg_image_animation="none"][vc_column column_padding="no-extra-padding" column_padding_tablet="inherit" column_padding_phone="inherit" column_padding_position="all" background_color_opacity="1" background_hover_color_opacity="1" column_shadow="none" column_border_radius="none" column_link_target="_self" gradient_direction="left_to_right" overlay_strength="0.3" width="1/1" tablet_width_inherit="default" tablet_text_alignment="default" phone_text_alignment="default" column_border_width="none" column_border_style="solid" bg_image_animation="none"][vc_column_text]Duis posuere diam eu eleifend tristique. Morbi tincidunt leo sit amet diam ultricies elementum.[/vc_column_text][/vc_column][/vc_row][vc_row type="in_container" full_screen_row_position="middle" column_margin="default" column_direction="default" column_direction_tablet="default" column_direction_phone="default" scene_position="center" text_color="dark" text_align="left" row_border_radius="none" row_border_radius_applies="bg" overlay_strength="0.3" gradient_direction="left_to_right" shape_divider_position="bottom" bg_image_animation="none"][vc_column column_padding="no-extra-padding" column_padding_tablet="inherit" column_padding_phone="inherit" column_padding_position="all" background_color_opacity="1" background_hover_color_opacity="1" column_shadow="none" column_border_radius="none" column_link_target="_self" gradient_direction="left_to_right" overlay_strength="0.3" width="1/1" tablet_width_inherit="default" tablet_text_alignment="default" phone_text_alignment="default" column_border_width="none" column_border_style="solid" bg_image_animation="none"][vc_column_text]<strong>Duis posuere diam eu eleifend tristique. Morbi tincidunt leo sit amet diam ultricies elementum.</strong>
Duis posuere diam eu eleifend tristique. Morbi tincidunt leo sit amet diam ultricies elementum.[/vc_column_text][/vc_column][/vc_row][vc_row type="in_container" full_screen_row_position="middle" column_margin="default" column_direction="default" column_direction_tablet="default" column_direction_phone="default" scene_position="center" text_color="dark" text_align="left" row_border_radius="none" row_border_radius_applies="bg" overlay_strength="0.3" gradient_direction="left_to_right" shape_divider_position="bottom" bg_image_animation="none"][vc_column column_padding="no-extra-padding" column_padding_tablet="inherit" column_padding_phone="inherit" column_padding_position="all" background_color_opacity="1" background_hover_color_opacity="1" column_shadow="none" column_border_radius="none" column_link_target="_self" gradient_direction="left_to_right" overlay_strength="0.3" width="1/1" tablet_width_inherit="default" tablet_text_alignment="default" phone_text_alignment="default" column_border_width="none" column_border_style="solid" bg_image_animation="none"][divider line_type="No Line"][/vc_column][/vc_row][vc_row type="in_container" full_screen_row_position="middle" column_margin="default" column_direction="default" column_direction_tablet="default" column_direction_phone="default" scene_position="center" text_color="dark" text_align="left" row_border_radius="none" row_border_radius_applies="bg" overlay_strength="0.3" gradient_direction="left_to_right" shape_divider_position="bottom" bg_image_animation="none"][vc_column column_padding="no-extra-padding" column_padding_tablet="inherit" column_padding_phone="inherit" column_padding_position="all" background_color_opacity="1" background_hover_color_opacity="1" column_shadow="none" column_border_radius="none" column_link_target="_self" gradient_direction="left_to_right" overlay_strength="0.3" width="1/1" tablet_width_inherit="default" tablet_text_alignment="default" phone_text_alignment="default" column_border_width="none" column_border_style="solid" bg_image_animation="none"][vc_column_text]<strong>Duis posuere diam eu eleifend tristique. Morbi tincidunt leo sit amet diam ultricies elementum.</strong>[/vc_column_text][/vc_column][/vc_row][vc_row type="in_container" full_screen_row_position="middle" column_margin="default" column_direction="default" column_direction_tablet="default" column_direction_phone="default" scene_position="center" text_color="dark" text_align="left" row_border_radius="none" row_border_radius_applies="bg" overlay_strength="0.3" gradient_direction="left_to_right" shape_divider_position="bottom" bg_image_animation="none"][vc_column column_padding="no-extra-padding" column_padding_tablet="inherit" column_padding_phone="inherit" column_padding_position="all" background_color_opacity="1" background_hover_color_opacity="1" column_shadow="none" column_border_radius="none" column_link_target="_self" gradient_direction="left_to_right" overlay_strength="0.3" width="1/1" tablet_width_inherit="default" tablet_text_alignment="default" phone_text_alignment="default" column_border_width="none" column_border_style="solid" bg_image_animation="none"][divider line_type="No Line"][/vc_column][/vc_row][vc_row type="in_container" full_screen_row_position="middle" column_margin="default" column_direction="default" column_direction_tablet="default" column_direction_phone="default" scene_position="center" text_color="dark" text_align="left" row_border_radius="none" row_border_radius_applies="bg" overlay_strength="0.3" gradient_direction="left_to_right" shape_divider_position="bottom" bg_image_animation="none"][vc_column column_padding="no-extra-padding" column_padding_tablet="inherit" column_padding_phone="inherit" column_padding_position="all" background_color_opacity="1" background_hover_color_opacity="1" column_shadow="none" column_border_radius="none" column_link_target="_self" gradient_direction="left_to_right" overlay_strength="0.3" width="1/1" tablet_width_inherit="default" tablet_text_alignment="default" phone_text_alignment="default" column_border_width="none" column_border_style="solid" bg_image_animation="none"][vc_column_text]Duis posuere diam eu eleifend tristique. Morbi tincidunt leo sit amet diam ultricies elementum.[/vc_column_text][/vc_column][/vc_row]]]></content:encoded>
So, I have been attempting various regex to find these 'vc' tags, but what I have been using does not find the end of each tag, it finds the end of the tag for that particular string.
The expression I have been using so far - (\[vc|\[\/vc).*(\"]|\]).
Any help with this would be appreciated.
You may use this regex:
/\[\/?(vc[^\]]*)"?\]/g
RegEx Demo
RegEx Breakup:
\[: Match a [
\/?: Match optional /
(: Start capture group
vc: Match vc
[^\]]*: Match 0 or more of any char that is not ]
): End capture group
"?: Match optional "
\]: Match a ]
I have this list:
var ls = List("Should be ignored", "X", "test", "test1", "X", "test2")
I was wondering if someone knows how I could filter out the elements in the list which are right after the "X" so that the result is:
List("test", "test2")
So far I have tried:
ls.filter(x => x._2.equals("X"))
However that simply bring back this result:
List((0,This line should be ignored, because it is before the first predicate), (2,Lorem ipsum dolor sit amet, consectetur adipiscing elit.), (3,Suspendisse aliquet quis ligula nec tristique.), (5,Donec augue ipsum, mattis et elit vel, convallis convallis dui.), (7,In hac habitasse platea dictums.))
You can use sliding to get an Iterator of every tuple of consecutive elements, and then select the second elements from the tuples in which "X" is the first element:
val items = List("Should be ignored", "X", "test", "test1", "X", "test2")
items
.sliding(2)
.collect { case List("X", item) => item }
.toList
// res0: List[String] = List(test, test2)
You might create the new list by unfolding over the given list.
var ls = List("Should be ignored", "X", "test", "test1", "X", "test2")
List.unfold(ls){state =>
val ns = state.dropWhile(_ != "X").drop(1)
Option.when(ns.nonEmpty)(ns.head->ns.tail)
}
//res0: List[String] = List(test, test2)
Should work no matter how many "X" elements there are.
But what if the input is List("A","X","X","X","B")? Should the result be List("X","B") or just List("B")? Right now my suggested solution produces the former but it can produce the latter after a very simple modification.
I believe the simples solution would be this:
def filterAfterX(data: List[String]): List[String] =
(data lazyZip data.tail).collect {
case ("X", word) => word
}.toList
I have been stuck like 3 hours without finding anything on the net.
this is what I want to achieve: https://gyazo.com/281aa4fd3ddc3824063899da5f121d72
this is what I get:
https://gyazo.com/d50617fa8a6ff38d36b9b0c795328b89
Can't make the first list unable to invade column 2, that's my problem.
I've tried to use div, tables, some columns atributes, but it seems I can't make it work.
So just simple as that… I need 3 columns, 1 for list, that's all.
#fondo{
align-content: center;
width: 960px;
}
#cabecera{
background-color: grey;
}
#cabecera H1{
align-content: center;
margin-left: 200px;
margin-right: 200px;
}
#datos {
width: 260px;
float: left;
}
#contenido {
width: 700px;
float: right;
}
#columnas{
width: 700px;
column-count: 3;
/*-webkit-column-break-break-inside: avoid;
-webkit-column-break-break-after: always;*/
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>HTML & CSS: Curso práctico avanzado</title>
<link rel="stylesheet" type="text/css" href="estilo.css">
</head>
<body>
<div id="fondo">
<div id="cabecera">
<h1>HTML & CSS: Curso práctico avanzado</h1>
</div>
<div>
<div id="datos">
<h2>Datos del libro</h2>
<ul>
<li>Título: HTML & CSS: Curso práctico avanzado</li>
<li>Autor: Sergio Luján Mora</li>
<li>Editorial: Publicaciones Altaria</li>
<li>Año de publicación: 2015</li>
<li>ISBN: 978-84-944049-4-8</li>
</ul>
</div>
<div id="contenido">
<div>
<h2>Descripción del libro</h2>
<p>
Aunque los inicios de Internet se remontan a los años sesenta,
no ha sido hasta los años noventa cuando, gracias a la Web, se ha
extendido su uso por todo el mundo. En pocos años, la Web ha
evolucionado enormemente: se ha pasado de páginas sencillas, con
pocas imágenes y contenidos estáticos que eran visitadas por unos
pocos usuarios a páginas complejas, con contenidos dinámicos que
provienen de bases de datos y que son visitadas por miles de
usuarios al mismo tiempo.
</p>
<p>
Todas las páginas están internamente construidas con la misma
tecnología, con el Lenguaje de marcas de hipertexto (Hypertext
Markup Language, HTML) y con las Hojas de estilo en cascada
(Cascading Style Sheets, CSS).
</p>
<p>
Este libro es adecuado para cualquiera que tenga interés en
aprender a desarrollar sus propias páginas web. No son necesarios
conocimientos previos para aprender con este libro, lo único que
es necesario es saber utilizar un ordenador y saber navegar por la
Web.
</p>
<h2>Contenido del libro</h2>
<p>
El contenido de este libro se estructura en tres apartados bien
diferenciados:
</p>
</div>
<div id="columnas">
<div style="width: 233px">
<ul>
<li>En la primera parte del libro se trabajan conceptos generales
que son necesarios para poder desarrollar páginas web; se explican
conceptos de estructura física y estructura lógica (o estructura
de navegación) de un sitio web. Se detalla cómo influye la
estructura física en las URL o direcciones que se emplean a la
hora de crear los enlaces de un sitio web. Pasando por el concepto
de "estándar web", un término general que se emplea para
refererirse a los estándares que define su funcionamiento como
HTML y CSS, empleados para el desarrollo de las páginas web en el
lado del cliente.</li>
</ul>
</div>
<div style="width: 233px">
<ul>
<li>En la segunda parte se trabaja HTML. Partiendo de la estructura básica de una página web, se explican las etiquetas de
HTML que se utilizan para definir el texto, los enlaces, las
listas, las tablas, los formularios y los elementos
multimedia.</li>
</ul>
</div>
<div style="width: 233px">
<ul>
<li>En la tercera y última parte se explica CSS, el lenguaje que
se emplea para definir el formato y la presentación de una página
web. Se explica cómo utilizar el color, cómo definir la
presentación del texto, de las tablas y de los formularios; cómo
realizar transformaciones y transiciones con el fin de diseñar una
página web.</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
I am using Google Apps Script to return a text string from simple comments entity in a database into Google Sheets. I would like to identify certain comments that contain my own 'bbCode' such as [Status: Complete]. But I am not sure how to extract the 'Complete' text and how to remove the entire '[Status: Complete]' bbCode from the comment text. This is where I have got to so far - thank you for any suggestions:
Example 1 comment text: '[Status: Complete] Lorem ipsum bla bla'
Desired output: Col1: 'Lorem ipsum bla bla' Col2: 'Complete'
Example 2 comment text: 'Lorem [Status: Proposed] ipsum bla bla'
Desired output: Col1: 'Lorem ipsum bla bla' Col2: 'Proposed'
Example 3 comment text: 'Lorem ipsum bla bla'
Desired output: Col1: 'Lorem ipsum bla bla' Col2:
var bbCode = '[Status: ";
//get data from db and for next into val
var val = rs.getString(col+1);
if (val.indexOf(bbCode) > -1) {
// Item with Status, place the status in the Status Column
//but this next line is not right - I would like var Status = 'Complete' or 'Proposed' etc...
var Status = RegExp(.*\[Status: (.*)\].*', 'g');
cell.offset(row, col+2).setValue(Status);
// Place the remaining comment in the Comment column
//This next line is not right I would like val = the comment string without the '[Status: Completed]' or '[Status: Proposed]' etc...
cell.offset(row, col+2).setValue(val);
} else {
// Enter comment in Comment column as normal
cell.offset(row, col+1).setValue(val);
}
Try this sample:
function RegexGetTwoStrings() {
Logger.log('^^^^^^^^^^^^^^^^^^^^^^^^^^^^^');
var sample = ['[Status: Complete] Lorem ipsum bla bla',
'Lorem [Status: Proposed] ipsum bla bla',
'Lorem ipsum bla bla'];
var RegEx = /(.*)\[.*: (.*)\] (.*)/;
var Replace = "$1$3,$2";
var str, newStr, Col1, Col2;
var strArr = [];
for (var i = 0; i < sample.length; i++) {
str = sample[i];
newStr = str.replace(RegEx, Replace) + ",";
strArr = newStr.split(',');
Col1 = strArr[0];
Col2 = strArr[1];
Logger.log("Sample1 = '" + str + "'");
Logger.log('Col1 = ' + Col1);
Logger.log('Col2 = ' + Col2);
}
Logger.log('^^^^^^^^^^^^^^^^^^^^^^^^^^^^^');
}
I have a scrollview i'm inserting divs into.
however, the content of these divs are being rendered by javascript templating engine.
when famo.us initially creates this page, it seems it calculate the height of the div content to be zero, so the divs in the scrollview all end up being on top of each other. I'm guessing this is because template rendering happens a couple of ticks later..
is there a way to force famo.us to recalculate/reflow its layout?
I too owe johntraver a beer for his excellent answers on famo.us questions here. This is work derived from one of his previous answers, I use it for surfaces on scrollviews with dynamic html content (and height):
/* AutoSurface.js */
define(function(require, exports, module) {
var Surface = require('famous/core/Surface');
var Entity = require('famous/core/Entity');
function AutoSurface(options) {
Surface.apply(this, arguments);
this.hasTrueSize = false;
this._superCommit = Surface.prototype.commit;
}
AutoSurface.prototype = Object.create(Surface.prototype);
AutoSurface.prototype.constructor = AutoSurface;
AutoSurface.prototype.commit = function commit(context) {
this._superCommit(context);
if (!this.hasTrueSize) {
this.trueHeight = Entity.get(this.id)._currTarget.clientHeight;
this.setSize([undefined,this.trueHeight]);
this.hasTrueSize = true;
}
}
module.exports = AutoSurface;
});
Commit is called every tick so you should be able to wait until you have a height > 0 or what you need before you set hasTrueSize = true.
This is very similar to the answer I just posted here.
how best to create a single scrollable view in famo.us?
You can wrap your true-sized surfaces in a sized modifier. This allows for scrollview to know the actual height of the surfaces within, and thus properly scroll. I am using the _currTarget of surface in the Modifiers sizeFrom method. The ternary operation is to prevent errors pre-deploy of the surface.
Here is that example revised for multiple cells in scrollview.. Hope it helps!
var Engine = require('famous/core/Engine');
var Surface = require('famous/core/Surface');
var RenderNode = require('famous/core/RenderNode');
var Modifier = require('famous/core/Modifier');
var Scrollview = require('famous/views/Scrollview');
var context = Engine.createContext();
var content = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod \
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, \
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo \
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse \
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non \
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
var scrollview = new Scrollview();
var surfaces = [];
scrollview.sequenceFrom(surfaces);
for (var i = 0; i < 10; i++) {
var surface = new Surface({
size:[undefined,true],
content: content,
properties:{
fontSize:'24px',
backgroundColor:'hsl('+(i*360/20)+',100%,50%)'
}
})
surface.pipe(scrollview);
surface.node = new RenderNode();
surface.mod = new Modifier();
surface.mod.sizeFrom(function(){
target = this._currTarget;
return target ? [undefined,target.offsetHeight] : [undefined,true];
}.bind(surface));
surface.node.add(surface.mod).add(surface);
surfaces.push(surface.node);
};
context.add(scrollview);
Instead of hacking deploy of using a sizeFrom-modifier, there is a much easier hack:
Let a surface return it's actual calculated height instead of it's specified height.
Override the default getSize function with this:
surface.getSize = function() { return this._size || this.size }
Full example in a JSFiddle
Warning: This breaks setting the Size with a modifier higher up the rendering tree. (But since you set size explictly anyway, this should not be a problem)