This gem was last updated on the 10.03.2024 (dd.mm.yyyy notation), at 15:36:44 o'clock.
Introduction to the Cyberweb project
The cyberweb project allows the user to make use of ruby to tap into web-related functionality in general.
Use cases herein include running ruby in oldschools .cgi script, as well as via sinatra-applications (including storing the code in plain .rb files) or RubyOnRails-applications.
Future goals include offering at the least the very functionality that can be found in webmin (https://webmin.com/) as well as in wordpress (https://wordpress.com/) - stay tuned for this in the coming months and years.
Installing the cyberweb gem
Use the following commandline instruction to install the cyberweb gem:
gem install cyberweb
Alternatively simply download the .gem from the official homepage, at rubygems.org - https://rubygems.org/gems/cyberweb.
Requiring the Cyberweb project
After the cyberweb project has been installed (see the section above this paragraph), you can simply issue:
require 'cyberweb'
require 'cyberweb/autoinclude' # This is the preferred and recommended way for .cgi files.
If you only need certain functionality then you should require the relevant parts as-is; you can also look under the cyberweb/requires/ subdirectory, where common use cases for require-statements, in regards to the cyberweb project, are kept.
The (slightly convoluted) History of the Cyberweb project
The following rather lengthy paragraph shall explain some aspects related to the history of the cyberweb project.
The cyberweb project was created a very long time ago, in about the year 2004 or so - give or take. Back then it was written exclusively in PHP.
I was combining custom functions (in PHP) to control how to serve web-related content back in these days. Mostly the use cases that I had were related to serving local content, that is, different .php files to be served, as well as some local text files. A few of these .php files were hosted externally, though, just to showcase the feature set.
In late 2004, sort of, I transitioned into Linux as my primary operating system. Along with this transition I also started to use Ruby, which eventually replaced PHP for my needs.
The original framework (the ancient code for the cyberweb project) was written (and maintained) in PHP and this origin is in some ways still somewhat similar to the cyberweb project. To illustrate this statement specifically: the original class Cyberweb::WebObject was written at about the same time, in the year 2004, in PHP - or perhaps a year after that, in 2005.
class Cyberweb::WebObject had a smaller use case back when it was written in PHP - less code and fewer methods, but by and large I already had the idea back then to describe a web-site in PHP completely. That is, to generate its content purely via PHP as-is.
I eventually abandoned PHP, as pointed out above, and I went on to rewrite the parts I was using in PHP in ruby. The functionality that was initially part of cyberweb thus originated from a legacy use case. The original use case for class WebObject was to actually describe a web-object, similar to a .html file, but dynamic and adaptable in nature - a higher-order class. A .html page can be generated from an instance of class WebObject, for instance. This use case still remains with the cyberweb project and it existed in the old PHP code too: I want to be able to autogenerate .html pages via the cyberweb project. Of course there are additional use cases, but this is an example of legacy-derived use cases.
The Cyberweb-project was rewritten several times over the next ~15 years or so - actually 18 years since then. Quite a long time ago already.
Today the Cyberweb-project is not quite so similar to the old code base that was written in PHP anymore. The important core methods, though, are still somewhat similar. Let's illustrate this statement with a specific example.
I was using div() in PHP already, as a function call. I am using the div() method in ruby too, through cyberweb, even though a separate project (HtmlTags) is nowadays tasked with autogenerating HTML tags. It was easier to separate this functionality into a separate gem. But, as this example shows, it originated from code I wrote in PHP.
Ruby allows for significantly more functionality and flexibility out of the box than PHP does, so I can do the following in Ruby just fine, by default:
div {
}
In PHP this is not easily possible, because the syntax is more rigid; there are no blocks in PHP, for instance, and you need to carry with you the () to arguments. I find ruby in general more flexible and better than PHP here, but your mileage may vary.
Let's revisit the syntax consideration shown above, via the div {} syntax. I consider ruby to be the better language here, when compared to PHP, as we simply have more flexibility syntax-wise, which in turn helps when we wish to formulate ideas into code (and projects).
This flexibility really helps a lot when writing more dynamic, and more succinct, code. We can define custom DSLs (Domain Specific Languages) that are close to the target area we operate within. See Ruby on Rails and the various active-gems as one example of this flexibility. These allow us to store data in databases in a very expressive manner. You can, of course, reason that complexity should be avoided, but at the end of the day we need to consider the totality of the situation: does that flexibility make us human beings more productive and efficient? I think the answer to this is either yes, or, at the least, it can be - whereas, if you look at PHP, you simply have less flexibility, and, in my opinion as a consequence of this, fewer options.
Going back to the transition phase, where I switched from php to ruby, the cyberweb project was renamed several times as well. The first renaming was done towards web_foundation, then I renamed the project towards cybersprawl, then to Cyberweb, then to web_object and finally back to Cyberweb again. A bit chaotic this is ...
I think the name Cyberweb is the best choice among these alternatives, though. With that name I want to capture "the future" - that is, ideas where web-apps are more integrated and powerful in general. A bit like how Alan Kay envisioned the world wide web. At the least this is a far-away vision to have; perhaps webassembly brings us closer towards that goal. For the time being, we have to use HTML, CSS and JavaScript for the most part of course.
While web_object is the more technically correct and accurate term, as everything related to the www is handled via that object (or such objects), I prefer the name Cyberweb for the whole project - it sounds rather futuristic.
The name WebObject is a good name too, though, as we attempt to describe a particular "web-page" as a "web-object", with specific functionality, basically. The WebObject not only describes the raw HTML code or combines it with CSS and JavaScript, but it can be thought of as a higher abstraction in the hierarchy. In principle we could generate a .pdf file from a WebObject too, so the functionality is not limited to "merely" HTML or CSS only. This is another goal for the project, but it is secondary - still, I want to be able to have a .pdf page too, derived from a .cgi page, a .sinatra page or a .html file.
class WebObject was originally the very main class I was using in PHP to describe my local knowledge base, an "app" where I kept useful information bits about linux, and ruby, and other parts together. The code for this project in PHP was simpler, and also uglier though, and less flexible. (Actually the name was not even WebObject back then, but let's not make this too overly complicated and convoluted; it's already a fairly messy history.)
This knowledge base resides in another gem I maintain, called roebe. This is a separate project, but in order to view the various web-pages of the roebe gem, the cyberweb gem will be needed. (The roebe gem is my primary gem - I use it as a general entry point to all my code. The cyberweb gem is less specific to my use cases; other people could use it just fine for their own web-specific projects, but I have to caution other users in that, despite this, the cyberweb project is primarily catering to my use case. I will try to make the project more flexible for other users too, but it is not necessarily a primary goal of this gem to "appeal to the masses".)
When I switched to ruby, I rewrote all my PHP code in ruby, as stated already; and eventually I did put the web-specific parts into a project called web_foundation, which was the actual predecessor to Cyberweb, as mentioned as well. Cybersprawl was a component of this back then. The initial idea here was to have cybersprawl be the basis for a custom webforum. At a later time, this changed a bit and was extended - cybersprawl not only tries to include a webforum, but also clone all the functionality available in webmin. In other words, to be usable as a webmin clone. This is far from finished, though, and I may never finish - but, even then, this use case remains, so who knows. Perhaps at a later moment in time I can succeed with that goal. The wish to have a web-forum as part of the cyberweb project is still retained.
The original Cyberweb project on rubygems.org was "officially" started on 13.06.2012 (13th June in the year 2012) - that is, the name was first used in the year 2012. In 2020 it came to an end and was replaced with the WebObject project, but in May 2021 the original name was reinstated again. Such a messy history for the win. \o/
The project called html_tags was created at about the same time back then, in the year 2012, in order to keep the code base of the newly generated project somewhat cleaner and smaller. WebFoundation was thus renamed to Cyberweb - the original directory that kept the code there was put under the directory called foundation/. Old gem releases of cyberweb may still show that, back when I kept these old releases on rubygems.org.
In August 2018, the foundation/ subdirectory was removed and the code residing therein put into other parts of the cyberweb project instead. The original functionality that WebFoundation provided was retained.
The transition phase in 2012 happened to some extent because I was still using ruby 1.8.x and had to make several changes to the old web-foundation project, in order to have my code work on ruby 1.9.3 anyway.
The rewrite would allow me to change some design decisions I made earlier on, which were not that ideal - in other words, to allow me to discard some of the old code at the same time (which again happened in 2018, when I cleaned up the cyberweb project, after many years of "semi-activity" only).
The rewrite step worked for the most part, even though it took me significantly longer than expected. While the code base that you can see today is still not "perfect", it is quite ok-ish and also to some extent documented this time - at the least much better than it used to be in the old code before. I will continue to improve the documentation slowly over time. Whenever I do a full or a partial rewrite, I make sure to improve the existing documentation, so one minor goal of every rewrite is to make the project's documentation better.
In my opinion, it is quite common to rewrite web-related projects in ruby in general - see manveru's old Ramaze project, for instance, which unfortunately was abandoned at a later time. (Innate was created prior to that → https://github.com/Ramaze/innate)
Essentially cyberweb integrates what I learned over the years, so I built some sort of "framework" for the web. It is actually not necessarily a framework only as such, but more a tool-set project for the www. There won't be a lot of idioms used such as could be seen in rails - because the cyberweb project is way too simple to make use of complicated idioms. You can even call the cyberweb project a dumb project, deliberately so, on purpose. I do not like the proliferation of complication and complexity that the modern web-era induced onto developers - just look at the amount of JavaScript frameworks that emerge and disappear over the years. Anyone still remember Mochikit? Or the era before Mochikit? Do we have to transition to these again and again and again? Why not abstract these use cases away for us?
The cyberweb project has combined, and thus integrated, the following older components that have existed at various moments in time or may still exist:
- web foundation
- Ruby-CGI (a snapshot, including the excellent cgi-exceptions functionality)
- cybersprawl
- sinatra mapping
This may not be hugely important to know, but it explains a bit of the historic origin for the cyberweb project.
Installing recommended but optional "add-on" gems
The cyberweb project has a rich set of functionality by default.
Users can, at their own discretion, install additions gems, naturally. A few of these gems may enhance cyberweb in one way or the other.
PDF-related functionality is quite important in general, and this is the case for the cyberweb-project as well. It is recommended that users of the cyberweb-project should consider the installation of a PDF-related gem - be it prawn, or, more modern, hexapdf. More functionality may be tied and combined with .pdf files in the long run, as far as the cyberweb project is concerned, to make the cyberweb project a bit more polished in regards to a (viable) alternative to wordpress one day (in the future). Stay tuned in this regard.
Aim, Goals and Scope of the Cyberweb project
This subsection will detail some of the goals of the Cyberweb project.
Before describing the cyberweb project in more detail, please keep in mind that the project is fairly incomplete, not even in an early beta stage; and that it is presently catered to my own use cases, so it may not work for you. Consider it more as a proof-of-concept project than something you may want to use for production. Sinatra may be a much better choice for the latter.
At any rate, let's next see for the aims and goals of the cyberweb project - after all that is the primary purpose of this subsection.
The Cyberweb project is both a collection of web-related tools (thus, a toolset project) as well as a web "framework". Both terms will be defined next.
What is meant with a "set of web-related tools"? This means that there will be code, written in ruby (primarily), that aims to solve problems related to the world wide web, ranging from small to medium-sized issues.
This may also include formatters and linters for e. g. JavaScript in principle, but it can also include file-generators or related to managing files, directories, css files, javascript files, and so forth. A set of tools.
The other part of the Cyberweb project is to act as a "framework", that is - to provide code that can be used for higher abstractions when creating web-apps.
Note that the Cyberweb project itself is not necessarily extremely opinionated. Different strategies may be used, be it MVC (model, view, controller), be it plain oldschool .cgi or be it modern microservices and REST APIs as such, such as used in rack and sinatra/padrino. All can be combined and mixed together - in theory. In practice, Cyberweb is of course limited mostly by my own time investment, so different parts of the project will be more comprehensive (and better) than other parts. The bottom line is that there is "no single strategy to rule them all", as far as the cyberweb project is concerned.
It is true that the Cyberweb project is, in itself, very traditionally focused on the .cgi centric ways to develop web-apps. In theory, a .cgi page could also be thought of as a WebApp. Nothing prevents this really, other than some old assumptions about CGI.
In the long run, expect the Cyberweb project to become more general and hopefully more "modern" as well, as I work on improving the documentation in the next step (no possibility to have more users without high quality documentation).
Since June 2021 two new goals were added to this project:
- It will contain documentation in regards to useful CSS knowledge.
- It will contain documentation in regards to useful JavaScript knowledge.
There are two reasons for this. The more important reason was that I wanted to bundle web-related stuff into one project, and just use that project, rather than dilute this to many separate projects.
The second reason was that I have collected a lot of knowledge over the years about CSS and JavaScript, and wanted to keep them presented (and presentable) in a single project as well. This means that there may be pure CSS, pure HTML and pure JavaScript examples distributed within the Cyberweb project as well.
Since as of October 2023 you can also find a .html page that links to all examples. This file can be found at:
cyberweb/examples/examples.html
(Remember that you can simply extract a ruby .gem file; there the .html file can then be found.)
Features of the Cyberweb project
The cyberweb project attempts to address multiple different use cases, so it is difficult to provide an overview over its features; in part also due to its fuzzy history.
However had, this subsection will at the least try to name some of its features - keep in mind that ultimately it is about the use cases you may have that matter more.
In no particular order, the cyberweb gem attempts to solve these problems:
Provide support for rack, sinatra and .cgi files for "out of the box" working with web-related technology in general.
Provide numerous helper methods in various classes (most importantly in Cyberweb::Base) to help build web-applications.
Be able to generate standalone .html files.
Provide a unified DSL over web-related use cases.
Support CSS-related aspects, including auto-generation of CSS code and re-using CSS templates.
Aim to provide a webmin-clone.
Aim to provide a wiki.
Aim to provide a webforum.
And many more use cases that are somehow related to these goals.
Not all of these use cases currently work fully; the cyberweb gem in many ways is also there to help me experiment with different ideas, and try to see what could be done to make these work.
A word about "CSS templates": you can select various different default CSS templates. They will be stored in the cascading_style_sheets/ directory by default. To use them, pass a symbol to the method invocation for css_style=(). They are numbered in succession, so template1, template2 etc..
Example for this on the main w object:
w.css_style = :template1
This will default to the template1.
Alternatively since October 2022 you can simply use this, if you work with a WebObject:
template1 '
# your CSS rules go in here
'
This will pull in the first template (template1) and then add the CSS rules towards that.
Currently the way to add new templates is to expand the case menu.
Adapting the cyberweb gem to your use cases
Presently it may be a bit difficult to adjust the cyberweb gem to your use cases. The primary reason for this is that the cyberweb gem was originally started to support my use cases, as well as making available images that I have collected over many years. So that explaines why the method img(), for instance, is defaulting to a fairly weird use case, which means that it may not work for your use cases initially. In the long run I intend to remedy this situation, but for the time being, you have to accept that some parts of the cyberweb gem are not useful for you.
Note that the above is no longer true since as of January 2023. I have decided, for several reasons, to simply distribute these images as well. They are available under:
cyberweb/images/standard_images/
You can also view these images via a dedicated .html file, at:
cyberweb/images/standard_images/standard_images.html
Some of these images are fairly old and require adaptations/changes, and adding these images has made the cyberweb gem significantly larger as well, which is not great - but I think the drawbacks are outweighed by the advantage that now every user of the cyberweb gem can use these images as well, without me having to offer separate download links. I collected these images over the last 20 years, and some are probably outdated at this point in time, but again - some images may still need to be tweaked, file sized decreased, simplified, and what not. I will do so over the course of the coming months.
I decided to add this subsection to document some things, and provide some help to new users, until eventually the situation improves so that people can just install the gam and "it will work", as-is.
Without further ado, let's clarify some things here next.
The cyberweb gem needs access to a temporary directory.
On Linux this is typically /tmp/. The cyberweb gem may create a subdirectory there, called cyberweb/, and then copy some files into that subdirectory - in particular JavaScript .js files. (If you have difficulties here, consider adding such a subdirectory there, with explicit permissions to allow people to dump data into that directory - after all that is the point of /tmp/ on linux.) If that step fails then you may have to copy these files manually for now; in the future this manual step may no longer be necessary, but as of May 2023 it still has to be done - apologies for that extra time investment.
To query the base directory in use you can call the following method:
Cyberweb.temp_directory?
If you want to use another temporary directory then you can use this method:
Cyberweb.set_temp_directory('/opt/')
You need to make the permission bits on that directory possibly to be modified, such as /tmp/ on Linux normally is able to be modified by group and user nobody (or, the user that runs the webserver; in my case this is typically lighty, as I use lighttpd as my primary webserver).
The code for this functionality can be found here:
cyberweb/toplevel_methods/temp_directory.rb
Or the direct require command:
require 'cyberweb/toplevel_methods/temp_directory.rb'
This is a very important first step to do, to adjust the temp directory to your use case.
I may add more code support for this step in the future; for now (October 2022) I just wanted to document this, so people know where to look for changes in this regard.
Include the cyberweb project on a website
To include the cyberweb project on a website, in your .cgi script for instance, do use this line:
require 'cyberweb/autoinclude'
You can then populate the @web_object object, which resides in the main Cyberweb-namespace, and which is also aliased through a convenience method called w(). If you autoinclude Cyberweb then you can use the w() method directly.
This allows you to describe a webpage, such as by issuing the following code:
w {
title 'My first homepage'
body_css 'mar1em'
h2 'Hello World!'
use_jquery
}
Note that this should happen on separate lines - the description
here for the gem does not replace newlines with the html
tag.
Inside w {} you can issue special instructions, such as use_jquery or disable_webimages. The former allows us to use jquery, the latter disables webimages. (Webimages are small icons that I find myself to use a lot. If you wish to use these images, have a look at
http://shevegen.square7.ch/STD.tar.xz
)
Proper (default) order of arguments to many methods in the Cyberweb project
The Cyberweb project uses quite a few methods that have more than 4 or 5 parameters.
The typical order for these methods is the following:
(1) the content belonging to the tag at hand (2) the css class that is to be used for that tag (defaults to class WebTag) (3) the id to that HTML element (optional) (4) the css style for that tag (optional) (5) javascript code to that tag (optional)
Cyberweb.set_path_to_images
The method Cyberweb.set_path_to_images() can be used to set the path to a global image directory, that is - a directory that holds all images. On my home system this defaults to /home/x/data/images/, so if you find any references to that directory in any of my projects then this is the reason as to why, since it is the default on my home setup.
I put almost all images into this directory as-is, but there are a few exceptions to this as well. The important thing is that the cyberweb project has to remain flexible.
Note that this directory will only be of relevance if the configuration options for the cyberweb project were set up to use such a directory in the first place. Only image-related methods are affected by this setting anyway.
Note that Cyberweb.set_path() is a shorter alias to this method; may be useful in IRB. Otherwise I recommend to use the longer method name instead, as it is more explicit.
For many users this API may be fairly irrelevant or even cumbersome. In that case you should consider uploading some of your images to a remote server and then simply link towards these images rather than having to deal with paths to local images being a nuisance. I do that with some of my files, e. g. referring to a FTP site. In the long run, though, this situation will eventually improve.
Images
If an image is not existing, but used within the Cyberweb framework, then a a red border and a red text will be displayed around that (non-existing) image.
This way, the user is being encouraged to fix the problem at hand.
However had, it may also be annoying to see it if the user can NOT fix/change this.
This is why the red warning or warnings in general, can be reduced or disabled - have a look at the configuration file for this. Personally I prefer a red warning, but others may not want to have this.
If warnings are set to verbose, then the cyberweb project will display the notification mentioned above for all images that were not found. If it is set to normal or lower than that, the cyberweb project will not display that warning.
Greek letters
The old greek letters are specified via shortcuts such as σ in HTML. The σ variant would display the small sigma character; the constant SIGMA_SMALL or just SIGMA will allow you to refer to this constant within the Cyberweb project.
You can output a table with all available greek letters by issugin the following command:
Cyberweb.show_greek_letters
Commandline usage
A commandline program exists, at bin/cyberweb.
This file allows you to generate a new file-skeleton, such as via:
cyberweb foo.cgi
cyberweb index.cgi
You can also get some feedback over what it can do, via "cyberweb --help".
The interactive web_object-shell
There also exists an interactive cyberweb-shell, which may be used to test out various things - but it is fairly unfinished, so I do not recommend anyone to use it as of yet (2018).
The idea is to have this work as some kind of developer-console where web-related activities can be tested.
HtmlTags
Since as of cyberweb version 0.0.5, a dependency exists on a project called html_tags, which was created in order to separate the generation of HTML tags out from the rest of the framework.
The idea is to hold a full HTML page in a special object, the so called "web_object", and to then .serve() said object when it is required. Which essentially is done through a .cgi page.
Since as of April 2019, the old .cgi approach will be extended; while .cgi will be always supported in the Cyberweb project, an approach similar to sinatra will eventually be adopted as well.
Configuration - and editing the configuration file (which is a yaml file)
Keep in mind that you can modify a lot of the configuration that the Cyberweb project uses, through the yaml files stored in the configuration/ subdirectory.
If you need to display the configuration settings via web-page, you can always use the method .show_config(), on the main Cyberweb, such as via either of the following code:
w.show_config
div('mars3em') { w.show_config }
You can also just show the configuration setting without depending on the web-object, through this module-level method:
Cyberweb.show_configuration_settings
The main configuration file, a .yml file, can also be modified through a commandline "interface", via:
cyberweb edit
This presently uses a hardcoded value (towards the editor called vim).
You can also query the current configuration via appending config? such as in:
http://localhost/data/personal/sitemap.cgi?config?
HTML Tables and the Cyberweb project
The method table() is the primary entry point for table-related tags. The first three arguments are:
css class to use
ID of the table
css style to use
You can also, optionally, pass in a dataset to the table, such as an Array, via a block argument.
The following example shows how to do that:
table('mars1em','test_table1','border:1px solid rand') { %w(
this is a test table1 with every individual
entry becoming populated into the table
)}
The part after the {} constitutes the Array that is passed into the table.
By default this will use two td-elements, aka table data elements. The third element goes on a new line, aka via a closing tr tag (in HTML parlance).
Note that you can use variants of table() if you need a different amount of td tags.
For example, table4() can be used to denote a table with 4 elements per row:
table4('mars1em','test_table1','border:1px solid rand') { array_goes_here }
You can also set global CSS classes to class Table:
Table.set_css_class 'bblack5 pink_border3 marl2em mart1em'
For a longer explanation of that .set_css_class() functionality, have a look at the link here at HTML Tables and the Cyberweb project.
Note that you do not have to supply any arguments to table() aside from the dataset given into it as block - a simple Array will suffice:
table { pass_array_here }
You can also style each td element, such as by tagging them with a block border:
Td.set_css_class 'bblack1'
table('mars2em') { %w(
This is just an example Array
)}
Td.set_css_class ''
The last line of code will again clear the default set to Td.
The name cyberweb
You may wonder why the name used to be cyberweb.
There is not a single good reason for this other than, firstly, I thought it was related to the web - so I included web. And cyber? Well, I like science fiction; and cyber sort of fits to the www too, at the least to some parts.
The idea for a "social" web, from the point of view of the older web-foundation project (the predecessor to the cyberweb project), was to call this the "cybersprawl". The name cybersprawl would indicate a virtual meet-up place for people.
This may sound a bit confusing but it is sort of how the name gradually evolved - and eventually became cyberweb, before it was renamed to web_object in 2020. And at a later time back to cyberweb - yup, I change the project names way too quickly. But the name used to by cyberweb in the past, so I am slowly getting used to that name.
HTML Entities
If you wish to remove HTML entities from a given input string at hand, you can use Cyberweb.escape_html() or one of its alias.
Example:
Cyberweb.escape_html('abc') # => 'abc'
x = '<p>this is ( ) a test</p><div> Ok -& outcome will be </div>'; y = Cyberweb.html_entities(x) # => "<p>this is (&nbsp;) a test</p><div> Ok -&amp; outcome will be </div>"
Specifying a monospace font to use
The Cyberweb has a method that allows you to use a monospace font.
Within your Cyberweb instance, such as:
w {
}
You can add any of the following two lines:
use_monospace_font
monospace_font
This will use a monospaced font. I needed this functionality because I sometimes use the pre-tag, and display numbers in a table-fashion, for where it may be useful to use a monospaced font, so that the alignment of the text is easier.
The WebObject (Cyberweb::WebObject)
The following subsection will contain information pertaining to the most important class of this gem: WebObject.
This is the primary class that is used for describing a web-application (or, in oldschool parlance, a HTML object or HTML page).
Setting the date-of-creation for a web-app based on WebObject
Since as of October 2021 you can use:
created_when '20.08.2021'
To indicate when the webpage at hand has been created. This will then add a meta-element to the page, which is roughly equivalent to:
<meta name="DCTERMS.created" scheme="DCTERMS.ISO8601" content="2010-03-17T13:31:50"/>
I am not sure whether this is super-useful or not, but I wanted to add a method that keeps track of the creation-time of web-apps based on web_object, which is the main reason why this functionality was added. At the least it helps me remember when a web-app was created.
Default hyperlinks
The default styling for a-tags in HTML is to start with text-decoration: none, and upon a hover event change towards text-decoration: underline.
Since this is so commonly used, the method .default_hyperlink_behaviour() can be used to add the CSS rules for this, as-is.
Setting a title on a webobject
You can set a title on the default webobject via:
set_title()
You can omit this call, in which case we will default to the filename of the page in question, such as for a file named foobar.cgi, the corresponding title would simply be "foobar".
You can also use markdown files if you want to. I personally use a file such as TITLE.md or TITEL.md. The method call will try to read in the file content, and then use that as the title, if the file exists.
The default image directory
The default image directory is defined in default_image_directory.yml
At least the name of the image directory.
Viewing the source of a webpage
Use the view_source() method to add a javascript button, to view the source of a page. The method view_source() is defined in the file cyberweb/web_object/misc.rb:.
You can, of course, combine this with other code elements. For instance, if you want to embed the view-source button into a div, and style it, then consider the following:
div('BG_Black white','div_view_source') { view_source }
This will create a div-tag with black background and white font colour, and the id of that div will be div_view_source. Inside that div-tag the view-source button can be found.
The table-tag
The tag that is generated via table() will create a HTML table. It also supports blocks. That means you can use arrays in tables as input, such as shown in the following example:
table { %w( one two three for ) }
Or, styled with CSS:
table('s1em bblack1') { %w(one two three for) }
You can combine fieldset with table and a caption, by doing:
table_with_caption('title of caption goes in here')
Hiding / disabling scrollbars
You can use:
in the main web_object to hide the scrollbar, by making use of CSS. I recommend against this, because it may annoy some users, but it was enabled because sometimes there may be use cases to NOT have a scrollbar at all.
The idea was taken from:
https://www.w3schools.com/howto/howto_css_hide_scrollbars.asp
Showing the source code of a particular file
By default every file that is part of the cyberweb project can show its source to the visitor, by appending:
?source
?view_source
to the URL.
For example, on my home system I make use of this like so:
http://localhost/data/video/play_this_video_file.cgi?source
Evidently this is not always wanted and will, in the future, have means to disable this (or selectively enable it in the configuration file). But for the time being (January 2020) this is the way how things work - after all, even with criticism about this functionality, it is a feature too.
HTML header tags
HTML has, by default, different header tags, starting with h.
For example we have:
<h1>This is h1</h1>
<h2>This is h2</h2>
<h3>This is h3</h3>
<h4>This is h4</h4>
<h5>This is h5</h5>
<h6>This is h6</h6>
The corresponding generator in Cyberweb is:
h1 'This is h1'
h2 'This is h2'
h3 'This is h3'
h4 'This is h4'
h5 'This is h5'
h6 'This is h6'
If you also wish to make the content displayed there as the id="" setting, then you can use:
h1_id 'This is h1'
h2_id 'This is h2'
h3_id 'This is h3'
h4_id 'This is h4'
h5_id 'This is h5'
h6_id 'This is h6'
The id at hand will be the content, so this is more useful for short header-entries, such as "Goals" or "Aims" or "Introduction" and so forth. The latter functionality purely exists due to convenience - I wanted to quickly generate the default id entry for a sitemap.
Note that at the least h2_id() has been improved a bit, directly and indirectly, in January 2023.
Specifically the following is now valid:
h2_id('Stickstofffixierung - eine symbiotische Beziehung, als '\
'Teil des Stickstoffkreislaufs') { :clickable_image }
So, what does this do?
First, as normal, it will "autogenerate" the corresponding ID entry, via the newly created method .sanitize_this_id(). I intend to re-use this method for all other parts of the cyberweb gem that require autogeneration of valid ID tags.
But, even more importantly than that, the block and the Symbol called :clickable_image, will now add an image (a small dot) to the left side of this header. This image is clickable by the user. If the user clicks on that dot, he/she will be re-directed to that specific header as intralink. In other words: this functionality allows us to "tag" any paragraph as intralink, by clicking on it.
I needed this functionality for many different local websites, so I thought it was more useful if it is made a proper method as-is.
Redirecting to another page
You can combine BeautifulUrl, and Cyberweb, to redirect to another page.
Example:
http://localhost/data/misc/sitemap.cgi?redirect_to=ruby_todo
This would redirect me to my local todo-file in ruby. In fact: that was the primary reason why the code was added, so that I can use the web-server as a pseudo file system.
Evidently not everyone may want this feature, so in the long run this may have to be modified - but for now it will remain as it is. It can be used to quickly "jump" to another page, both a local page or a remote page.
If you want to do so via the meta-tag, consider using the following method:
Cyberweb. 'foobar.de'
This would yield the following string:
<meta http-equiv="Refresh" content="1; URL="foobar.de">
Viewing the content of any file
You can view the content of any file via:
http://localhost/data/personal/sitemap/sitemap.cgi?view_file=ruby_todo
This can be disabled since as of May 2021, by setting the view_file: true in the project configuration .yml file. I recommend to do so, as you probably don't need this functionality. I needed it for my local webserver, to quickly test things, and view local files in the browser, no matter where they reside (which is handled by another gem, which is not published, as it is for internal use only).
dropdown()
You can use the dropdown() method to use several <select> statements, if you use class Cyberweb::WebObject.
Specific usage examples:
dropdown( %w( a b c ) )
dropdown( %w( a b c ) ) {{ selected: 2 }}
dropdown( %w( a b c ) ) {{ selected: 3 }}
The middle variant will have the second entry selected as default; the last variant will have the third entry selected as default.
Note that for the purpose of dropdown() we will begin to count at 1 rather than 0. So 1 refers to the first entry. Furthermore if the number given to selected: is too high then it will be automatically reduced to the last entry of that Array - this should simplify using the method a little bit.
For a working example of the method have a look at the file testing_the_select_tag.cgi.
Here is also a small screenshot with a bit of CSS styling to show how this looks:
Cyberweb.display_all_files_in_this_directory
The method Cyberweb.display_all_files_in_this_directory() can be used to simply and quickly display the content of all files in the given (target) directory.
Example:
Cyberweb.display_all_files_in_this_directory '/tmp'
I needed this functionality because I had many standalone .py files holding matplotlib code and I needed to display them, so this functionality was added in May 2020.
Register on-click events
If you want to register an on-click event and change the opacity value of an element, you can use this method:
on_click_change_opacity '#drag_notepad','0.95'
The first argument is the ID of the target element, and the second value is the opacity value - the lower that value is, the higher the opacity (and thus, the highlighting).
Note that you can also combine this with a drag-action. For instance, the symbol :drag_and_highlight means that we will combine both actions here, thus allowing a drag-object action, and also a on-click-highlighting action on the same object.
Body id
To set a body-id for the Cyberweb, you can use something like this:
body_id 'foobar'
set_body_id 'foobar'
This is equivalent to:
<body id="foobar">
Not a huge saving per se, but if you just want to keep a separate entry for the id of the body, you can use this method on a web_object instance.
Editable text
HTML5 allows the visitor to modify text on a webpage (although not persistently).
The Cyberweb project also allows this. Example:
e('Type something here.') { :editable }
This would make a span-tag, following by a br-tag, and the attribute that this is editable. You can select some text and then just type as-is - and thus modify the text.
Caret cursor in CSS and cursors in general
You can style the colour of the cursor that appears in an input-field.
Example for this:
.input_field {
caret-color: tomato;
font-weight: bold;
font-size: 30px;
}
If you need a specific example, have a look at the following file:
cyberweb/examples/css/caret_colour_example.html
This may then look like this:
The relevant part is the red cursor in the ~middle in that input field.
If you have a use case for a web-page having some different cursor, you can use this for a given Cyberweb::WebObject:
cursor :wait # signals that the program is busy.
cursor :help # signals that help-information is available.
cursor :crosshair # signals that a selection is possible/needed.
cursor :grab # signals that this element can be grabbed via the mouse/pointer device.
CSS helper code and how it relates to the Cyberweb project
This subsection attempts to detail how the cyberweb project relates (and makes use of) CSS.
All my custom CSS rules are distributed in the subdirectory called cascading_style_sheets/. You can find files such as colours.css or default.css and so forth. Furthermore I have a local directory at /home/x/data/CSS/ which contains symlinks to the subdirectory cascading_style_sheets/. This was done mostly because it saves me some typing-work on the commandline.
CSS can, in principle, be accessed through the predefined global object named @css.
This object can be accessed via "css" or via the helper method called css(). (Remember that you can omit the () in ruby).
A specific usage example would look like this:
css.
The idea here was that we could treat all the CSS code in any given web-app as an object too, and manipulate it if needed.
Additionally, we would also be able to modify default CSS assignments given to some methods, redefine them and so on.
Do note that since as of 2020, I am no longer as convinced that this is really that useful. So consider this a bit of work-in-progress rather than a finished solution that other people should use.
For instance, to change the default for the HTML tag h4, the following code could be used:
css.h4.custom_css = 'padl1em'
The idea here was to be able to re-define which custom CSS class is to be used. (padl1em is my abbreviation for padding-left: 1em)
An alternative syntax exists as well - this is the better way, in my opinion, and should be used:
Table.set_css_class 'bblack5 pink_border'
Div.set_css_class 'mar3em'
I personally like explicit setters like the above, but the following variants are equivalent:
Table.css_class = 'bblack5 pink_border'
Div.css_class = 'mar3em'
Future goals for the Cyberweb project
There are a tons of things I always wanted to add or have available in a web-toolkit - a simple webforum; a blog engine and system for managing the content therein; the possibility to easily scrape remote websites, with code that is simple to understand, write, use (via a web-interface) and maintain. And many more goals - in short, to use the browser as the main tool.
Inertia and laziness is one (or two) reason(s) why these goals have not yet been implemented, largely because I find myself facing non-web related issues more often than web-related issues. So naturally, more of my time goes into non-web related issues. Furthermore, I really dislike JavaScript - if only we could describe everything via Ruby instead ...
For the design of the Cyberweb project (and I am aware that a LOT of it could be improved here), I am wondering whether it would not be better to actually replace all of the dichotomy out there in regards to the www, with "one language to rule them all" as a solution. I don't even refer to ruby primarily as such, even though Cyberweb is evidently written in ruby - but what I mean is ... consider the following ...
Why do we have to write JavaScript? Why do we have to write CSS?
Why can't we let our computers actually generate the "logic" behind these programming languages or markup languages?
For example, take:
set_font 16
This could mean a (any) font with 16 pixels in size.
It's quite simple to use this from within Cyberweb:
w {
set_font 16
}
Done!
We could even get rid of the '_' there perhaps:
w {
set font 16
}
Don't mind the "set_font" name; we could easily use this (or allow several aliases):
w {
fontsize 16
}
Or:
w {
font size 16
}
(The w is a shortcut to tap into the web-object instance.)
The primary thing of note here is - why would we HAVE to use CSS in order to style a webpage? Why not use, in this case, Ruby? Or any other language for that matter? Ideally one language to describe all these disparate languages (HTML/CSS/JavaScript) and the logic found in them.
Based on this thinking, when you apply this on everything, including JavaScript, you actually should be able to write something that is simple and works - and have ruby interprete it correctly. Or perhaps another language, similar to how LLVM works or perhaps the WebAssembly project, to some extent.
So, for example:
on_mouse_click highlight_id('mouse_pic')
on_mouse_click highlight_id(:mouse_pic)
Now, if you as the visitor are to click on this, say, a button or some other container element, you would highlight the element that has the mouse_pic id. This is quite easy to do via jquery as-is, but why even have to think about JavaScript at all?
I would like to have a platform where I can do simple manipulations, without having to worry about the underlying code implementation AT ALL.
So, this would constitute one future goal for web_object - to be able to do tasks, from Ruby, and have it applied to the whole Cyberweb component.
Note that WASM is in some ways a bit similar to this, in the sense that we become less dependent on JavaScript than before, since we can also use other languages. Of course this is still a far cry away from using just one format to describe everything, but still, it helps break up the monopoly of JavaScript, which is good that this happens. That way we aren't as imposed by the constraints that JavaScript puts onto us here anymore (in theory, at least).
Saving (storing) the content of the main web_object into a local file
You can save the main string into a file quickly, by using:
save # or web_object?.save
Note that this will save into the temp-directory. Your webserver needs to have access to it, as otherwise no file can be saved.
It may be simpler to use the last option, because of the main doc {} clause that is only finished after the w {} has completed.
That toplevel web_object? call taps into the main web-object.
Favicons
Favicons are small images that may be shown in the tab of the browser. I consider them potentially cute and even useful, as it may allow the user to quickly look for specific images through the browser-tabs.
According to this blog https://getkiss.org/blog/20191004a all among the major browsers will request a favicon, even if one has not been set. This evidently wastes a tiny bit of bandwith.
If you wish to avoid this then you can simply inline a favicon. The smallest "inline" favicon which which ensures zero HTTP requests is the following:
<link href=data:, rel=icon>
You can do so in Cyberweb too, as part of the Cyberweb class, via:
favicon :inline
favicon :minimal
favicon :none
Use any of these three variants and it will lead to the above minimal "inline" favicon. This is admittedly not too overly useful, but the functionality was added nonetheless simply as a proof-of-principle. And, who knows - perhaps the web_object project will one day also offer support for "minimal webpages".
rem units in CSS
In the past, the em unit was quite popular in .css files.
Since some years, such as 2011, rem units are increasingly more popular - see articles such as https://www.sitepoint.com/understanding-and-using-rem-units-in-css/.
I have not yet decided whether to use rem units or not, but I am aware of the differences. I may be too used toward em to transition into rem, and add more complexity that way - but for the time being (August 2020) nothing changes in this regard.
The td_row() method
The Cyberweb project has support for <td> tags, via td() method calls.
Since inputting an Array of values padded with a td-tag is quite tedious, the method td_row() was added.
An example may be simplest to demonstrate this method:
td_row( %w( 256 128 64 32 16 8 4 2 1 ) )
This will generate valid td-tags for each of the given Array member, thus shortening the HTML code generated.
The WebImages components
WebImages are essentially just a small component of the Cyberweb project, available under the namespace Cyberweb::WebImages.
Since as of July 2020 the web_images component resides under the subdirectory at web_object/images/.
WebImages provide a way to map certain symbols, such as :big_star or :rainbow_circle, to a corresponding image.
To give another example for this: the symbol called :alert could be interpreted as showing a small icon that is useful for notification towards the end user. This is usually tied to a particular image, which is displayed on the webpage.
In the past, up until September 2020, these images were not distributed with the web_object gem for various reasons - one was that the .gem would become quite bigger. In September 2020 this approach was changed, and the WebImages are now also distributed as images. Some of these images were autogenerated via ruby code; others were "hand"-drawn in photoshop, kolourpaint or gimp, and others were re-used from permissive sources/licences. The licence for the images is different for the code: CC BY 4.0 (Attribution 4.0 International; see the following URL https://creativecommons.org/licenses/by/4.0/ ).
Do note that even prior to September 2020, in May 2019 I modified the prior assumption that no images are bundled within the web_object project slightly - some images were distributed within the web_object project, but not as an "actual" image; instead, they were (and still are) available as base64-encoded Strings. The following subsection describes how to make use of such base64-encoded Strings.
First, we have to limit the above statement - not all images will be distributed as base64-encoded Strings, only those that may be somewhat useful to lots of different people. Simple elements such as a dot, or an arrow-image - the latter could be used to indicate which hyperlinks could be clicked on a website, for instance. (You can also use the Unicode symbols in general, of course, which does not require any .png file or base64-encoded String. In some ways, Unicode has actually made it a lot easier to work on web-projects without needing to bundle specific images as such.)
Note that some websites claim that Base64-encoded Strings load up faster than e. g. loading up .png files. This may or may not be the case, but what we do know is that base64-encoded strings will be somewhat larger than the corresponding binary image. So I think this statement about a speed gain is really only true for smaller images at best - which is an advice that is repeated on the www in general, small is beautiful, and fast. So we will limit this approach mostly to smaller images in this context; this makes it a bit simpler to distribute the web_object gem as well.
If you want to see the available images, you can use this method to help you:
Cyberweb.display_the_registered_base64_images
In September 2020, this would tap onto this Array:
["AUSRUFUNGSZEICHEN", "BLUEARROW", "BUBBLE", "CAT", "CAUTION",
"CHEERING_PERSON", "CURSOR", "DUCKY", "DOT_01", "ELEPHANT",
"HALLOWEEN", "HANGING_MONKEY", "LENS", "TU_WIEN_LOGO",
"VOGEL"]
So, 15 images are so far made available as base64 string-encoded images.
Note that the images can be found under this directory:
web_object/images/real/
Unfortunately a major design constraint (aka a major bug) was discovered on 18.09.2020 (September 2020), leading to the reversion of this change. I may at a later time re-evaluate this; in the long run I really want to include these images too, by default. But since that change broke a lot of code in my own web-apps, I had to revert this for the time being. This will eventually be fixed, but it requires some larger rewrite, and I don't quite have the time commitment for this right now (it will include some architecture changes in the web_object library as well).
In June 2021 experimental support for arbitrarily converting image files to base64 strings was added to the Cyberweb project. This currently depends on imagemagick, so make sure to install it first. This is highly experimental, so do not yet use it. The idea is that we will simply convert any image to base64 if the user wants to do so.
The API currently looks like this:
img_base64 'STD/ZAUBERHUT.png'
This refers to my base directory for images; and then the path within that base directory.
This is currently only tested on my home system. At a later time I'll add support for any image-conversion, and most likely a cache system, to not have to decode all these images again and again and again. Instead, to just convert it once; right now Cyberweb always converts this, as that was easier to do in code.
You can also make this image draggable via:
draggable_img_base64(path_to_the_image_goes_in_here)
The Application Root
A typical web-related project needs to define and designate the starting-point directory. This is often called the "application root". The Cyberweb project will also refer to the base directory as the application root.
Presently Cyberweb uses a hardcoded approach mostly (sorry), but eventually it will transition into a more flexible approach.
Buttons
Buttons are user-elements that can be clicked.
The following should work, in principle:
{}
My long-term goal in regards to the above is to make this DSL work in web-applications as well as in 'traditional' toolkits, such as the ruby bindings to GTK (ruby-gtk).
A box-shadow effect applied to a button may yield to a depth effect for that button.
An example for this follows:
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
See also the file at cyberweb/examples/html/buttons_example.html to see differently styled buttons in action.
How to vertically align any element via CSS
You can use:
display: flex
display: flex specifies a Flexbox layout for the element.
You can also use align-items: center, which would take care of the vertical centering in a container-element.
The CSS property shape-outside can be used to allow geometric shapes to be set, in order to define an area for text to flow around.
Example:
.shape {
width: 500px;
float: left;
shape-outside: circle(50%);
}
You do not need to use the flexbox, though. An older way is to define three div elements, such as by using these CSS classes:
.left {
display: inline-block;
width: 30%;
height: auto;
}
.middle {
display: inline-block;
width: 30%;
height: auto;
}
.right {
display: inline-block;
width: 30%;
float: right;
height: auto;
}
Use the variant that more suits your way to think about things. I actually prefer the oldschool div-CSS approach and avoid flexbox altogether. Keep it simple! \o/
This is not equivalent to a grid, though, in particular if you want a layout such as 3x3. In that case I recommend to use a grid. Example for this can be seen here:
https://codepen.io/chris__sev/pen/bYmpxw
Working with Frames
You can use Frames.
This example shows how, in the main frame:
w.frame_left 'foo.cgi' # specify frame to the left w.frame_right 'bar.cgi' # specify frame to the right w.use_frames w.serve
Working with Grids in HTML/CSS
You can add padding between the grid containers using grid padding or row-gap and column-gap. This is a general CSS feature implemented for Grids specifically.
Examples for that, in particular the two last lines:
gap
row-gap
column-gap
row-gap: 6px;
column-gap: 6px;
Colours and the Colour chart in the Cyberweb project
If you wish to show a HTML colour chart, you can use the following method:
Cyberweb.show_html_colour_chart
If you want to return a random HTML colour, as a String, you can use this toplevel method:
Cyberweb.random_colour?
Show directories
If you wish to display directories from somewhere, use the method:
display_directories()
Predefined methods
Some commonly used methods are predefined, such as:
question() answer() frage() antwort()
This is mostly because I use them quite often personally.
They are defined in:
$CYBERWEB/predefined_methods.rb
Disabling web images
You can disable the webimages component even in an URL by issuing:
?disable_webimages
Of course you can also disable them through a configuration setting, in the configuration file - see the other command "cyberweb edit" how to edit that file. The idea is to allow several ways to achieve the same effect.
Modifying the configuration of the cyberweb project
The configuration is stored in a single yaml file. This file can be edited by issuing:
cyberweb edit
For a full listing of options, issue:
cyberweb --help
or
cyberweb HELP
The base directory
The base directory can be defined through the yaml file, with the entry called base_directory.
Standalone .cgi files
You can load standalone .cgi files, by supplying the path to the .cgi file in question.
Be careful however, we will use eval() to load that code.
Usage example for this:
load_cgi('bla.cgi')
or the alias:
run_cgi 'bla.cgi'
Support for markdown
You can use markdown formatting via the method markdown().
Example how to use markdown:
markdown(i = '/home/x/data/PC/MARKDOWN/example.md')
Tables with alternate backgrounds
You can use tables with alternate background such as by doing the following:
Table.alternate_backgrounds(%w( one two three four ))
The following partial screenshot shows how this may look like, via an additional black border, to indicate where the table begins and starts:
The two classes are currently (September 2021) called dark_background and light_background, respectively. Never mind the name - if you want to style them differently then simply modify these classes in your web-page. Right now this is not trivial if you re-use the distributed .css files; at another moment in time the API may be changed to allow you to re-define the CSS class as-is.
Editing content on a webpage
You can make some content editable. This currently (March 2017) only works for the e() tag, which creates a span-tag.
The command for this is:
{ :editable }
To do this, try:
p {
e('This text should now be editable.') { :editable }
}
Configuration
All meaningful options that can be configured, can be configured via a yaml file. Settings such as the global font size and so on.
This is stored in the file cyberweb_configuration.yml.
Do simple counting via list()
Do simple counting via list().
list "one"
list "two"
list "three"
To reset it again, do:
clear_list
or:
reset_listing
To use a specific CSS style for these listings, do something like:
Cyberweb.listing_css = '<b class="red">'
You can also make use of ordered lists, via:
ordered_list %w( cat dog parrot deer horse )
This would yield exactly this String (if you use Cyberweb::WebObject):
<ol>
<li>cat</li>
<li>dog</li>
<li>parrot</li>
<li>deer</li>
<li>horse</li>
</ol>
Link in pages via link()
You can link in other pages via the method link().
This method also accepts '*', in which case we will try to use Dir.glob (or more accurately, Dir[])
Specific Usage Example:
link 'BIOCH*/BIOCHE*.cgi'
The licence of the Cyberweb project
Since as of May 2021 the cyberweb project is using the MIT licence.
You can read the requirements for this licence here:
https://opensource.org/licenses/MIT
Before May 2021, cyberweb used the GPLv2 licence. The reason as to why the licence was changed was mostly because I consider the cyberweb project to be not extremely "important" in regards to mandating that the GPL-specific restrictions should apply. I ultimately don't quite care about the licence in regards to the cyberweb project. If others find the project useful then this is fine. If they want to contribute code, that's fine - and if they don't want to, that's fine as well, as far as the cyberweb project is concerned.
Cyberweb.string_image()
The method Cyberweb.string_image() can be used to return a proper HTML img tag, as String. This can then be used to embed it into some website.
The input to this method will be an Array, since we use *args there. The first entry should be the URL to the image at hand - this can be a local URL or a remote URL.
A Hash can also be given. Such a Hash should have a key called :url to denote the image.
Note that the method Cyberweb.string_image() is quite long, in order to cover for different use cases. The document here will not detail all these options, but a few may be explained next:
:guess_id # This means that the ID will be "guessed" based on the filename at hand.
:guess_draggable_id # This is as above, but will prepend the string 'drag_' before, to allow for dragging the image at hand.
Personally I use :guess_draggable_id usually, as it helps me remember what this is doing. :-)
To make all images draggable, use this API:
all_images_will_be_draggable
enable_drag_all_images # Or this variant.
Drag and drop support in general and drag-and-drop support via Dragula
Via the new attribute draggable="true" it is possible to drag any element in HTML. An image can simply contain set this attribute.
The JavaScript library Dragula is used, aside from jquery, for drag-and-drop support.
If you wish to make use of it, keep the dragula-related entry set to true in the file project_configuration.yml.
Example:
use_dragula: true
Keep in mind that the ID for a HTML tag has to have a certain format. For instance, using a '.' dot is not allowed as part of an ID; this is why cyberweb will automatically replace this via a '_' character instead.
Since as of May 2023 you can also determine that all images on a given webpage can be dragged by the user (via the mouse).
First, enable this for the web-object at hand via:
enable_drag_all_images
Past this point whenever you call img(), it will be assumed and treated to be quite similar to dimg(), which stands short for draggable_image().
Sinatra interface
The Cyberweb project is a toolset project, so there is also a class called Cyberweb::Sinatra. This can be used to quickly write a subclass for use as a web-page, based on sinatra.
To use this in your own code, do subclass from it such as via this variant:
require 'cyberweb/requires/require_sinatra.rb'
class Foo < Cyberweb::Sinatra
@root_string will carry the content (aka the index) of the main / route by default. A few other projects make use of class Cyberweb::Sinatra, such as the studium gem or the beautiful_url gem - see files such as studium/lib/studium/www/sinatra_main_entry.rb or beautiful_url/lib/beautiful_url/www/app.rb.
Since as of June 2021 I am changing the old approach in regards to .cgi files. While I will retain support for .cgi files, I am also exploring offering the very same content via sinatra for some of the files - at the least in the roebe project, as a test-project for now. My idea here is that the Cyberweb project can already handle all HTML, CSS or JavaScript-related part that I may need. On Windows, using .cgi is somewhat annoying (but possible - I use lighttpd for this), whereas using sinatra is a lot simpler. So my idea is that I will slowly add and extend support for both .cgi and sinatra, and re-purpose the cyberweb project to achieve this. This currently lacks documentation, but eventually I'll add more documentation in how to solve this.
You can designate that Cyberweb::WebObject is serving a sinatra application right now via the following method invocation:
is_a_sinatra_application
And to query the state:
is_a_sinatra_application?
If you use a file extension such as .sinatra then this is automatically done. In fact that was the reason why I added this functionality in June 2021. The idea in the long run is to be able to do sinatra-specific calls that enable or disable certain things, in particular in regards to images, and have images work properly at the least on my home setup.
draggable_image() and the HTML draggable attribute
HTML added the draggable global attribute. This can be either true or false. A value of true indicates that the element can be dragged.
So, for example, in HTML:
<img src="cat.png" draggable="true">
This should enable drag-support for that image.
The default value is auto, which means that drag behaviour will default to the given browser behaviour. Only text selections, images, and links can be dragged by default. For other elements, the event ondragstart must be set for drag and drop to work.
in_dir_image()
To quickly display an in-dir image, that is an image that resides within the current directory, you can try the following API:
in_dir_image 'foobar.png', 'marl3em bblack1'
Generate system settings
If you want to store the system settings in a file, you may be able to use this:
cyberweb --systemsettings
Normal users of cyberweb won't need this functionality. I only wanted to have this available as a separate instruction, to simplify updating the cyberweb project.
Textarea in HTML
You can make a textarea HTML tag readonly via readonly, as an additional attribute to the textarea-tag.
Specific example for this:
<textarea readonly>
Foobar.
</textarea>
To prevent a textarea from being resized by the user, use a CSS rule such as:
textarea {
resize: none;
}
The example cyberweb/examples/html/readonly_textarea_example.html demonstrates this.
CSS first-line rule
The first-line rule can be used to style the first line in a given HTML tag (the specified selector), such as the p (paragraph).
Example:
p:first-line
{
color:#ff0000;
font-size: 30em;
font-variant:small-caps;
}
The first line would then appear larger and in another colour.
Another example:
.foobar:first-line{
font-size: 40px;
line-height: 50px;
font-weight: bold;
color: #662929;
}
In some ways this is similar to using a h-tag such as h1 or h2.
Several properties can be modified within the :first-line rule, such as font properties, color properties, background properties, word-spacing, letter-spacing, text-decoration, vertical-align, text-transform, line-height or clear.
CSS text-transform properties
The three main variants are:
div.a { text-transform: uppercase; }
div.b { text-transform: lowercase; }
div.c { text-transform: capitalize; }
CSS letter-spacing property
letter-spacing can be used to decrease or increase the distance between texts within a given text.
Example:
<div style="letter-spacing: 5px"><h2>Hello world!</div>
CSS and the border-spacing property for HTML tables
You can style HTML tables via CSS, by making use of border-spacing.
Example:
border-spacing: 20pt
The values for border-spacing can be: length|initial|inherit.
IDs for use in HTML tags
An ID may occur only once on a given webpage.
CSS text-decoration
Via text-decoration you can modify text such as by underlining it or line-through the text.
Examples for this:
h1 {
text-decoration: overline;
}
h2 {
text-decoration: line-through;
}
h3 {
text-decoration: underline;
}
h4 {
text-decoration: underline overline;
}
h5 {
text-decoration: underline overline dotted red;
}
h6 {
text-decoration: underline overline wavy blue;
}
As you can see from the last example, you can combine several values for the same modifier, e. g. both underline and overline.
The allowed values for text-decoration are:
inherit
none
underline
overline
line-through
blink
HTML Frames
HTML frames are rarely used nowadays. Syntax-wise they may be defined like this:
<frameset rows="100,*,60"> <frame ...></frameset>
Two frames:
<frameset cols="200,*">'),'default'
<frame src="contents_of_frame1.html">
<frame src="contents_of_frame2.html">
</frameset>
HTML accesskeys
You can use an accesskey in HTML like so:
<input type="button" value="Button (accesskey is b)" accesskey="b">
<button accesskey="f">Foobar</button>
The attribute accesskey is allowed in the following tags:
input
textarea
label
legend
CSS ::before and CSS ::after
Via :before it is possible to insert elements before another element. Even graphics can be inserted.
Let's look at a simple example:
p::before {
content: "Read this: ";
}
As you can see, the text that should be inserted comes after the content: part.
This can also be used to play audio files:
h1::before {
content: url(beep.wav)
}
Now a slightly more convoluted example:
h2::before {
content: "";
width: 10px;
height: 10px;
border-radius: 50%;
background: hotpink;
displEvolution_of_Metabolic_Pathways-2000.pdfay: inline-block;
vertical-align: middle;
margin-right: 10px;
}
To make use of an image, you can use something like:
img:before {
content:url(https://example.com/image.png);
}
CSS2 used the :before notation, but this was changed to :before in CSS3. I was a bit surprised to see ::before, because I used to use :before only.
The same exists for appending text, called ::after.
Example:
p::after {
content: "»";
color: red;
}
CSS input autofocus
You can modify elements by setting the focus onto them the moment a page loads, via autofocus.
Example for this:
<form action="/action_page.php">
<label for="fname">First name:</label>
<input type="text" id="fname" name="fname" autofocus><br>
<label for="lname">Last name:</label>
<input type="text" id="lname" name="lname"><br><br>
<input type="submit">
</form>
This is a bit similar to ruby-gtk3, e. g. .do_focus or .set_focus(true).
CSS grouping and CSS selectors
CSS selectors, such as the typeselector, can be used to refer to specific HTML tags. This can be used to style these HTML tags via CSS rules.
The following example shows how to use a margin of 10 pixels for each p tag:
p { margin: 10 px; }
This is fairly convenient and elegant. It is also quite flexible in that you can group several selectors together, and apply the same CSS rules to each element listed therein.
You have to use a ',' as separator between the individual elements in order for this to work.
An example for this follows:
h1,h2,h3,h4,h5,h6 { color: green; }
Now all HTML headers (h1 up to h6) will be displayed in a green colour.
This can be extended for particular tags that occur as part of other tags as well.
For example, in order to colourize all h2 headers that occur within the ID called #nav, use the following:
#nav h2 {
color: tomato;
}
In plain HTML this would be used via code like this:
<div id="nav">
<h2>Hello world!</h2>
</div>
This allows you to use conditional rules in CSS. Don't forget to use the correct ID; in this case #nav.
CSS box-shadow effects
How does box-shadow work in CSS?
The general syntax may look like this:
div {
box-shadow: 10px 10px 5px #888888;
}
div('Black','box_shadow_one'){
h3 'Hier die obige Box'
}
See also: http://www.w3schools.com/cssref/css3_pr_box-shadow.asp
The allowed values to box-shadow are:
box-shadow: none|h-shadow v-shadow blur spread color |inset|initial|inherit;
h-shadow refers to a horizontal shadow, whereas v-shadow refers to a vertical shadow.
A box-shadow Generator can be used as shown on the following webpage:
http://www.cssmatic.com/box-shadow
Add a .js file, as-is
The following API can be used to ad-hoc add a .js javascript file:
link_in_javascript 'app.js'
CSS Cursors
To use a different cursor, set a CSS style rule such as:
cursor: pointer;
cursor: auto;
Alternatively use a defined CSS class such as:
.crosshair { cursor: crosshair; }
And then in HTML:
<p class="crosshair">crosshair</p>
Valid cursors include:
auto
crosshair
default
e-resize
grab
help
move
n-resize
ne-resize
nw-resize
pointer
progress
s-resize
se-resize
sw-resize
text
w-resize
wait
not-allowed
no-drop
Using language-specific files as content of a webpage
The typical way how I describe the main content of a web-page is via:
doc {
}
This doc refers to document and is ultimately just a <div> tag. So I put my web-applications into a big <div> tag ultimately.
Since as of late 2020 I am also using language variants such as:
english {
}
# or
german {
}
The latter is used for denoting that this webpage is written in german, and the former is used when the webpage is written in english. This is not a replacement for doc {}, but is the starting point I use for describe a web-object in general.
In June 2021 this was extended in that I added the method called:
doc_skeleton
The word skeleton refers to a separate file, the skeleton of the web-application.
Say that you have five files called index.rb, index.cgi, index.sinatra, index_english.md and index.german.md.
This allows us to read in either the english or the german language, as-is.
To let the cyberweb project guess on its own, consider using a variant via the following Symbol:
doc_skeleton(:english_or_german)
This currently defaults to german. You can pass ?use_english or ?english to the .cgi page to overrule this and force the web-application to view the english content instead. That way the user can change languages, as-is. A bit cumbersome for now, but possible.
In order for this to work, the corresponding .md file must exist, e. g. index_english.md or index_german.md.
Note that this is currently (June 2021) quite experimental, but I wanted to add the feature that we can offer different languages. In the long run I may adapt this approach, to make it easier to use different languages on any given web-application, but for now I only use this in the roebe gem. For example, luft.cfg under roebe/www/luft/ will show this. It may not work on your home system, though, as it is catered to my home setup currently. But it shows how this could be done in theory. So, who knows - in the long run I may integrate this as a 'default' feature.
Note that ?use_german will work as well, to force the _german.md file to be read.
CSS border-style property
CSS gives you the possibility to style borders via different properties, through border-style.
Let's showcase some examples for this:
p.solid { border-style: solid;}
p.dotted { border-style: dotted;}
p.dashed { border-style: dashed;}
p.double { border-style: double;}
p.groove { border-style: groove;}
p.ridge { border-style: ridge;}
p.inset { border-style: inset;}
p.outset { border-style: outset;}
p.none { border-style: none;}
p.hidden { border-style: hidden;}
p.mix { border-style: dotted dashed solid double;}
Personally I like solid the most, followed by dotted, then dashed.
The other properties may be useful in some cases, e. g. when you wish to indicate some button-like element - but visually, I think the first three styles are by far the most appealing ones.
Styling a row of a table and styling a table in general
You can use CSS rules such as this:
tr {
background: wheat;
}
tr.even {
background: none;
}
This can be used to use a different colour for each even row. You still have to use the CSS class called even in this case manually, though. (There may be other solutions but for now this is simply documented here as-is - perhaps in the future this may become more flexible.)
This may look like this:
See also the file at cyberweb/examples/html/table_with_header_example.html.
CSS first-letter
CSS allows us to modify the first-letter in, for example, a HTML paragraph. This is enabled via the so-called :first-letter selector.
In CSS rule this will look like this:
.fl:first-letter { font-size: 120%; }
The ':' is the important identifier.
Some time ago this was modified though. It is now required to use two ':' rather than one.
Example:
p::first-letter {
font-size: 150%;
color: steelblue;
}
Take note that this is limited to block-level elements, so by default the span tag is unable to make use of this, unless it is turned into a block-level element as well.
CSS and Hovering
CSS allows us to make use of :hover in order to have certain effects happen when the mouse cursor hovers over an element.
The general API respectively syntax for CSS hover goes like this:
.NAME_OF_ELEMENT:hover { background: COLOUR_HERE; }
.NAME_OF_ELEMENT:hover { background: COLOUR_HERE; }
.test:hover { background: green; }
.button:hover {opacity: 1;}
To then test this via cyberweb:
p('hover_test2 mart1px','') {
ee sg(:pfeil_rechts,'marl1em marr6px')+
'Hier drüberfahren'
}
To make all HTML links, aka the a tag, change the colour when the mouse hovers over them, the following CSS rule should work just fine:
a:hover {
background-color: yellow;
}
You can style several tags in one go, via:
p:hover, h1:hover, a:hover {
background-color: lightblue;
}
This also works inline.
The CSS !important rule
Let's start with a syntax example.
Consider the following CSS rule for the body tag:
body {
background: steelblue !important;
}
This will set the background colour of the whole body of the page to the colour steelblue.
It is important to use that very syntax, e. g. to close the CSS rule at hand via !important;. Otherwise it may not work properly.
Once such an !important rule applies then it takes precedence over every other rule, including the style attribute. Later set !important rules can override earlier set !important rules, though.
Use this with caution, though, as it really overrides any other settings, including user-defined settings.
Including external .css files
The syntax for adding external (standalone) .css files is as shown in the following examples:
<link rel="stylesheet" type="text/css" href="name_of_the_css_file_goes_in_here.css">
<link rel="stylesheet" type="text/css" href="base.css">
Embeddable Interfaces
Since as of June 2021 I am experimenting with embeddable interfaces in regards to web-related components - most importantly sinatra.
The basic idea here is that we can easily make available additional routes for other applications. Let's explain this by using an example.
The PdfParadise project defines a route such as /view. This entry will become /pdf/view if I want to use it within the Roebe::Controller - my master-class for controlling all the various web-APIs that I use locally.
To enable this functionality, I decided to settle for a module name called EmbeddableInterface. I am trying to use this consistently for my own projects. Different details may change, but ultimately this should be used when I want to extend functionality of the core controller.
This module then typically looks like this:
module EmbeddableInterface # === Wetter::EmbeddableInterface
begin
require 'html_tags'
include HtmlTags::BaseModule
rescue LoadError; end
begin
require 'cyberweb/sinatra/custom_extensions.rb'
include Cyberweb::Sinatra::CustomExtensions
rescue LoadError; end
# Some methods defined next
end
def self.
object = Object.new
object.extend(Wetter::EmbeddableInterface)
return object
end
That's the skeleton for it right now, roughly.
In the future this may be simplified, but for now this is the way it is.
You can use the following toplevel method for merging new routes into an application; again, for the time being, this is a bit hackish. It may take a while before this becomes officially endorsed.
The API is:
Cyberweb::Sinatra::CustomExtensions.merge_interface
Arguments should be:
Cyberweb::Sinatra::CustomExtensions.merge_interface(
i, # Should be an Array of routes that are to be used.
prepend_this_to_the_route = '/',
namespace_to_use # For example, PdfParadise or Repackage.
)
Some methods are assumed to exist within module EmbeddableInterface. This may be subject to change in the future, but for now simply look at the repackage gem to find out how this is done. Documentation is missing in this regard, but will be added over the next weeks slowly.
Including CSS into a webpage
If you want to include CSS into a webpage, use the following HTML tag:
<style type="text/css"></style>
Including external .js files into a HTML (web)page
The syntax for adding standalone .js files goes like this:
<script type="text/javascript" src="path/to/javascript/file.js"></script>
# or simpler:
<script src="path/to/javascript/file.js"></script>
CSS comments
If you want to use comments in a CSS file, use something like this:
/* This is a CSS comment. */
CSS font-face property (in CSS3)
Via the @font-face property it is possible to make use of different (custom) fonts. This font can be loaded from a remote server, or it can be provided on the local system, thus a locally installed font on the user's computer.
An URL should be given as argument.
The syntax rules for this goes as follows:
(1) first give the name of the font
(2) provide the path to the font
If you then wish to make use of that font you can declare this in CSS.
An example for this follows:
@font-face {
font-family: myFirstFont;
src: url("sansation_light.woff"); # Here you can provide the URL
}
Another example:
@font-face {
font-family: "Open Sans";
src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2"),
url("/fonts/OpenSans-Regular-webfont.woff") format("woff");
}
Lazy loading of images
You can use loading=lazy to defer the loading of that image until the user scrolls to the image.
Example in HTML:
<img src='foobar.jpg' loading='lazy' alt='Alternative Text'>
CSS zoom-on-hover effect
This can be done like this:
.images {
display: flex;
width: 100vw;
juftify-content: center;
align-items: center;
}
img {
width: 400px;
}
img:hover {
transform: scale(1.3);
}
/* And another example:
img:hover {
transform: scale(2.5);
}
The important part is the transform: scale specification. You can here specify how large or small the image should become. For instance, to shrink an image, you could use the CSS rule transform: scale(0.5);. This will shrink the image to half its original size.
I typically put these rules into a special CSS class, such as:
.enlarge_this_image_on_hover:hover {
transform: scale(1.1); /* Just a modest increase. */
}
And then, for instance, for a generate image tag:
img(:document, 'enlarge_this_image_on_hover')
# or this example for a draggable image:
dimg 'BOX.png', 'VAM enlarge_this_image_on_hover'
The small drawback (or advantage, depending on your point of view) is that the CSS rule has to be specified as-is.
In theory we could also autogenerate the CSS rule and use an API such as img(:document) enlarge_this_image_on_hover: '25%' } instead, but for now I'll leave it with the above CSS-based approach. It's quite simple really.
Valid values for CSS font-size:
xx-small
x-small
small
smaller
medium
large
x-large
xx-large
larger
Cyberweb::Header
Examples:
Cyberweb::Header.size = 'h3' # Set to a smaller header.
Cyberweb::Header.reset
Not sure if this is still necessary in 2021; at a later time it will be decided whether to keep this or not. If it is kept then this subsection will be expanded.
Working with HTML form elements
Within a HTML form tag, the following tags are valid or have a special meaning:
input
select
textarea
CSS ::before rule
You can add content via CSS like this:
.some_class::before {
content: "Only today offer ";
font-size: larger;
color: red;
}
<p class="some_class">Wood only € 4.95</p>
I don't think this is too overly useful when you can dynamically generate the web-app as-is, though.
How to work with form-elements
This subsection was added because I tend to forget how to work with <form> elements in HTML.
HTML allows us to make use of <form> elements.
Any such <form> element is typically associated with an action, which is determined via action="".
This may look like this:
<form action="/foobar.php">
</form>
The attribute action determines the recipient, that is, the one who will receive the transmitted data from the <form> element. In the example above, the file called foobar.php.
The attribute method determines how the data will be transmitted. If omitted then the default is get.
You can also send this to an email, such as via this:
<form action="mailto:foo@bar.org" method="post" enctype="text/plain">
Within any such given element, we can use <input>, as in:
<input type="text" id="first_name" name="first_name">
To use a web-form via cyberweb, try:
form('SELF', :post, 'mars2em') {
}
simple_table2
Since as of 24 Aug 2011 we can also use the method simple_table2() which is stored in the file html_tables.rb.
Example for this:
simple_table2(ARRAY_ALL_LINKS)
This will simple make a 2 data-cell table, and accepts an Array as its input. Very easy way to make tables!
Sitemaps
A sitemap is a navigational tool, displaying to the user which links may exist on a given webpage.
If you want to use a sitemap via the Cyberweb project, do something like this here:
sitemap :h4, 'Schnelles Abnehmen'
autogenerated_sitemap
If you also want to autogenerate a sitemap, as-is, then you can use the following method:
header_for_sitemap 'This is some generic header.'
You can also use an Array for a special method:
sitemap_array('Hratie','Tulis','Kuulk')
This will be treated as an Array of headers to be used for the sitemap that will be generated.
Generating standalone webpages (.html files)
This subsection deals with the cyberweb project generating standalone .html files.
First, the general method to create a HTML dump is via:
.to_html
This is only possible on a WebObject instance. This alone will just return the HTML representation.
To store it into a local file use this method:
.create_standalone_html_page
This presently (August 2021) uses hardcoded file paths. In the future more flexibility will be added to the method, but for the time being it was only added to quickly do some ad-hoc testing.
Spinbuttons in HTML
Use something like:
<input type="number" value="1" min="1" max="999">
You may even style them via CSS like:
input[type=number]::-webkit-inner-spin-button {
opacity: 0.3
}
HTML-links
Since as of 19.02.2020 (19th February 2020), the cyberweb project now uses the HtmlTags project for generating a href hyperlinks (HTML hyperlinks).
While this led to some broken links on my home system, the code as well as the usage pattern for links is now more consistent, and simpler to use in the long run - I hope. Before that I used tons of different HTML-generating methods, all of which used different signatures. This was too confusing to maintain in the long run.
The typical API for use of such a HTML link may look like this:
a 'https://www.manualslib.de/manual/123/Gerät_xyz.html',
content: 'Handbuch zum Gerät xyz',
css_class: 'mars2em'
So essentially, you can describe the HyperLink as a Hash, where content is the content (the text you wish to display), css_class is the CSS class to use for that link, and so on and so forth.
For the actual CSS code, I recommend to group the a-related tags together, such as via:
a:link, a:visited, a:active { color: #3366FF; text-decoration: none; }
The hover-action should be styled separately:
a:hover { color: #006699; text-decoration: underline; }
To globally style all HTML hyperlinks, you can use CSS style such as the following:
<style>
a {
color: steelblue;
}
</style>
Remember that you can also use a title for a href tag. Example:
<a href="http://foobar.de/" class="slateblue" title="Some Superlong Title here">
The br-tag
The br-tag can be used in HTML to add a linebreak.
You can style the height of the line break via CSS such as:
br {
line-height: 30%;
}
I needed this on a webpage to control the distance between individual HREF-links, and I did not want to use div-tags or p-tags as such. So using the line-height property was very useful.
Remote images versus local images
I use various www-related projects, including local webpages.
Some of these pages lateron became available for everyone, such as in the roebe gem, via the www/ subdirectory.
However had, images are normally not distributed for these webpages - it would inflate the gem size way too much.
This in turn means that a visitor does not see any image, when some of these images are important or helpful. This is not an ideal situation.
So, in September 2021 I decided to add a new API, called:
drag_local_image_or_remote_image()
drag_local_image_or_remote_image('foo/bar.png')
drag_local_image_or_remote_image('foo/bar.png','www.some_page.com/yo/foo/bar.png')
The idea here is to default to my local image, but to provide a second argument as well, containing a remote URL to an image that can be used as a substitute, in the event that there is no local image available (such as when other users look at a webpage distributed in the roebe gem).
I tested this in September 2021 and it works, so in the future I expect a few more images to be made available. But this is quite experimental as of now, and probably still not too hugely useful for other users. In the event you may have a need case to document such a web-page via images, you can modify these API calls and supply your own images.
If you do not need drag-and-drop support then simply use:
local_image_or_remote_image()
If drag_local_image_or_remote_image() is too long to type, use the alias called dimg2.
To quickly embed a remote image, you can use the following API:
'https://foobar.com/cat.jpg'
'https://foobar.com/cat.jpg','mar1em mars2em' # This here passes CSS classes to the image at hand.
Cyberweb.convert_back_german_umlauts
This method can be used to 'convert back' german umlauts, when the encoding failed somewhere, such as converting '%d6' into 'Ö'. It is mostly an ad-hoc method that most users of the project will not need, but sometimes there may be a use case to make use of that method, such as when one uses open-uri to download a remote website into a local file, if said remote website contains german umlauts.
In fact this was precisely the reason why that method was added.
autogenerated_system_settings.yml
The file cyberweb/yaml/autogenerated_system_settings.yml is created via the external file roebe/classes/generate_system_values.rb.
This file will contain entries such as:
SYSLIB_DIR: "/usr/lib/"
This was needed because in some environments these directories are not defined, yet there are examples where the cyberweb project may need to know these paths. Thus, the hardcoded values are stored in that .yml file. You will probably never need the .rb file or the .yml file, but it is here documented to explain why it exists.
Column width in CSS
You can specify a column width via column-width: 250px;.
The following screenshot shows this:
The meter tag in HTML
HTML allows us to use a meter tag.
Example in HTML:
<label for="value1">Low</label>
<meter id="value1" min="0" max="100" low="30" high="75" optimum="80" value="25"></meter>
This would eventually yield a page that may look like this:
This is documented here in the event that we may need this one day.
Unicode and Encoding
This subsection is currently a stub - in the future it may be expanded to contain more useful information.
On the world wide web you can sometimes see greek symbols displayed on a homepage. This often makes use of the "math> tag.
Preliminary support for this was added to the cyberweb project in October 2021. This is incomplete right now but hopefully will become more inclusive in the future.
Following next is just one example to add (display) the greek symbol omega on the webpage at hand:
add_omega_symbol_semantics
Sanitizing .html files
Sometimes a .html file is "compressed", aka newlines are removed. Everything is then on a single line.
Some editors struggle with this; and it is quite ugly.
Thus, an ad-hoc method was added to Cyberweb.
Its API is:
Cyberweb.sanitize_this_string_by_adding_a_newline_after_every_closing_HTML_tag
Cyberweb.sanitize_this_string_by_adding_a_newline_after_every_closing_HTML_tag('/Depot/j/foobar.html')
Pass a local .html file to the method; alternatively a String should do well. Every closing > html tag found will be turned into ">\n" instead. Thus, you get a nicely split .html page. (Ideally we should use a more sophisticated regex, but I really added this just as a throw-away action, to sanitize a mangled .html page.)
This can also be called de-minify-script.
Placeholder text
Placeholder text can be assigned to a textarea HTML tag. Let's first show the raw HTML code for this, mixed in with a bit of CSS:
Describe the physical attributes of your character next:<br><br>
<textarea rows="4" cols="50" style="margin: 1em" placeholder="Describe your character here ..."></textarea>
This would yield the following result in the browser:
You can use the input tag to designate a placeholder text to use.
Only two HTML attributes can receive the placeholder attribute. These are:
<input>
<textarea>
An example for this follows for the input tag:
<input type="tel" id="phone" name="phone" placeholder="123-45-678" pattern="[0-9]{3}-[0-9]{2}-[0-9]{3}"><br><br>
And for the textarea tag as well:
<textarea placeholder="Describe your complaint here ..."></textarea>
See also the distributed example file at *cyberweb/examples/input_placeholder_example.html.
It is possible to style the placerholder-text via CSS.
For instance, if you would like to use the color *steelblue then use the following CSS rule:
::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
color: red;
opacity: 1; /* Firefox */
}
CSS rules in general
This subsection contains a few explanations to CSS rules in general.
Inheritance: after a property has been applied to a particular element, its children retain those property values as well. That way you can consistently style these elements via the same CSS rules.
Normally when a CSS value is changed, the change is instant. This can be avoided by the transition property, which allows us to animate from the old state to a new state.
Working with base64-encoded data (image)
Have a look at the following file:
cyberweb/test/testing_the_web_object/testing_base64_image.cgi
The idea is that we can eventually embed all images as base64 encoded variants. This is especially useful for sinatra and rack-based applications. Right now this is fairly experimental; in the future it will become easier to use.
Remote images at imgur
I have some local .cgi files that request images stored in a path that is not accessible by the local webserver. Sometimes I can put it into WebImages and use it, such as via Base64 encoding - but sometimes I just want to be able to link to it via an img tag. So in these cases I am fine linking in to remote images.
As I may forget which image is available, here comes a listing - this may be extended over time:
Downloading a remote webpage
You can use Cyberweb.download_webpage() to download a remote webpage.
This isn't hugely sophisticated - it just performs URI.open().read and then dumps that string into a local file. The file bin/download_webpage is representing that functionality from the commandline.
Usage example from within Ruby code:
Cyberweb.download_webpage('https://en.wikipedia.org/wiki/Tom_and_Jerry')
Tooltip example via CSS
A tooltip is often used to specify extra information about something when the user moves the mouse pointer over an element.
Have a look at the file at cyberweb/examples/css/css_tooltip.html.
This shows a simple CSS tooltip. Adjust the style, colours, width according to your own preferences.
hr_stars
You can use the method call hr_stars to display three stars aligned one to another.
This may look as the following image shows:
Cyberweb::RouteHandlerModule
This module shall eventually replace sinatra for my own needs. I will not port all of sinatra's functionality, but I want to be able to use the core functionality for my own custom web-related needs.
To use puma, use:
Cyberweb.puma
And for webrick, use:
Cyberweb.webrick
These methods were added mostly for convenience. If you are curious have a look at the code to find out which is the 'real' method.
Rebuilding Sinatra
Sinatra is a small webframework, built on top of Rack. It provides a useful DSL for specifying what the given application should respond to, and what it will send back.
The DSL can be as simple as shown in the following example:
get "/hello" do
[200, {}, "Hello from Sinatra!"]
end
post "/hello" do
[200, {}, "Hello from a post-Sinatra world!"]
end
The get() method must take a path (which is the first argument) and an associated handler block - which is the part within the do/end clause.
A very simple definition may be the following variant:
def get(path, &handler)
route("GET", path, &handler)
end
def route(verb, path, &handler)
@routes[verb] ||= {}
@routes[verb][path] = handler
end
So, in other words: we will append new verb-entries to the main hash called @routes.
This can then be used like this:
route_handler.get "/hello" do
[200, {}, ["Hello world!"]]
end
puts route_handler.routes
The next method that has to be defined, if we want to support Rack, is .call(), such as:
def call(env)
end
Hover.css
Since as of November 2021 the cyberweb project makes use of Hover.css (licence: MIT):
http://ianlunn.github.io/Hover/
The .css is distributed as-is. Note that some names were changed, though, to make it more 'logical'.
Web-safe fonts
The following list is assumed to contain web-safe fonts, for use in HTML pages (via CSS):
Arial (sans-serif)
Verdana (sans-serif)
Helvetica (sans-serif)
Tahoma (sans-serif)
Trebuchet MS (sans-serif)
Times New Roman (serif)
Georgia (serif)
Garamond (serif)
Courier New (monospace)
Brush Script MT (cursive)
Note that the names of CSS fonts in general are case insensitive. Thus you can lowercase them too, if you would like to.
You can also use generic fonts. Five are available by default, being: serif, sans-serif, cursive, fantasy and monospace. Serif resembles Times New Roman, sans-serif resembles Arial.
Most text on the Web is displayed with a sans-serif font family.
Balloon.css
You can download the balloon.css file via class DownloadBalloonCss (Cyberweb::DownloadBalloonCss).
This file resides at the location web_object/utility_scripts/download_balloon_css.rb.
It presently (May 2018) does not do much other than download that remote .css file.
I needed a small "pop-up" for displaying additional information to some entries in a table, which is how I found Balloon.css.
Grayscale filtering on an image
CSS allows us to "remove" colours in an image. I call this the grayscale filter.
Cyberweb comes with a default CSS class that may be of help here - simply attach the CSS class grayscale to the image at hand if you want it to "lose" colours (for display purposes only; of course nothing is lost in the image as such, only the display of said image is modified via CSS).
Converting from a .html page to a cyberweb-object
The file bin/html_to_cyberweb_converter can be used to convert some .html files into cyberweb-objects. This class has been created in February 2022, but it does not yet work very well. In the future this may change.
The idea is that we can grab any .html page, re-build its logic into cyberweb, and allow you to modify this in any way, shape or form. The long-term goal is to adjust any .html page to any different format, in any way, shape or form. It would allow users a higher level of abstraction to deal with a HTML page. For instance, you can re-style the CSS classes in use as-is.
(Note that presently, as of 2022, class WebObject is actually not used; HtmlTemplate is used instead. The reason is because WebObject is too big and not flexible enough right now. In the future this may be resolved and unified, but for now, class HtmlTemplate will generate the new .html file.)
autoextend
If you make use of Cyberweb::WebObject then you may be able to describe a webpage as an "object". Various methods will be made available at that point.
The API may include a sort of DSL like this:
english('Title goes here') {
}
This kind of means that the webpage at hand will be using english as its primary language. And the first argument will become the title of that webpage. (Note that presently only english() and german() are available. It's not making any real difference, but perhaps I should add alias-names for other languages as well. Not so many users of this project aside from english as the primary language in use, though.)
Various other methods part of WebObject exist that help here, one of which is autoextend. This method is also aliased onto enable_namespace.
That method will include various other modules. One module that was somewhat recently (March 2022) added was Cyberweb::Objectified::Mask. This module will pull in HTML-tag support. So, for instance, oop_h1() can then be used as a method, which will refer to using h1 as the HTML tag. These objectified (OOP) HTML tags are described in more detail in other subsections of this document (README.md).
Including the namespace for Cyberweb::Objectified::Mask is done mostly for convenience, so that the user does not have to manually include this module.
JQuery
The Cyberweb framework/toolset favours the use of jquery. Presently, since May 2021, the version that is to be used by default will be for jquery 3.6.0. This may change at a later time.
In the event that it is changed and the documentation here is not updated, you can always rely on the following method call to yield the correct version of jquery to be used:
Cyberweb.jquery_version?
For example, the above method called would yield 3.6.0 in May 2021. Personally I always use the latest stable version of jquery when possible.
You can also query the jquery-ui version in use, via:
Cyberweb.jquery_ui_version?
Again, this also has to be synced manually, via the .yml file called project_configuration.yml.
Since as of May 2021, the cyberweb will also bundle this corresponding version of jquery and jquery-ui into the javascript_code/jquery/ subdirectory of the gem. This is solely done to simplify the use of jquery so that, for example, dragging an object becomes simpler and available by default, even if access to the www is unavailable at the current time.
You can also call this method on a Cyberweb::WebObject instance via the following method:
report_the_jquery_version_in_use
Both jquery-ui and jquery use the same licence as the Cyberweb project (MIT licence). See also this wikipedia entry if you want to read more about jquery and its history:
https://en.wikipedia.org/wiki/JQuery
To make a container resizable via the mouse, by using jquery, try this method:
jquery_resizable_via_the_mouse(id: :resizable_via_the_mouse)
As id you simply pass in the id of the HTML element at hand. In this case, the symbol called :resizable_via_the_mouse.
See also the file JQUERY.md for a more thorough reference.
Note that in May 2021, support for jquery is actually mildly deprecated. This is not set in stone and it does not mean that jquery support will be removed, as far as the cyberweb project is concerned; it is more that I want to see whether we have better or simpler alternatives, without being tied into jquery too closely.
The basic syntax for jquery, in javascript, goes like this:
$(selector).action()
The general rules for JQuery go along these lines, in JavaScript:
$(this).hide() # hides the current element.
$("p").hide() # hides all <p> elements.
$(".test").hide() # hides all elements with class="test".
$("#test").hide() # hides the element with id="test".
Some of this is a bit cumbersome to type and use, so the Cyberweb project simplifies some of it.
For instance, rather than type out the document_ready functionality via $(document).ready(function(){} you can simplify this via the following method:
document_ready() # No arguments in this case, which is rather pointless.
document_ready('$("h1").css("color", "lightgreen");') # ← Real usage example here.
This may not appear to be of a huge help, but it gets rid of a bit of boilerplate code, which I think is useful in its own right. Future changes may even simplify this further, but for now let's keep it simple.
Jquery mini-tutorial
This subsection will contain some useful snippets pertaining to jquery. It will be a mini-tutorial, NOT a complete tutorial.
To select all
elements via jquery, use:
$("p")
$("*") # will select all elements
To select all specific CSS classes, use:
$(".info") # to select the class called .info
$(".info,.features") # to select all elements with the class info or features
To select the ID, do:
$("#id_goes_in_here")
You can also select based on href-attributes, via:
$("[href]")
Via $(document).ready() jQuery defers the function calls until the DOM is loaded.
To add a CSS class to every p-element, you could use this jquery-code:
$(document).ready(function() {
$('p').addClass('highlight'); })
Here, the name of the CSS class would be highlight.
The CSS class called select_everything
This document already mentioned how to use JavaScript to select everything.
Interestingly it is possible to achieve the same nowadays, without JavaScript - by making use of CSS*.
Cyberweb integrates this via the CSS class called .select_everything.
Simply add it to any tag and when the user clicks on it via his or her mouse, then all content is selected. On Linux this will also assign to the xorg-buffer, so you can use a one-left mouse-button click, and then use the middle-mouse button to paste it onto the commandline. Very convenient! \o/
CSS tables versus original HTML tables versus flexbox and grid layouts
There are various possibilities to lay out HTML containers on a webpage. The simplest one is the old HTML table. This one worked really well.
Lateron we had support via simple div-tags, as well as the float element. Then came grid layouts and flexbox.
Which variant to use?
Well - I have consistently had problems with both grid layouts as well as flexbox. HTML tables, on the other hand, work really well, and so do CSS tables. I have no idea why, but for me CSS tables seem to be the best variant. Flexbox and grid lead to increased complexity, and always created issues for me, so I mildly deprecated using it instead; perhaps one day they will become simpler, but for now I will stick to CSS tables.
How to use a CSS table? Make use of display: table; as well as display: table-row. That way you can kind of simulate tables.
The following CSS rules show this:
.grid {
display: table;
border-spacing: 5px
}
.row {
display: table-row
}
.cell {
width: 50px;
height: 50px;
background: grey;
display: table-cell;
}
.row div:last-child {
background: red
}
If you need to set a maximum width then the following may work:
<table style="width: 90%; table-layout: fixed">
Working with local files in HTML - input type="file"
You can use:
<input type="file">
To give the user a way to handle local files conveniently.
You can limit the file types handled by this input tag via:
accept="image/png, image/jpeg"
<input type="file" accept="image/png, image/jpeg">
CSS, text-shadow support and drop-shadow support
The CSS text-shadow can be used to simulate an engraved text.
If you want to have shadows added to a given text then the text-shadow CSS property may be useful. Be careful when using this, though, because it can make the text harder to read - so perhaps use it only for some headers or larger text rather than for all text content.
At any rate, let us next look at a simple example for the h1 HTML tag, how it can be styled via the text-shadow CSS rule:
h1 {
text-shadow: 2px 2px #FF0000;
}
The syntax used here (and in general) is as follows:
text-shadow: h-shadow, v-shadow, blur-radius, color
text-shadow: 1px 1px 2px black;
text-shadow: 2px 5px tomato; /* Note that you can also omit values, as seen here on this line. */
Another example, for a CSS rule:
.red_text_shadow {
text-shadow: red 0 -2px;
}
Strangely enough you can also re-arrange the arguments a litte bit:
/* colour | offset-x | offset-y | blur-radius */
text-shadow: #fc0 1px 0 10px;
/* offset-x | offset-y | blur-radius | colour */
text-shadow: 1px 1px 2px black; # This is my preferred style.
I do not know why they went that route, but I recommend to just stick to one style, and avoid the other. Seems easier to remember when one can be consistent about the arguments.
Note that text-shadow is not the only way you can use to modify text. drop-shadow is another CSS property that can be used in this regard.
In CSS the rule for drop-shadow would be as follows:
drop-shadow(2px 4px 8px #585858);
More specifically what these four values mean:
drop-shadow(offset-x offset-y blur-radius color)
If you make use of the cyberweb project then you can use the following API, to generate a drop shadow:
generate_drop_shadow :red, :default, 'drop_shadow_red'
div('drop_shadow_red') {
h3 'This part should show a drop-shadow effect - but in red'
}
This would yield the following text (shown as image, for convenience):
Let's look at another example:
generate_drop_shadow :darkblue,
'4px 2px 4px',
'drop_shadow_lightblue'
div('drop_shadow_darkblue pad0px mar0px') {
h2 dot(105, 'marr12px')+
'Fancy Text',
'ud mart5px'
}
This would yield the following text (shown as image):
And let's show another example:
generate_drop_shadow :deepskyblue,
'6px 4px 8px',
'drop_shadow_deepskyblue'
div('drop_shadow_deepskyblue pad0px mar0px') {
h2 dot(105, 'marr12px')+
'Cats are adorable creatures.',
'mart5px'
}
This time no image, but you get the idea - if you want a fancy border, cyberweb may help automatically generate these.
You can also use the internal CSS class called shadow_div_without_restrictions.
Give it a try on a div-element, such as via:
div('shadow_div_without_restrictions') {
h2 'Hello world!'
}
See also the file at cyberweb/examples/css/shadow_example_in_CSS/shadow_example_in_CSS.cgi.
A similar effect is shown by the following image:
The important thing to look at is the border-area around the central div-container. You can see that it is surrounded via a border; that is what the CSS class shadow_div1 is achieving.
Since as of November 2021 you can also use objectified-html-tags. The drawback is that it is currently a bit verbose.
Example:
_ = Cyberweb.oop_h1('Batterien', 'martb1px')
css_manager = Cyberweb::CssManager.new
css_manager.css_rule_for_drop_shadow(:lightgreen) # Generate the CSS rule here.
_.css_class 'martb1px drop_shadow_lightgreen' # Use the CSS rule - note the last part.
_.css_manager 'css_rule_for_drop_shadow(:lightgreen)'
_.add_to_pre_content css_manager.result_as_CSS_style?
Or simpler:
_ = Cyberweb.oop_h1('Batterien', 'martb1px')
_.css_class 'martb1px drop_shadow_lightgreen'
_.css_manager 'css_rule_for_drop_shadow(:lightgreen)'
_.add_to_pre_content(
Cyberweb.css_manager { css_rule_for_drop_shadow(:lightgreen) }.css_style?
)
Unfortunately the second example (aka the one right above ^^^) does not work yet. I am not entirely certain how to enable this - ruby's meta-patterns begin to confuse me.
Since my brain is too feeble, I actually wrote a class instead that will autogenerate some CSS rules that can be used.
These CSS rules are stored in the file called drop_shadow.css and work without needing any meta-pattern or autogenerator.
To use these in your own scripts, do something like this:
p('drop_shadow_chartreuse') { ee 'Hello world!' }
p('drop_shadow_chocolate') { ee 'Hello world!' }
p('drop_shadow_coral') { ee 'Hello world!' }
p('drop_shadow_cornflowerblue') { ee 'Hello world!' }
p('drop_shadow_cornsilk') { ee 'Hello world!' }
p('drop_shadow_cyan') { ee 'Hello world!' }
p('drop_shadow_darkblue') { ee 'Hello world!' }
p('drop_shadow_darkcyan') { ee 'Hello world!' }
p('drop_shadow_darkgoldenrod') { ee 'Hello world!' }
This is currently hardcoded to 5px. At some point this default may change, but for now I think 5px is a good compromise.
The actual CSS rule will look like this:
.drop_shadow_cornflowerblue { filter: drop-shadow(5px 5px 5px cornflowerblue); }
This is possible for all registered HTML colours.
Have a look at the file cyberweb/examples/advanced/advanced/drop_shadow_examples.cgi to see how this may look like.
The following image shows this (partially):
HTML IDs
Each HTML tag may have an id entry. The id entry, in HTML, is typically defined like this:
id="some_value" # A generic example.
<div id="some_div"><h2>Hello world!</h2></div> # A better example.
Which values are permissive here?
For HTML4 ID tokens must begin with a letter (which is [A-Za-z]) and may be followed by any number of letters, digits ([0-9]), hyphens ("-"), underscores ("_"), colons (":"), and periods (".").
In August 2022 I confirmed this, via the following ID:
date_01.09.2022
So you can even use '.' characters. I note this down here as I tend to forget things - so this documentation here is a reference for me as well as for others.
As far as the cyberweb project is concerned, all HTML ids are registered into an array (if you use Cyberweb::WebObject). To then show whether you have duplicated IDs in a page, do use the following method:
show_duplicated_ids()
Or in a more general way, use the #debug method, like so:
w.debug
This will report whether you have a duplicated ID or not.
When the page is served, we will also display a little error message in case we have found duplicated IDs. This way we can notify the developer that there is some mistake in his page and we can correct this mistake then.
Have a look at the corresponding source code to see how this is actually implemented.
.show_this_local_directory()
The method .show_this_local_directory() can be used to show content of a local directory. It is available for class Cyberweb::WebObject.
I plan to extend this in the coming weeks and months. The key idea is that we can use this in .cgi scripts and sinatra to show the content of different directories.
The tag
You can highlight text in HTML via:
<p>Foo<mark>bar</mark></p>
Showing the line numbers of the displayed content
You can show the line numbers via a trailing ?show_lines.
This is experimental as of May 2023 - it does not work extremely well. Nonetheless, the option is available.
Lazy loading of HTML elements, such as the img tag
You can use:
loading=lazy
To load images at a later time - that is when the user scrolls to such an image, hence the term "lazy loading" for this functionality.
Let's have a look how this looks in raw HTML:
<img src="foobar.jpg" loading="lazy" alt="Alternative Text">
So all you have to do is add the part loading="lazy" to the image tag (img) at hand.
The Cyberweb project supports this in both the traditional way, as well as the OOP variant offered by cyberweb.
The examples for this are:
img 'foobar.jpg', loading: lazy
img('foobar.jpg') { :lazy }
If you want to use it via the OOP variant:
_ = oop_image('foobar.jpg')
_.lazy_loading # or _.lazy
puts _ # => <img src="foobar.jpg" loading="lazy">
As you can see, the OOP variant of cyberweb allows us to assemble the desired HTML tag as-is. It may seem quite verbose, but remember that you also get a lot of flexibility that way.
The method images_css() in class Cyberweb::WebObject
Sometimes you may have several images and may want to apply the same CSS rules to all of them.
For instance, I use the CSS class bblack1 which is equivalent to:
border: 1px solid black;
So, if I want to apply the bblack1 CSS rule to all images in a WebObject, I do this:
images_css 'bblack1'
Past that point all images on that particular web-object will have a 1px black border.
See the example file at cyberweb/examples/advanced/images/global_css_rules_for_the_images.cgi for a demo in this regard. (Not all images work; some of them are only available on my home system, but the other images should work.)
Do note that since as of November 2022, when images_css is used then it will always be appended to every image tag. So only use it if you really need this functionality.
links.md
If a file called links.md exists in the current working directory then a .cgi or sinatra application powered by cyberweb will read in the content of this file. Then it will display each entry in that file as a HTML hyperlink. I needed this functionality so that I can dynamically modify links displayed on a webpage, for another user of the cyberweb gem. So this functionality may not be hugely important for most users, but in case you need it, it is available.
module Cyberweb::JqueryModule
module Cyberweb::JqueryModule is used to enable or disable support for jquery. Not all classes in the cyberweb gem make use of this module right now - notably class Cyberweb::WebObject does not use this module as of yet. This is planned at some later time in the future, as some code has to be re-written, in order to make use of this new module.
The only class that uses module Cyberweb::JqueryModule right now is class Cyberweb::HtmlTemplate.
CSS Borders
CSS supports different borders.
You can control various different aspects here, such as the width of the border, or the style of the border.
The available border-style properties are as follows:
dotted - Defines a dotted border.
dashed - Defines a dashed border.
solid - Defines a solid border.
double - Defines a double border.
groove - Defines a 3D grooved border. This effect depends on the border-color value.
ridge - Defines a 3D ridged border. This effect depends on the border-color value.
inset - Defines a 3D inset border. This effect depends on the border-color value.
outset - Defines a 3D outset border. This effect depends on the border-color value.
none - Defines no border.
hidden - Defines a hidden border.
The following paragraph shows how you can use this:
p.dotted {border-style: dotted;}
p.dashed {border-style: dashed;}
p.solid {border-style: solid; }
p.double {border-style: double;}
p.groove {border-style: groove;}
p.ridge {border-style: ridge; }
p.inset {border-style: inset; }
p.outset {border-style: outset;}
p.none {border-style: none; }
p.hidden {border-style: hidden;}
p.mix {border-style: dotted dashed solid double;}
Interestingly enough, if you do not specify a color for the border via border-color then this will default to black.
The toplevel methods english() and german()
A couple of years ago these two toplevel methods were added. You may find some of my gems make use of these, when there is content that ought to be displayed on a website.
What do these two methods do, essentially?
They are mostly just a mnemonic reminder that the website that is shown to the user (visitor) is written in that particular language primarily. So, for most webpages, I prefer to use:
english() {
}
Whereas for my local knowledge base I often tend to use german.
Sometimes I mix both languages in the same webpage, but I wanted to be able to selectively switch between languages too, as well as be able to indicate when content is in german rather than english. Thus, to satisfy these use cases, german() and english() are available.
An additional use case for these methods is that I can designate a specific title quickly - either manually, or by using something like:
german(:autotitle)
The symbol :autotitle here would mean that the cyberweb gem should try to infer the name of the page at hand based on its filename.
SVG
If you wish to make use of SVG it is recommended to install the svg_paradise project. Then, you can use it through Cyberweb such as in the following case:
ee Cyberweb.circle
This will output a SVG circle. Do note that this can be customized; simply have a look for the SVG Paradise project for more documentation pertaining to this part.
Drawing a coloured circle via CSS
You can draw a circle via CSS.
Let's first show the pure CSS rules for this functionality:
div.circle {
width: 300px;
height: 300px;
background: #2762e9;
border-radius: 50%;
}
Next you can use HTML to actually "draw" the circle, as-is:
That's it.
I found this to be simple and potentially useful, so I added an API to the cyberweb project to support this.
The toplevel API goes like this:
Cyberweb.draw_circle()
Cyberweb.draw_circle(width: 200)
Cyberweb.draw_circle(width: 200, height: 500)
Cyberweb.draw_circle(width: 200, height: 500, background_color: :steelblue)
Cyberweb.draw_circle(width: 200, height: 500, background_color: :steelblue, border_radius: '30%')
Pass a Hash into the method. Note that this will return the CSS rule as-is, as well as return the div-tag String. Cyberweb::BaseModule will directly embed this if you use the method draw_circle().
Here is a partial screenshot showing three such examples; only the second example has a border-radius of 50%. See also the distributed example at cyberweb/examples/advanced/draw_circle/draw_circle.cgi showcasing this functionality.
class Cyberweb::ObtainCssRules
class Cyberweb::ObtainCssRules was added to quickly fetch the CSS rule shortcut.
For instance, the cyberweb gem comes with many custom CSS classes defined. I use these for different project.
One such CSS rule is this:
.mars1em {
margin-left: 1em;
margin-right: 1em;
}
Now: sometimes I can not use these custom CSS rules, even though I want to.
class Cyberweb::ObtainCssRules fills that use case.
We can tell this class to fetch the body of the CSS rule at .mars1em. This will then be automatically expanded onto the corresponding "margin-left" and "margin-right" entries.
To require this class do:
require 'cyberweb/utility_scripts/obtain_css_rules/obtain_css_rules.rb'
Furthermore, this class was also added to automatically make use of various shortcuts.
Let me demonstrate how I use this specifically.
In the file pidgin.rb, which is part of the roebe gem, I use the following:
default_template1 '
p.default {
.mars1em;
}
'
What does the above mean?
It means that the p-tag (in HTML), if it makes use of the CSS class called default, will use the CSS rules defined in the .mars1em CSS class' body.
So, it is exactly identical to the following:
p.default {
margin-left: 1em;
margin-right: 1em;
}
This is a bit similar to less and SASS and similar shortcut-tools.
Within the web-app, for class WebObject, I may then create these paragraphs via:
p_default {
e 'Hello world!'
}
Note that the above does not work 100% reliably; I added this in November 2022 in part to try it out.
In April 2023 this was improved a bit and changed slightly; I tend to use:
p_default_le {
}
nowadays.
At some later point in time this may be improved, so use with care. I recommend to be very strict when using the above functionality; the less complexity, the better usually (unless you can write more succinct and more expressive code, perhaps; but even then it is a trade-off ultimately).
Since as of April 2023 this functionality has proven to work fairly well, so tentatively I can recommend it now. All my local webpages make use of this already.
Returning all images from a remote website
If you ever have a use case that you wish to return all images found on a remote website, consider using the following API:
x = Cyberweb.return_all_images_from_this_webpage('https://www.projectaon.org/en/xhtml/lw/02fotw/sect166.htm', true)
This would yield the following Array:
[
"https://www.projectaon.org/en/xhtml/lw/02fotw/title.png",
"https://www.projectaon.org/en/xhtml/lw/02fotw/brdrtpl.png",
"https://www.projectaon.org/en/xhtml/lw/02fotw/brdrtp.png",
"https://www.projectaon.org/en/xhtml/lw/02fotw/brdrtpr.png",
"https://www.projectaon.org/en/xhtml/lw/02fotw/brdrl.png",
"https://www.projectaon.org/en/xhtml/lw/02fotw/ill10.png",
"https://www.projectaon.org/en/xhtml/lw/02fotw/brdrr.png",
"https://www.projectaon.org/en/xhtml/lw/02fotw/brdrbtl.png",
"https://www.projectaon.org/en/xhtml/lw/02fotw/brdrbt.png",
"https://www.projectaon.org/en/xhtml/lw/02fotw/brdrbtr.png",
"https://www.projectaon.org/en/xhtml/lw/02fotw/left.png",
"https://www.projectaon.org/en/xhtml/lw/02fotw/toc.png",
"https://www.projectaon.org/en/xhtml/lw/02fotw/right.png"
]
Rack and the cyberweb project
Rack is a modular Ruby web server interface. It is very popular in the ruby ecosystem.
The most important method that rack requires is .call().
In May 2023 I tested whether Rack works for Cyberweb::HtmlTemplate and Cyberweb::WebObject - and it does. So we can now use, for instance, webrick, and have rack work automatically for these two classes specific to the cyberweb project.
In the long run I plan to smoothen this out, to make it possible to just use Rack directly rather than, say, sinatra or ruby-on-rails with the cyberweb gem.
Examples distributed in the cyberweb project
This subsection has a few noteworthy points to make about examples distributed in the cyberweb project.
You can find these examples under the directory called examples/ - easy to remember.
You can find plain HTML examples, and examples that use JavaScript and CSS. Additionally some examples stored as .cgi files are distributed as well, to demonstrate how the cyberweb project works. I recommend that you have a look at the simple examples first, without .cgi, unless you already know HTML/CSS/JavaScript, and then transition into the .cgi files. That should make it a bit easier to understand what is going on.
You may find that these examples sort of follow a specific style, more or less. For instance, I tend to name all animations with a trailing _animation tag. That helps me identify which animations exist more easily so.
JavaScript in general
The next subsection will contain some information about JavaScript.
JavaScript and JSON
To convert JSON to JavaScript the following function can be used:
JSON.parse()
To convert a JavaScript object to JSON, the following function can be used:
JSON.stringify()
Variables in JavaScript
The three ways to declare a variable in JavaScript goes via var, let and const.
- var variables can be updated and re-declared within their scope
- let variables can be updated but not re-declared
- const variables can neither be updated nor re-declared
Adding an Event Listener
The syntax in general goes like this:
.addEventListener('click', call_function_here);
The above line would allow us to respond to a click-action. We could also use onclick="call_function_here()", but one advantage of using event listeners is that we can be more flexible, and even remove events again.
JavaScript comments
The simplest way to use comments in JavaScript, in my opinion, is via:
/* This is a comment */
JavaScript loops
To do a loop in "modern" JavaScript, try:
for (let i = 0; i < 5; ++i) {
/* do stuff here */
}
The index variable i will remain completely local to the block, and not appear outside of it.
Note that JavaScript also allows you to use a .forEach loop instead, which no longer requires of you to use an index-counter.
There are a few variations possible for the .forEach() loop.
A somewhat verbose variant is the following one:
array.forEach(
function(entry) {
document.write(
"<img style=\"margin: 2px; margin-bottom: 5px\" src=\""+entry.replace(/^(\/home\/x\/data\/images\/fotos\/)/,"")+
"\"><br>\n"
)
document.write('<br>')
}
);
Here we can easily use multiple lines.
A shorter variant exists via the => arrow.
Example for this:
array.forEach(entry => console.log(entry));
So this is basically like pp in ruby.
Checking for specific keys pressed, via JavaScript
You can obtain an event, and then call the method .code on it, such as via:
if (e.code === 'ArrowLeft') { # For the left-arrow key.
}
if (e.code === 'ArrowRight') { # For the right-arrow key.
}
Converting Strings to Numbers in JavaScript
To convert a String such as "5" to the Integer 5, use:
x = "5"
parseInt(x)
To convert a String such as "5.15" to the Float 5.15, use:
x = "5.15"
parseFloat(x)
Numbers can be converted to a String via the method toString().
You can then also use the comparison operator, aka ===:
a = parseInt("3");
b = parseInt("5");
a === b
Setting a default value to a variable in JavaScript
let = object.method1 || 'Default Value here'
Using the switch statement in JavaScript
Usage example:
switch(expression){
case x:
/* code to run when expression === x */
break;
case y:
/* code to run when expression === y */
break;
default:
/* code to run if nothing else matches expression */
}
Symbols in JavaScript
To define a symbol in JavaScript, use Symbol() such as in:
let symbol1 = Symbol("mysymbol1")
String concatenation in JavaScript
The simplest way to concatenate two Strings in JavaScript is by using the + operator.
Example for this:
= "foo" + "bar"
You can append to an existing String via the += operator.
Example for this:
= "foo"
+= "bar"
You can also use the method .concat(), such as in:
foo = "foo"
= foo.concat("bar")
Obtaining user input in JavaScript
The following code example shows how to obtain user input via JavScript:
var x, y;
x = prompt("Gib mal eine Zahl ein","")
y = prompt("Gib mir noch eine Zahl","")
alert(Number(x)+Number(y)
So the primary way to obtain user through JavaScript goes via window.prompt. The second argument to that method specifies the default value of the input-field.
Creating an Array in JavaScript
The easiest way is the following:
const array = ['red','green','blue'] # This is also called the Array literal notation.
Note that at the least two additional ways exist in JavaScript to create an Array.
You can use:
The Array() constructor, aka:
new Array();
and
Functions that return arrays, such as split().
Note that you can, of course, also pass in elements into the Array when you create it via new. The following example shows this:
const array = new Array('January','February','March')
Personally I prefer the [] variant, as Ruby also uses it and I have become so used to it.
Appending and Prepending onto a JavaScript Array
The method .push() can be used to add content, via an append-operation, onto an array.
new_array.push(old_array[i]);
If you wish to add elements onto the beginning of an Array, use .unshift() such as via:
new_array.unshift("foobar"); /* Adds "foobar" to the beginning of the Array */
Splitting a String into an Array, in JavaScript
You can use the .split() method on a String, to split it up into an Array.
Example for this:
let x = 'Foo, Bar, Bla'
const splitted = x.split(',')
Simplified for-loop in JavaScript
You can iterate over an Array in JavaScript via:
const colours = ["Pink", "Green", "Yellow", "Black"];
for (const this_colour of colours) {
console.log(this_colour); /* Display the element in the javascript-console */
}
Splitting an Array in JavaScript via the , delimiter
const new_array = old_array.split(',');
Shortcomings of JavaScript
This subsection lists some shortcomings of JavaScript. This may be subject to change, as JavaScript changes as well. It is not a rant as such either - the focus will be on syntax.
You can not use inline JavaScript if it contains the end part , such as:
"); }
JavaScript support in the cyberweb project
The following subsection shows some of the javascript-related code and possibilities in regards to the cyberweb project.
The method .dump_all_javascript() in Cyberweb::WebObject
If you want to embed all javascript as a String and just put that string into the webpage, you can use this method call:
dump_all_javascript
This is a bit hackish for now. The use case here was that a local .js file has to exist, in order for the browser to make use of it. For some reason this was not always the case on webservers I used - so, rather than invest more time to find the real problem, I simply added that method to be done with it and move it. That way I can still call custom javascript functions such as .toggle() and similar functions.
JavaScript for-in and for-of loops:
Just examples for each:
for (const key in {a: 1, b: 2}) {
console.log(key);
}
// a, b
for (const value of [1,2,3,4,5]) {
console.log(value);
}
// 1, 2, 3, 4, 5
Javascript-support in the Cyberweb project
Have a look at the subdirectory called javascript/.
If a new javascript-component is added, it should be registered in one of the .rb files in said directory.
Data Types in JavaScript (ECMAScript)
There are six simple data types:
Undefined
Null
Boolean
Number
String
Symbol
How to use the typeof() operator in JavaScript
The typeof operator is called like this:
let x = "some string";
typeof(x) # "string"
typeof(95) # "number"
Note that the () for typeof() could be omitted, as typeof is an operator and not a function - but it seems simpler to use the () just as it is used for other functions in JavaScript as well.
JavaScript clock
If you wish to display a small JavaScript "clock" that just shows the time, you could use this:
display_clock('pad1em') { :larger_font_size }
The block argument just increases the font-size a bit; it can be omitted of course, as can all arguments, too:
display_clock
Specify JavaScript files
You can specify a specific javascript file via:
w.javascript_file = '../../CODE/JS/FADER.js'
w.javascript_file = :fader
As you can see, both a string version giving the full path, and a Symbol shortcut, will work - provided that the Symbol was registered.
I recommend to use the Symbol version for two reasons: first, it is less to type. Second, it is trivial to change the path lateron.
Removing child elements in JavaScript
An element can be removed via JavaScript by issueing:
this.parentNode.removeChild(this)
Default parameters to functions in JavaScript
You can use default values to functions in JavaScript.
Example:
function multiply(a, b = 1) {
return a * b;
}
console.log(multiply(5, 2));
console.log(multiply(5));
Alternatively you could also use || inside of the function body, to simulate default values.
It may then look like this inside of a function:
= || "Default Value";
JavaScript's document.getElementById()
You can use JavaScript's document.getElementById() to modify values programmatically.
Example showcasing this:
function () {
document.getElementById("set_on_value_changed").value = "44";
}
All you need to know is the ID of the target element.
Does order matter for JavaScript?
Script tags that are used in a webpage are executed in the order they appear. So, if you look at the following JavaScript code:
<script>
var x = 42;
</script>
<script>
alert(x); // Will alert '3';
</script>
Then first the variable x will be set, to the value of 42.
Note that this also applies to when you load external .js files - first in, first to be evaluated. So order does indeed matter.
The reason I noted this down here was in the event that I may forgot why I decided to load some .js files before others.
There is, however had, also a practical consideration here: if you have some external .js files that take a while to load, it may be best to put them near the end of the page, or at the least after other .js files were already loaded, as it may otherwise slow down the loading of the webpage. This is the reason why some webpages recommend to put JavaScript script-tags shortly before the closing