Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document & Dialog improvements #271

Merged
merged 4 commits into from
Oct 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions docs/html/modules/classes/document.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/html/modules/core.html
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ <h3>Error Codes</h3><table class="table table-sm borderless"><tbody><tr><th clas
<p>To get the context of the caller (the client), use <a href="?page=ParentContext">ParentContext()</a>.</p>
<h3>Result</h3><p>Returns an object pointer (of which the process has exclusive access to). Cannot return <code>NULL</code> except in the initial start-up and late shut-down sequence of the Core.</p><div class="footer copyright text-right">Core module documentation © Paul Manias 1996-2024</div></div><div class="docs-content" style="display:none;" id="CurrentTask"><h1>CurrentTask()</h1><p class="lead">Returns the active Task object.</p><div class="panel panel-info"><div class="panel-heading"><samp>objTask * CurrentTask()</samp></div></div><h3>Description</h3>
<p>This function returns the Task object of the active process.</p>
<p>If there is a legitimate circumstance where there is no current task (e.g. if the function is called during Core initialisation) then the "system task" may be returned, which has ownership of Core resources.</p>
<p>If there is a legitimate circumstance where there is no current task (e.g. if this function is called during Core initialisation) then the "system task" may be returned, which has ownership of Core resources.</p>
<h3>Result</h3><p>Returns a pointer to the current Task object or NULL if failure.</p><div class="footer copyright text-right">Core module documentation © Paul Manias 1996-2024</div></div><div class="docs-content" style="display:none;" id="DeleteFile"><h1>DeleteFile()</h1><p class="lead">Deletes files and folders.</p><div class="panel panel-info"><div class="panel-heading"><samp>ERR DeleteFile(CSTRING Path, FUNCTION * Callback)</samp></div><div class="panel-body"><table class="table" style="border: 4px; margin-bottom: 0px; border: 0px; border-bottom: 0px;"><thead><tr><th class="col-md-1">Parameter</th><th>Description</th></tr></thead><tbody><tr><td>Path</td><td>String referring to the file or folder to be deleted. Folders must be denoted with a trailing slash.</td></tr><tr><td>Callback</td><td>Optional callback for receiving feedback during the operation.</td></tr></tbody></table></div></div><h3>Description</h3>
<p>This function will delete a file or folder when given a valid file location. The current user must have delete access to the given file. When deleting folders, all content will be scanned and deleted recursively. Individual deletion failures are ignored, although an error will be returned if the top-level folder still contains content on its deletion.</p>
<p>This function does not allow for the approximation of file names. To approximate a file location, open it as a File object or use <a href="?page=ResolvePath">ResolvePath()</a> first.</p>
Expand Down
15 changes: 9 additions & 6 deletions docs/xml/modules/classes/document.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,8 @@
<copyright>Paul Manias © 2005-2024</copyright>
<description>
<p>The Document class offers a complete page layout engine, providing rich text display features for creating complex documents and text-based interfaces. Internally, document data is maintained as a serial byte stream and all object model information from the source is discarded. This simplification of the data makes it possible to edit the document in-place, much the same as any word processor. Alternatively it can be used for presentation purposes only, similarly to PDF or HTML formats. Presentation is achieved by building a vector scene graph in conjunction with the <class name="Vector">Vector</class> module. This means that the output is compatible with SVG and can be manipulated in detail with our existing vector API. Consequently, document formatting is closely integrated with SVG concepts and seamlessly inherits SVG functionality such as filling and stroking commands.</p>
<header>Safety</header>
<p>The Document class is intended to be safe to use when loading content from an unknown source. Processing will be aborted if a problem is found or the document appears to be unrenderable. It is however, not guaranteed that exploits are impossible. Consideration should also be given to the possibility of exploits that target third party libraries such as libpng and libjpeg for instance.</p>
<p>By default, script execution is not enabled when parsing a document source. If support for scripts is enabled, there is no meaningful level of safety on offer when the document is processed. This feature should not be used unless the source document has been written by the client, or has otherwise been received from a trusted source.</p>
<p>To mitigate security problems, we recommend that the application is built with some form of sandbox that will stop the system being compromised by bad actors. Utilising a project such as Win32 App Isolation https://github.com/microsoft/win32-app-isolation is one potential way of doing this.</p></description>
<p>The native document format in Parasol is RIPL. Documentation for RIPL is available in the Parasol Wiki. Other document formats may be supported as sub-classes, but bear in mind that document parsing is a one-way trip and stateful information such as the HTML DOM is not supported.</p>
<p>The Document class does not include a security barrier in its current form. Documents that include scripted code should not be processed unless they originate from a trusted source and are confirmed as such. To mitigate security problems, we recommend that the application is built with some form of sandbox that can prevent the system being compromised by bad actors. Utilising a project such as Win32 App Isolation https://github.com/microsoft/win32-app-isolation is one potential way of doing this.</p></description>
<source>
<file path="../class/">document_class.cpp</file>
<file path="../class/">fields.cpp</file>
Expand Down Expand Up @@ -107,13 +105,17 @@

