By using this site, you agree to have cookies stored on your device, strictly for functional purposes, such as storing your session and preferences.

Dismiss

 Contributing.md

View raw Download
text/x-script.python • 15.52 kiB
Python script, ASCII text executable

Contributing Requirements

Style Guide

This document provides conventions for the coding style used in the Roundabout project. Rules can be broken -- just try to make the code as readable as you can.

When something is not covered by this document, refer to PEP 8. However, please read this even if you know PEP 8, as it diverges in some places.

Code Layout

Indents and Line Continuation

Keep lines up to 80 characters long. Use 4 spaces for indentation, per level. Do not use tabs, and do not put trailing whitespace.

For parentheses, three styles are accepted:

# No indent.
thing = function(arg1, arg2)

# Hanging indent. Align to the contents, not to the bracket.
thing = function(arg1, arg2
                arg3, arg4, arg5)

# Full indent. Here only one argument or variable or whatever is allowed per line.
# The closing bracket must be at the previous indent level.
# Any level is allowed, but it must be a multiple of 4.
thing = function(
   arg1,
   arg2,
   arg3,
   arg4
)

Collections should read like lists, not tables.

fruits = ["apple", "tomato", "pear", "cherry", "plum", "melon", "grape", "aubergine",]

fruits = [
   "apple",
   "tomato",
   "pear",
   "cherry",
   "plum",
   "melon",
   "grape",
   "aubergine",
]

# Don't!
fruits = [
   "apple", "tomato", "pear", "cherry",
   "plum", "melon", "grape", "aubergine",
]

Additionally, for a collection meant to be expanded use a trailing comma.

For long expressions, begin the line with the operator and align the operand with the indentation level. This is not permitted by PEP 8, but it follows mathematics and leads to nicer layouts.

population = (population
           + births
           + immigrants
           - deaths
           - emigrants)

When the hanging indent could be mistaken for a block, add an empty line.

Backslashes are discouraged, but allowed if it is the only way to write your expression. For example:

really_long_variable_name_hopefully_yours_wont_be_as_long = \
   "Really long value."

Blank Line Rules

  • Two between top-level class or function definitions.

  • One between local functions or methods.

  • One is allowed to separate related groups and logical sections.

  • One at the end of the file.

  • One below imports.

Imports

Imports should be on separate lines. from-imports must import all objects on the same line though.

import flask
import os

from models import User, Post

Imports should be ordered like this:

  • __future__ statements

  • one blank line

  • magic names (__all__, __version__)

  • one blank line

  • library imports

  • library from-imports

  • one blank line

  • application imports

  • application from-imports

Wildcard imports are discouraged and prohibited for libraries. However, they are fine if the module defines __all__.

Interior Whitespace

Never insert more than one space around operators and other symbols. Never add spaces just to align lines.

When to use
  • around the lowest priority operators in an expression, comparisons, assignments, and logical operators, as well as the function annotation arrow

    # Do
    thing += 10 + 2*thing
    # Don't
    thing+=10+2 * thing
    # Acceptable; use your best judgement
    thing += 10 + 2 * thing
    
  • after the colon when defining a single-line clause, or an annotation

  • after commas or semicolons

  • after the comment sign #

    When to avoid

  • when passing keyword arguments or defining argument defaults, unless they are annotated

  • inside any brackets

    # Do
    function(arg1, arg2)
    # Don't!
    function( arg1, arg2 )
    
  • after a trailing comma

    # Do
    (0,)
    # Don't!
    (0, )
    
  • before commas, semicolons or colons

    # Do
    x, y = y, x
    # Don't!
    x , y = y , x
    
  • around the slice operator :

  • before an argument list

    # Do
    function(arg1, arg2)
    # Don't!
    function (arg1, arg2)
    
  • before the indexing operator

    # Do
    dictionary["key"] = "Hello World!"
    # Don't!
    dictionary ["key"] = "Hello World!"
    

Other

Never use the semicolon for multiple statements; while allowed, it is discouraged as it hurts readability. Similarly discouraged are one-line clauses.

Strings

Only use double quotes like " for strings: single quotes are harder to spot, and they conflict with the common apostrophe.