<action>
<name>GetKey</name>
<comment>Retrieves script parameters.</comment>
<comment>Retrieves global variables and URI parameters.</comment>
<prototype>ERR acGetKey(*Object, CSTRING Key, STRING Value, LONG Size)</prototype>
<input>
<param type="CSTRING" name="Key">The name of a key value.</param>
<param type="STRING" name="Value">Pointer to a buffer space large enough to hold the retrieved value.</param>
<param type="LONG" name="Size">Indicates the byte size of the Buffer.</param>
</input>
<description>
<p>Use GetKey() to access the global variables and URI parameters of a document. Priority is given to global variables if there is a name clash.</p>
<p>The current value of each document widget is also available as a global variable accessible from GetKey(). The key-value will be given the same name as that specified in the widget's element.</p>
</description>
</action>

<action>
Expand All @@ -134,7 +136,7 @@

<action>
<name>SetKey</name>
<comment>Passes variable parameters to loaded documents.</comment>
<comment>Set a global key-value in the document.</comment>
<prototype>ERR acSetKey(*Object, CSTRING Key, CSTRING Value)</prototype>
<input>
<param type="CSTRING" name="Key">The name of the target key.</param>
Expand Down Expand Up @@ -653,6 +655,7 @@
<const name="ON_CROSSING_OUT">The mouse pointer has crossed out of an element.</const>
<const name="ON_MOTION">The user has triggered a motion event in an element that supports motion monitoring.</const>
<const name="PATH">The source file path has changed. Useful for detecting when the user has left the page.</const>
<const name="WIDGET_STATE">The state value of a widget has changed (e.g. input, checkbox, text). <code>name</code> and <code>value</code> keys will be defined in the event parameters.</const>
</constants>

<constants lookup="DRT" comment="Internal trigger codes">
Expand Down
1 change: 1 addition & 0 deletions include/parasol/modules/document.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ enum class DEF : ULONG {
ON_CROSSING_OUT = 0x00000010,
ON_CROSSING = 0x00000018,
LINK_ACTIVATED = 0x00000020,
WIDGET_STATE = 0x00000040,
};

DEFINE_ENUM_FLAG_OPERATORS(DEF)
Expand Down
3 changes: 3 additions & 0 deletions include/parasol/modules/vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -3946,6 +3946,9 @@ constexpr FieldValue AppendPath(OBJECTPTR Value) { return FieldValue(FID_AppendP
constexpr FieldValue DragCallback(const FUNCTION &Value) { return FieldValue(FID_DragCallback, &Value); }
constexpr FieldValue DragCallback(const FUNCTION *Value) { return FieldValue(FID_DragCallback, Value); }

constexpr FieldValue OnChange(const FUNCTION &Value) { return FieldValue(FID_OnChange, &Value); }
constexpr FieldValue OnChange(const FUNCTION *Value) { return FieldValue(FID_OnChange, Value); }

constexpr FieldValue TextFlags(VTXF Value) { return FieldValue(FID_TextFlags, LONG(Value)); }
constexpr FieldValue Overflow(VOF Value) { return FieldValue(FID_Overflow, LONG(Value)); }

Expand Down
1 change: 1 addition & 0 deletions include/parasol/system/fields.h
Original file line number Diff line number Diff line change
Expand Up @@ -934,6 +934,7 @@
#define FID_MatrixRows 0x64419145LL
#define FID_MatrixColumns 0x54dc215bLL
#define FID_Matrix 0x0d3e291aLL
#define FID_OnChange 0xee446f88LL
#define FID_PathTimestamp 0x2efda9a6LL
#define FID_PreserveAlpha 0xf9b49d57LL
#define FID_Pretext 0xc28b4df1LL
Expand Down
43 changes: 19 additions & 24 deletions scripts/gui/dialog.fluid
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ local function defaultIcon(self)
end

gui.dialog.message = function(Options)
local self = { // Public variables
local self = { -- Public variables
document = nil,
options = Options.options,
type = Options.type,
Expand Down Expand Up @@ -83,20 +83,18 @@ gui.dialog.message = function(Options)
local response = self.options[responseIndex]
local state = { }

if self.checkbox then
if self.checkbox.value == 1 then
state.checkboxState = true
else
state.checkboxState = false
end
if Document.getKey('checkbox') == '1' then
state.checkbox = true
else
state.checkbox = false
end

if self.input then
state.input = nz(self.input.string, nil)
if self.inputRequired and not state.input then
// If input is mandatory, the response is cancelled when no input is given
response = nil
end
local input = Document.getKey('input')
if nz(input) then state.input = input end

if self.inputRequired and not state.input then
-- If input is mandatory, the response is cancelled when no input is given
response = nil
end

self.feedback(self, response, state)
Expand All @@ -111,7 +109,7 @@ gui.dialog.message = function(Options)
local function buildDocument()
local option_icons = ''

// At minimum, there must be an OK option.
-- At minimum, there must be an OK option.

if not ((type(self.options) == 'table') and (#self.options > 0)) then
self.options = { { id=1, text='Close Dialog', icon='items/cancel' } }
Expand All @@ -138,13 +136,13 @@ gui.dialog.message = function(Options)
]]

if Options.envTemplate then
// The EnvTemplate can redefine the default body, GUI templates etc
-- The EnvTemplate can redefine the default body, GUI templates etc
doc = doc .. options.envTemplate .. '\n'
end

if Options.template then
// A dialog-specific template can override the body style and change any class templates,
// header and footer etc
-- A dialog-specific template can override the body style and change any class templates,
-- header and footer etc
doc = doc .. '<include src="' .. options.template .. '"/>\n'
end

Expand Down Expand Up @@ -178,13 +176,13 @@ gui.dialog.message = function(Options)
msg = ''
end

doc = doc .. '<p><input name="inDialog" flags="' .. inputFlags .. '" width="200" value="' .. msg .. '"/></p>\n'
doc = doc .. '<p><input name="input" flags="' .. inputFlags .. '" width="200" value="' .. msg .. '"/></p>\n'
end

if Options.checkboxLabel then
local checkbox_value = 'false'
if Options.checkboxState then checkbox_value = 'true' end
doc = doc .. '<p><checkbox name="dlgCheckbox" label="' .. Options.checkboxLabel .. '" value="' .. checkbox_value .. '"/></p>\n'
doc = doc .. '<p><checkbox name="checkbox" label="' .. Options.checkboxLabel .. '" value="' .. checkbox_value .. '"/></p>\n'
end

if Options.inject then
Expand Down Expand Up @@ -267,15 +265,12 @@ gui.dialog.message = function(Options)
eventMask = 'LinkActivated',
eventCallback = docEvent,
path = '#Index',
flags = 'Unrestricted|NoScrollbars',
flags = 'NoScrollbars',
clientScript = obj.find('self')
})

lDoc.acDataFeed(0, DATA_XML, buildDocument())

self.input = obj.find('inDialog')
self.checkbox = obj.find('dlgCheckbox')

if self.input then
self.input.textinput.mtSelectArea(0, 0, 20000, 20000)
end
Expand All @@ -290,7 +285,7 @@ gui.dialog.message = function(Options)
return self
end

// This sub-routine is provided for languages other than Fluid to utilise the module.
-- This sub-routine is provided for languages other than Fluid to utilise the module.

do
local state = getExecutionState()
Expand Down
1 change: 1 addition & 0 deletions src/core/defs/fields.fdl
Original file line number Diff line number Diff line change
Expand Up @@ -941,6 +941,7 @@ header({ path="system/fields", copyright="Paul Manias © 1996-2024" }, function(
"MatrixRows",
"MatrixColumns",
"Matrix",
"OnChange",
"PathTimestamp",
"PreserveAlpha",
"Pretext",
Expand Down
13 changes: 10 additions & 3 deletions src/document/class/document_class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,14 @@ static ERR DOCUMENT_Free(extDocument *Self)

/*********************************************************************************************************************
-ACTION-
GetKey: Retrieves script parameters.
GetKey: Retrieves global variables and URI parameters.

Use GetKey() to access the global variables and URI parameters of a document. Priority is given to global
variables if there is a name clash.

The current value of each document widget is also available as a global variable accessible from GetKey(). The
key-value will be given the same name as that specified in the widget's element.

-END-
*********************************************************************************************************************/

Expand Down Expand Up @@ -1246,13 +1253,13 @@ static ERR DOCUMENT_SelectLink(extDocument *Self, struct doc::SelectLink *Args)

/*********************************************************************************************************************
-ACTION-
SetKey: Passes variable parameters to loaded documents.
SetKey: Set a global key-value in the document.
-END-
*********************************************************************************************************************/

static ERR DOCUMENT_SetKey(extDocument *Self, struct acSetKey *Args)
{
// Please note that it is okay to set zero-length parameters
// Note: Zero-length parameter values are permitted.

if ((!Args) or (!Args->Key)) return ERR::NullArgs;
if (!Args->Key[0]) return ERR::Args;
Expand Down
1 change: 1 addition & 0 deletions src/document/class/document_def.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ static const struct FieldDef clDocumentEventMask[] = {
{ "OnCrossingOut", 0x00000010 },
{ "OnCrossing", 0x00000018 },
{ "LinkActivated", 0x00000020 },
{ "WidgetState", 0x00000040 },
{ NULL, 0 }
};

Expand Down
1 change: 1 addition & 0 deletions src/document/defs/document.fdl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ module({ name="Document", copyright="Paul Manias © 2005-2024", version=1.0, tim
"ON_CROSSING_IN: The mouse pointer has crossed into an element.",
"ON_CROSSING_OUT: The mouse pointer has crossed out of an element.",
"LINK_ACTIVATED: The user has interacted with a hyperlink. This event can be cancelled by returning ERR::Skip.",
"WIDGET_STATE: The state value of a widget has changed (e.g. input, checkbox, text). `name` and `value` keys will be defined in the event parameters.",
{ ON_CROSSING = "ON_CROSSING_IN|ON_CROSSING_OUT" }
)

Expand Down
2 changes: 1 addition & 1 deletion src/document/defs/module_def.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Auto-generated by idl-c.fluid

#undef MOD_IDL
#define MOD_IDL "c.DCF:DISABLED=0x8,EDIT=0x1,NO_LAYOUT_MSG=0x10,NO_SYS_KEYS=0x4,OVERWRITE=0x2,UNRESTRICTED=0x20\nc.DEF:LINK_ACTIVATED=0x20,ON_CLICK=0x2,ON_CROSSING=0x18,ON_CROSSING_IN=0x8,ON_CROSSING_OUT=0x10,ON_MOTION=0x4,PATH=0x1\nc.DRT:AFTER_LAYOUT=0x1,BEFORE_LAYOUT=0x0,END=0xa,GOT_FOCUS=0x6,LEAVING_PAGE=0x8,LOST_FOCUS=0x7,PAGE_PROCESSED=0x9,REFRESH=0x5,USER_CLICK=0x2,USER_CLICK_RELEASE=0x3,USER_MOVEMENT=0x4\nc.FSO:ALIGN_CENTER=0x20,ALIGN_RIGHT=0x10,BOLD=0x1,ITALIC=0x2,NO_WRAP=0x40,PREFORMAT=0x8,STYLES=0x7,UNDERLINE=0x4\nc.RIPL:VERSION=""20240126""\nc.TT:EDIT=0x3,LINK=0x2,VECTOR=0x1\n"
#define MOD_IDL "c.DCF:DISABLED=0x8,EDIT=0x1,NO_LAYOUT_MSG=0x10,NO_SYS_KEYS=0x4,OVERWRITE=0x2,UNRESTRICTED=0x20\nc.DEF:LINK_ACTIVATED=0x20,ON_CLICK=0x2,ON_CROSSING=0x18,ON_CROSSING_IN=0x8,ON_CROSSING_OUT=0x10,ON_MOTION=0x4,PATH=0x1,WIDGET_STATE=0x40\nc.DRT:AFTER_LAYOUT=0x1,BEFORE_LAYOUT=0x0,END=0xa,GOT_FOCUS=0x6,LEAVING_PAGE=0x8,LOST_FOCUS=0x7,PAGE_PROCESSED=0x9,REFRESH=0x5,USER_CLICK=0x2,USER_CLICK_RELEASE=0x3,USER_MOVEMENT=0x4\nc.FSO:ALIGN_CENTER=0x20,ALIGN_RIGHT=0x10,BOLD=0x1,ITALIC=0x2,NO_WRAP=0x40,PREFORMAT=0x8,STYLES=0x7,UNDERLINE=0x4\nc.RIPL:VERSION=""20240126""\nc.TT:EDIT=0x3,LINK=0x2,VECTOR=0x1\n"
21 changes: 13 additions & 8 deletions src/document/draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ void layout::gen_scene_graph(objVectorViewport *Viewport, std::vector<doc_segmen
DOUBLE y = avail_space - ((avail_space - font->metrics.Height) * 0.5);

combo.input = objVectorText::create::global({
fl::Name("combo_input"),
fl::Name(combo.name.empty() ? "combo_input" : combo.name), // Required for notify_combo_onchange()
fl::Owner(combo.clip_vp->UID),
fl::X(0), fl::Y(F2T(y)),
fl::String(combo.value),
Expand All @@ -659,8 +659,11 @@ void layout::gen_scene_graph(objVectorViewport *Viewport, std::vector<doc_segmen
fl::FontStyle(font->style),
fl::Fill(combo.font_fill),
fl::LineLimit(1),
fl::TextFlags(VTXF::EDITABLE)
fl::TextFlags(VTXF::EDITABLE),
fl::OnChange(C_FUNCTION(notify_combo_onchange))
});

combo.input->CreatorMeta = *combo.viewport; // Required for notify_combo_onchange()
}

if (!combo.clip_vp.empty()) {
Expand Down Expand Up @@ -749,8 +752,8 @@ void layout::gen_scene_graph(objVectorViewport *Viewport, std::vector<doc_segmen

DOUBLE y = avail_space - ((avail_space - font->metrics.Height) * 0.5);

objVectorText::create::global({
fl::Name("input_text"),
auto vt = objVectorText::create::global({
fl::Name(input.name.empty() ? "input_text" : input.name), // Required for notify_input_onchange()
fl::Owner(input.clip_vp->UID),
fl::X(0), fl::Y(F2T(y)),
fl::String(input.value),
Expand All @@ -760,14 +763,18 @@ void layout::gen_scene_graph(objVectorViewport *Viewport, std::vector<doc_segmen
fl::FontStyle(font->style),
fl::Fill(input.font_fill),
fl::LineLimit(1),
fl::TextFlags(flags)
fl::TextFlags(flags),
fl::OnChange(C_FUNCTION(notify_input_onchange))
});

vt->CreatorMeta = *input.viewport; // Required for notify_input_onchange()
}

if (!input.clip_vp.empty()) {
input.clip_vp->setFields(fl::X(input.label_pad), fl::Y(0), fl::XOffset(input.label_pad), fl::YOffset(0));
}

Self->VPToEntity.emplace(input.viewport.id, vp_to_entity { &input });
break;
}

Expand Down Expand Up @@ -800,9 +807,7 @@ void layout::gen_scene_graph(objVectorViewport *Viewport, std::vector<doc_segmen

txt.vector_text.push_back(vt);

DOUBLE twidth;
vt->get(FID_TextWidth, &twidth);
x_advance += twidth;
x_advance += vt->get<DOUBLE>(FID_TextWidth);
}
}
break;
Expand Down
Loading
Loading