For docstrings you should follow PEP 257. Additionally, docstrings should use Markdown to allow for a future tool to convert them to docs. HOWEVER arguments should be described using the ReST syntax, as it is more readable in the code. Other than this, they should be kept plaintext to prevent markup language battles (Python prefers RST, but most use Markdown).

Naming

Identifiers must only use ASCII characters. Abbreviations should be kept to a minimum and it should be made sure that they are widely used and accepted already. (id for identifier or repo for repository is acceptable, but avg for average is not). Generally, names should be easy to pronounce.

Class names must use UpperCamelCase with the first letter of each word capitalised and no underscores.

Other names (function, variable) should use snake_case with all words lowercase and separated by underscores.

For instance and class methods, only name the first argument self or cls, respectively.

To avoid conflicts, append an underscore or use a synonym but do not corrupt the spelling (class_ is better than clss or klass or classs or whatever).

Constants are an exception. They should use UPPER_CASE with underscores.

Non-public names should be prefixed with an underscore. In case it's really important to not use them, use a double underscore to invoke name mangling.

Comments

Block comments should be complete sentences; line comments don't need to. Write comments in English and always use a space after the comment sign, as stated above, unless it's an UNIX interpreter descriptor (#!) where you should not. Inside block comments, separate paragraphs with an empty comment, like in Markdown. For a solo sentence, full stops are optional. Avoid stating the obvious or contradicting the code.

Inline comments must be separated with more than one space from the statement, and they may be aligned.

In comments, never alter the case of identifiers, as it may lead to confusion.

Leaving TODO comments as personal notes is allowed, but they should be removed before merging or a release.

Programming guidelines

OOP Guidelines

Do not use getters and setters for class attributes. If you do need to change some other things, use properties.

Prefer overloading the operators; make using your objects as natural and Pythonic as possible.

Exceptions

Make exceptions specific enough, so catching them can be explicit.

Do not use the bare except clause. Make try clauses as short as possible to avoid silencing unrelated bugs.

Other

Comparisons to singletons (True, False, None etc.) should be done with the identity operators is and is not, not with the comparison operators. Use is not, not not ... is.

Unless it would be ambiguous, use the implicit truth test to check that numbers are different to 0, that containers have contents and similar tests.

Do not assign lambdas to identifiers. Make a real function instead.

Use with context managers to ensure resources are properly cleaned up.

Prefer making functions that take arguments and return a value instead of making them directly take global variables or process the information such as writing.

Use the methods startswith() and endswith() instead of string slicing to check for prefixes or suffixes.

To compare types, use isinstance() instead of the is operator with type() (this is one of my problems with Python, but it's the standard).

Use a proper condition for while instead of a while True that breaks.

Use for loops instead of while loops when possible, and use Pythonic iteration instead of C-style iteration.

To call shells, use the subprocess module instead of os.system() and use the functions that allow giving a list of arguments instead of a string, it leads to better security.

Similarly, avoid writing SQL manually, use Alchemy. If you must write SQL manually, be extra careful.

Jinja style guide

Jinja should be written like Python, with the following additions:

Tags should be written as {% <content> %} and expressions as {{ <content> }}. That is, put spaces around the content.

Always indent tag contents, just like you would indent HTML tags! If a tag contains other tags and it wouldn't disrupt whitespace, you should indent the contents. An exception can be made for top-level {% block %} tags, because indenting them would add an extra level of indentation to all HTML.

The filter operator | should have spaces around it, unless it's in a more complex expression when it shouldn't.

Translations should always be done with the {% trans %} tag provided by Babel, not with gettext(), _() or others. No exceptions.

The quoting rules are as in Python, unless it's in an HTML attribute, in which case you should use single quotes, as HTML takes precedence.

If you're trying to use some function that transforms or checks values, create additional filters or tests; they look cleaner.

HTML style guide

HTML tags should be written in lowercase, with attributes in lowercase as well. Attribute values should be quoted with double quotes. Attribute minimisation is suggested for boolean attributes.

Always indent tag contents with 4 spaces, except in plaintext tags like pre or textarea, where you should not indent as it affects rendering.

The tag should be multiple lines if the content is complex. Otherwise, mirror the page layout

  • so use:

<button>Label</button>  <!-- Good, because the content is simple AND the button is inline -->
<p>                     <!-- Good, because even though the content is simple, the tag is a block -->
   Content
</p>
<button>                <!-- Good, because the content is complex -->
   <iconify-icon icon="mdi:plus"></iconify-icon>
   Add
</button>

IDs or classes should be written in kebab-case. Names should be written in snake_case to provide better compatibility with Python.

Also, when making custom tags, always use a hyphen in the tag name, to make sure they won't be standardised in the future.

Inline CSS and JS should end with a semicolon, even if it's the only instruction.

CSS style guide

CSS selectors, properties and values should be written in lowercase. Custom properties should be written in kebab-case.

Always indent the contents of a ruleset with 4 spaces.

Unlike some other style guides, we do not require each selector after a comma to be on a new line. However, if they're too long, very complex or similar and they benefit from alignment, you should do so.

IDs are preferred over classes when the element only appears once on the page.

JavaScript style guide

JS should use double quotes for strings, and lowerCamelCase for names, and indenting should be 4 spaces. Otherwise I can't comment, because JS is ugly by nature. Try to make it as readable as possible and consistent with the other code. Also, use semicolons.

var is not deprecated and may be the best choice in some cases. Use let for temporary variables, but not const, as it provides a false sense of security by forbidding reassignment. However, if you const a mutable object, you can still change its contents.

Web programming guidelines

As a modern web developer, you will be disappointed. In the roundabout project, we write HTML and generate it on the server (which is not JavaScript, but Python/Flask). You may have to relearn web development if you want to contribute.

Also, we use semantic HTML, which means we use tags for their intended purpose. If you're using <div>, <span>, <input> and <img> for everything, you're doing it wrong.

We don't like bloat either, so we don't use <button class="btn btn-primary color-blue btn-large"> when <button> is enough. If you insist on something like Tailwind, you're in the wrong place.

It does not mean we do web development like in 2004. We use the modern features browsers gift us:

  • The powerful CSS layout engines, flexbox and gridbox

  • HTML5 semantic tags

  • JavaScript (plain!) for interactivity

  • SVG

  • Web fonts

and, most importantly, we use Flask, which didn't even exist in 2004.

In short:

  • The roundabout is not a SPA.

  • JS should be used to enhance the experience, not to create it.

  • We don't use client-side frameworks.

  • The server is a safe environment, so we can access the database and filesystem right from the server-side code.

  • JSON APIs are for specialised clients, not for the web interface.

  • This is a Python project, not a JavaScript project; treat it as such.

  • For live updates, get a segment of HTML, not JSON.

HTML

Use semantic tags where possible, and minimise the reliance of classes. If more than 10% of your tags are <div> or <span>, you're doing it wrong.

Use id if there is only one instance of the element on the page, not class.

Don't define custom attributes except data-* attributes.

CSS

Tag selectors are allowed! Style the default widgets as you see fit, because it leads to cleaner HTML. We also apply a reset stylesheet to make sure the default styles are consistent. In what scenario would you want an unstyled button in your site? Never! Then why always use <button class="btn btn-primary"> when it's the only kind of <button> your site has?

However, provide class-based alternatives for tag styles. For example, Efficient UI styles button by default, but it also styles .button to allow hyperlinks or other elements to look like buttons. Using both isn't needed though.

Also, selectors can be nested where it makes sense, however the > selector is preferred over plain nesting, which is generally discouraged.

For more information, read my article, Let's write more semantic CSS.

Use of fancy counters and data-attributes is allowed, but only for cosmetic purposes. We've got server-side templating, profit from it!

Inline CSS is only allowed to affect layout, not appearance.

New, application-specific styles should be added to /static/style.css. The CSS framework located in /static/efficient-ui/* should be kept reusable and generic; it will be published separately in the future. Improvements to the framework are welcome, but they should keep these goals in mind.

JavaScript

Event attributes are allowed, but please keep the JS inside shorter than a few tens of characters and limited to a single instruction. If you need more, use a separate script tag. Acceptable event JS includes, but is not limited to:

  • document.getElementById("dialog").showModal();

  • document.getElementById("id").classList.toggle("class");

  • myFunction();

  • document.getElementById("id").innerText = this.value;

If you're repeating the same event handler, put a class on the element and use addEventListener; it will produce smaller HTML.

Scripts should be small, independent and reusable, only added to the pages that require them, in the Jinja block {% block scripts %}.

Other

You may not call third-party JavaScripts or CSS; you must copy them to the repository. If you do, make sure they are licensed under a compatible licence.

Do not add features to snoop on users.

Make sure the site stays clean and loads quickly.

                
                    
1
Contributing Requirements
2
=========================
3
4
Style Guide
5
-----------
6
7
This document provides conventions for the coding style used in the Roundabout project.
8
Rules can be broken -- just try to make the code as readable as you can.
9
10
When something is not covered by this document, refer to [PEP 8](https://peps.python.org/pep-0008/).
11
However, please read this even if you know PEP 8, as it diverges in some places.
12
13
### Code Layout
14
15
#### Indents and Line Continuation
16
Keep lines up to 80 characters long. Use 4 spaces for indentation, per level. Do not use tabs, and do not put trailing whitespace.
17
18
For parentheses, three styles are accepted:
19
~~~python
20
# No indent.
21
thing = function(arg1, arg2)
22
23
# Hanging indent. Align to the contents, not to the bracket.
24
thing = function(arg1, arg2
25
arg3, arg4, arg5)
26
27
# Full indent. Here only one argument or variable or whatever is allowed per line.
28
# The closing bracket must be at the previous indent level.
29
# Any level is allowed, but it must be a multiple of 4.
30
thing = function(
31
arg1,
32
arg2,
33
arg3,
34
arg4
35
)
36
~~~
37
38
Collections should read like lists, not tables.
39
~~~python
40
fruits = ["apple", "tomato", "pear", "cherry", "plum", "melon", "grape", "aubergine",]
41
42
fruits = [
43
"apple",
44
"tomato",
45
"pear",
46
"cherry",
47
"plum",
48
"melon",
49
"grape",
50
"aubergine",
51
]
52
53
# Don't!
54
fruits = [
55
"apple", "tomato", "pear", "cherry",
56
"plum", "melon", "grape", "aubergine",
57
]
58
~~~
59
60
Additionally, for a collection meant to be expanded use a trailing comma.
61
62
For long expressions, begin the line with the operator and align the operand with the indentation level.
63
This is not permitted by PEP 8, but it follows mathematics and leads to nicer layouts.
64
~~~python
65
population = (population
66
+ births
67
+ immigrants
68
- deaths
69
- emigrants)
70
~~~
71
72
When the hanging indent could be mistaken for a block, add an empty line.
73
74
Backslashes are discouraged, but allowed if it is the only way to write your expression. For
75
example:
76
77
~~~python
78
really_long_variable_name_hopefully_yours_wont_be_as_long = \
79
"Really long value."
80
~~~
81
82
#### Blank Line Rules
83
* Two between top-level class or function definitions.
84
* One between local functions or methods.
85
* One is allowed to separate related groups and logical sections.
86
* One at the end of the file.
87
* One below imports.
88
89
#### Imports
90
91
Imports should be on separate lines. `from`-imports must import all objects on the same line though.
92
~~~python
93
import flask
94
import os
95
96
from models import User, Post
97
~~~
98
99
Imports should be ordered like this:
100
* `__future__` statements
101
* one blank line
102
* magic names (`__all__`, `__version__`)
103
* one blank line
104
* library imports
105
* library `from`-imports
106
* one blank line
107
* application imports
108
* application `from`-imports
109
110
Wildcard imports are discouraged and prohibited for libraries. However, they are fine if the module
111
defines `__all__`.
112
113
#### Interior Whitespace
114
Never insert more than one space around operators and other symbols. Never add spaces just to align lines.
115
116
##### When to use
117
* around the lowest priority operators in an expression, comparisons, assignments, and logical operators, as well as the function annotation arrow
118
~~~python
119
# Do
120
thing += 10 + 2*thing
121
# Don't
122
thing+=10+2 * thing
123
# Acceptable; use your best judgement
124
thing += 10 + 2 * thing
125
~~~
126
* after the colon when defining a single-line clause, or an annotation
127
* after commas or semicolons
128
* after the comment sign `#`
129
#### When to avoid
130
* when passing keyword arguments or defining argument defaults, unless they are annotated
131
* inside any brackets
132
~~~python
133
# Do
134
function(arg1, arg2)
135
# Don't!
136
function( arg1, arg2 )
137
~~~
138
* after a trailing comma
139
~~~python
140
# Do
141
(0,)
142
# Don't!
143
(0, )
144
~~~
145
* before commas, semicolons or colons
146
~~~python
147
# Do
148
x, y = y, x
149
# Don't!
150
x , y = y , x
151
~~~
152
* around the slice operator `:`
153
* before an argument list
154
~~~python
155
# Do
156
function(arg1, arg2)
157
# Don't!
158
function (arg1, arg2)
159
~~~
160
* before the indexing operator
161
~~~python
162
# Do
163
dictionary["key"] = "Hello World!"
164
# Don't!
165
dictionary ["key"] = "Hello World!"
166
~~~
167
168
#### Other
169
Never use the semicolon for multiple statements; while allowed, it is discouraged as it hurts readability. Similarly discouraged are one-line clauses.
170
171
### Strings
172
173
Only use double quotes like `"` for strings: single quotes are harder to spot, and they conflict with the common apostrophe.
174
175
For docstrings you should follow [PEP 257](https://peps.python.org/pep-0257/). Additionally, docstrings should use Markdown to allow for a future tool to convert them to docs.
176
HOWEVER arguments should be described using the ReST syntax, as it is more readable in the code.
177
Other than this, they should be kept plaintext to prevent markup language battles (Python prefers
178
RST, but most use Markdown).
179
180
### Naming
181
182
Identifiers must only use ASCII characters. Abbreviations should be kept to a minimum and it should be
183
made sure that they are widely used and accepted already.
184
(`id` for `identifier` or `repo` for `repository` is acceptable, but `avg` for `average` is not). Generally, names should be easy to pronounce.
185
186
Class names must use `UpperCamelCase` with the first letter of each word capitalised and no underscores.
187
188
Other names (function, variable) should use `snake_case` with all words lowercase and separated by underscores.
189
190
For instance and class methods, only name the first argument `self` or `cls`, respectively.
191
192
To avoid conflicts, append an underscore or use a synonym but do not corrupt the spelling (`class_` is better than `clss` or `klass` or `classs` or whatever).
193
194
Constants are an exception. They should use `UPPER_CASE` with underscores.
195
196
Non-public names should be prefixed with an underscore. In case it's really important to not use
197
them, use a double underscore to invoke name mangling.
198
199
### Comments
200
201
Block comments should be complete sentences; line comments don't need to. Write comments in
202
English and always use a space after the comment sign, as stated above, unless it's an UNIX
203
interpreter descriptor (`#!`) where you should not. Inside block comments, separate paragraphs
204
with an empty comment, like in Markdown. For a solo sentence, full stops are optional.
205
Avoid stating the obvious or contradicting the code.
206
207
Inline comments must be separated with more than one space from the statement, and they may be
208
aligned.
209
210
In comments, never alter the case of identifiers, as it may lead to confusion.
211
212
Leaving TODO comments as personal notes is allowed, but they should be removed before merging
213
or a release.
214
215
Programming guidelines
216
----------------------
217
218
### OOP Guidelines
219
Do not use getters and setters for class attributes. If you do need to change some other things,
220
use properties.
221
222
Prefer overloading the operators; make using your objects as natural and Pythonic as possible.
223
224
### Exceptions
225
Make exceptions specific enough, so catching them can be explicit.
226
227
Do not use the bare `except` clause. Make `try` clauses as short as possible to avoid silencing
228
unrelated bugs.
229
230
### Other
231
Comparisons to singletons (`True`, `False`, `None` etc.) should be done with the identity operators
232
`is` and `is not`, not with the comparison operators. Use `is not`, not `not ... is`.
233
234
Unless it would be ambiguous, use the implicit truth test to check that numbers are different to
235
0, that containers have contents and similar tests.
236
237
Do not assign lambdas to identifiers. Make a real function instead.
238
239
Use `with` context managers to ensure resources are properly cleaned up.
240
241
Prefer making functions that take arguments and return a value instead of making them directly take
242
global variables or process the information such as writing.
243
244
Use the methods `startswith()` and `endswith()` instead of string slicing to check for prefixes
245
or suffixes.
246
247
To compare types, use `isinstance()` instead of the `is` operator with `type()` (this is one of
248
my problems with Python, but it's the standard).
249
250
Use a proper condition for `while` instead of a `while True` that `break`s.
251
252
Use `for` loops instead of `while` loops when possible, and use Pythonic iteration instead of
253
C-style iteration.
254
255
To call shells, use the `subprocess` module instead of `os.system()` and use the functions
256
that allow giving a *list* of arguments instead of a string, it leads to better security.
257
258
Similarly, avoid writing SQL manually, use Alchemy. If you must write SQL manually, be extra
259
careful.
260
261
Jinja style guide
262
-----------------
263
264
Jinja should be written like Python, with the following additions:
265
266
Tags should be written as `{% <content> %}` and expressions as `{{ <content> }}`. That is,
267
put spaces around the content.
268
269
Always indent tag contents, just like you would indent HTML tags! If a tag contains other tags
270
and it wouldn't disrupt whitespace, you should indent the contents. An exception can be made
271
for top-level `{% block %}` tags, because indenting them would add an extra level of indentation
272
to all HTML.
273
274
The filter operator `|` should have spaces around it, unless it's in a more complex expression
275
when it shouldn't.
276
277
Translations should always be done with the `{% trans %}` tag provided by Babel, not with
278
`gettext()`, `_()` or others. No exceptions.
279
280
The quoting rules are as in Python, unless it's in an HTML attribute, in which case you should
281
use single quotes, as HTML takes precedence.
282
283
If you're trying to use some function that transforms or checks values, create additional filters
284
or tests; they look cleaner.
285
286
HTML style guide
287
----------------
288
289
HTML tags should be written in lowercase, with attributes in lowercase as well. Attribute values
290
should be quoted with double quotes. Attribute minimisation is suggested for boolean attributes.
291
292
Always indent tag contents with 4 spaces, except in plaintext tags like `pre` or `textarea`, where
293
you should not indent as it affects rendering.
294
295
The tag should be multiple lines if the content is complex. Otherwise, mirror the page layout
296
- so use:
297
298
```html
299
<button>Label</button> <!-- Good, because the content is simple AND the button is inline -->
300
<p> <!-- Good, because even though the content is simple, the tag is a block -->
301
Content
302
</p>
303
<button> <!-- Good, because the content is complex -->
304
<iconify-icon icon="mdi:plus"></iconify-icon>
305
Add
306
</button>
307
```
308
309
IDs or classes should be written in `kebab-case`. Names should be written in `snake_case` to
310
provide better compatibility with Python.
311
312
Also, when making custom tags, always use a hyphen in the tag name, to make sure they won't be
313
standardised in the future.
314
315
Inline CSS and JS should end with a semicolon, even if it's the only instruction.
316
317
CSS style guide
318
---------------
319
320
CSS selectors, properties and values should be written in lowercase. Custom properties should be
321
written in `kebab-case`.
322
323
Always indent the contents of a ruleset with 4 spaces.
324
325
Unlike some other style guides, we do not require each selector after a comma to be on a new line.
326
However, if they're too long, very complex or similar and they benefit from alignment, you should
327
do so.
328
329
IDs are preferred over classes when the element only appears once on the page.
330
331
JavaScript style guide
332
----------------------
333
334
JS should use double quotes for strings, and lowerCamelCase for names, and indenting should be 4 spaces.
335
Otherwise I can't comment, because JS is ugly by nature. Try to make it as readable as possible
336
and consistent with the other code. Also, use semicolons.
337
338
`var` is not deprecated and may be the best choice in some cases. Use `let` for temporary variables,
339
but not `const`, as it provides a false sense of security by forbidding reassignment. However, if
340
you `const` a mutable object, you can still change its contents.
341
342
Web programming guidelines
343
--------------------------
344
345
As a modern web developer, you **will** be disappointed. In the roundabout project, we write
346
HTML and generate it on the server (which is not JavaScript, but Python/Flask). You may have
347
to relearn web development if you want to contribute.
348
349
Also, we use semantic HTML, which means we use tags for their intended purpose. If you're using
350
`<div>`, `<span>`, `<input>` and `<img>` for everything, you're doing it wrong.
351
352
We don't like bloat either, so we don't use `<button class="btn btn-primary color-blue btn-large">`
353
when `<button>` is enough. If you insist on something like Tailwind, you're in the wrong place.
354
355
It does not mean we do web development like in 2004. We use the modern features browsers gift us:
356
* The powerful CSS layout engines, flexbox and gridbox
357
* HTML5 semantic tags
358
* JavaScript (plain!) for interactivity
359
* SVG
360
* Web fonts
361
362
and, most importantly, we use Flask, which didn't even exist in 2004.
363
364
In short:
365
* The roundabout is not a SPA.
366
* JS should be used to enhance the experience, not to create it.
367
* We don't use client-side frameworks.
368
* The server is a safe environment, so we can access the database and filesystem right from the
369
server-side code.
370
* JSON APIs are for specialised clients, not for the web interface.
371
* This is a Python project, not a JavaScript project; treat it as such.
372
* For live updates, get a segment of HTML, not JSON.
373
374
### HTML
375
376
Use semantic tags where possible, and minimise the reliance of classes. If more than 10% of your
377
tags are `<div>` or `<span>`, you're doing it wrong.
378
379
Use `id` if there is only one instance of the element on the page, not `class`.
380
381
Don't define custom attributes except `data-*` attributes.
382
383
### CSS
384
385
Tag selectors are **allowed**! Style the default widgets as you see fit, because it leads to
386
cleaner HTML. We also apply a reset stylesheet to make sure the default styles are consistent.
387
In what scenario would you want an *unstyled* button in your site? Never! Then why always use
388
`<button class="btn btn-primary">` when it's the only kind of `<button>` your site has?
389
390
However, provide class-based alternatives for tag styles. For example, Efficient UI styles
391
`button` by default, but it also styles `.button` to allow hyperlinks or other elements to look
392
like buttons. Using both isn't needed though.
393
394
Also, selectors can be nested where it makes sense, however the `>` selector is preferred over
395
plain nesting, which is generally discouraged.
396
397
For more information, read my article,
398
[Let's write more semantic CSS](https://roundabout.roundabout-host.com/articles/semantic-css.html).
399
400
Use of fancy counters and data-attributes is allowed, but only for cosmetic purposes. We've got
401
server-side templating, profit from it!
402
403
Inline CSS is only allowed to affect layout, *not* appearance.
404
405
New, application-specific styles should be added to `/static/style.css`. The CSS framework
406
located in `/static/efficient-ui/*` should be kept reusable and generic; it will be published
407
separately in the future. Improvements to the framework are welcome, but they should keep these
408
goals in mind.
409
410
### JavaScript
411
412
Event attributes are allowed, but please keep the JS inside shorter than a few tens of characters
413
and limited to a single instruction. If you need more, use a separate script tag. Acceptable event
414
JS includes, but is not limited to:
415
416
* `document.getElementById("dialog").showModal();`
417
* `document.getElementById("id").classList.toggle("class");`
418
* `myFunction();`
419
* `document.getElementById("id").innerText = this.value;`
420
421
If you're repeating the same event handler, put a class on the element and use `addEventListener`;
422
it will produce smaller HTML.
423
424
Scripts should be small, independent and reusable, only added to the pages that require them,
425
in the Jinja block `{% block scripts %}`.
426
427
Other
428
-----
429
430
You may not call third-party JavaScripts or CSS; you must copy them to the repository. If you
431
do, make sure they are licensed under a compatible licence.
432
433
Do not add features to snoop on users.
434
435
Make sure the site stays clean and loads quickly.
436