diff --git a/docs/source/_static/basic.css b/docs/source/_static/basic.css
index 9f42944a9b..ec33ab6d6e 100644
--- a/docs/source/_static/basic.css
+++ b/docs/source/_static/basic.css
@@ -48,9 +48,7 @@ div.sphinxsidebarwrapper {
}
div.sphinxsidebar {
- float: left;
- width: 230px;
- margin-left: -100%;
+ width: 21%;
font-size: 90%;
word-wrap: break-word;
overflow-wrap : break-word;
@@ -72,7 +70,7 @@ div.sphinxsidebar ul ul {
}
div.sphinxsidebar form {
- margin-top: 10px;
+ margin: 10px 0;
}
div.sphinxsidebar input {
diff --git a/docs/source/_static/nature.css b/docs/source/_static/nature.css
index ee6c86b042..868232b76b 100644
--- a/docs/source/_static/nature.css
+++ b/docs/source/_static/nature.css
@@ -23,16 +23,16 @@ body {
color: #555;
margin: 0;
padding: 0;
- height:88
}
div.documentwrapper {
- float: left;
- width: 100%;
+ display: flex;
+ flex-wrap: wrap;
}
div.bodywrapper {
- margin: 0 0 0 230px;
+ width: 79%;
+ box-sizing: border-box;
}
hr {
@@ -435,7 +435,9 @@ code.descname {
@media print, screen and (max-width: 960px) {
div.body {
- width: auto;
+ min-width: auto;
+ max-width: none;
+ padding: 0 30px 30px 30px;
}
div.bodywrapper {
@@ -446,28 +448,16 @@ code.descname {
div.document,
div.documentwrapper,
div.bodywrapper {
- margin: 0 !important;
- width: 100%;
- }
+ margin: 0 !important;
- div.sphinxsidebar {
- visibility: hidden;
- }
-
- .search {
- visibility: visible;
- position: absolute;
- top: -7px;
- right: 200px;
}
#top-link {
- display: none;
+ display: none;
}
}
@media print, screen and (max-width: 720px) {
-
div.related>ul {
visibility: hidden;
}
@@ -476,16 +466,25 @@ code.descname {
visibility: visible;
}
- .search {
- right: 10px;
- }
-
}
@media print, screen and (max-width: 480px) {
-
div.body {
- padding-left: 2px;
+ box-sizing: border-box;
+ padding: 5px;
}
+ /*
+ * At screen sizes this small, the sidebar stacks on top
+ * of the main content, so they both are 100% width.
+ */
+ div.sphinxsidebar {
+ width: 100%;
+ }
+
+ div.document,
+ div.documentwrapper,
+ div.bodywrapper {
+ width: 100%;
+ }
}
diff --git a/docs/source/_templates/layout.html b/docs/source/_templates/layout.html
index 601836a7e5..1177222a5d 100644
--- a/docs/source/_templates/layout.html
+++ b/docs/source/_templates/layout.html
@@ -179,13 +179,14 @@
{%- block document %}
+
{%- if render_sidebar %}
+ {%- block sidebar2 %}{{ sidebar() }}{% endblock %}
{%- endif %}
{% block body %} {% endblock %}
-
{%- if render_sidebar %}
@@ -193,8 +194,6 @@
{%- endblock %}
- {%- block sidebar2 %}{{ sidebar() }}{% endblock %}
-
{%- endblock %}
diff --git a/docs/source/_templates/localtoc.html b/docs/source/_templates/localtoc.html
index c086a18df8..d10bc0711f 100644
--- a/docs/source/_templates/localtoc.html
+++ b/docs/source/_templates/localtoc.html
@@ -8,6 +8,6 @@
:license: BSD, see LICENSE for details.
#}
{%- if display_toc %}
-
+
{{ toc }}
{%- endif %}
diff --git a/evennia/contrib/tutorials/evadventure/README.md b/evennia/contrib/tutorials/evadventure/README.md
index 6e308c37d6..d500ea836d 100644
--- a/evennia/contrib/tutorials/evadventure/README.md
+++ b/evennia/contrib/tutorials/evadventure/README.md
@@ -2,6 +2,13 @@
Contrib by Griatch 2022
+
+```{warning}
+NOTE - this tutorial is WIP and NOT complete! It was put on hold to focus on
+releasing Evennia 1.0. You will still learn things from it, but don't expect
+perfection.
+```
+
A complete example MUD using Evennia. This is the final result of what is
implemented if you follow the Getting-Started tutorial. It's recommended
that you follow the tutorial step by step and write your own code. But if
diff --git a/evennia/utils/containers.py b/evennia/utils/containers.py
index ae3236a2b3..fbce2a3299 100644
--- a/evennia/utils/containers.py
+++ b/evennia/utils/containers.py
@@ -12,13 +12,14 @@ evennia.OPTION_CLASSES
from pickle import dumps
-from django.db.utils import OperationalError, ProgrammingError
-from django.conf import settings
-from evennia.utils.utils import class_from_module, callables_from_module
-from evennia.utils import logger
+from django.conf import settings
+from django.db.utils import OperationalError, ProgrammingError
+from evennia.utils import logger
+from evennia.utils.utils import callables_from_module, class_from_module
SCRIPTDB = None
+_BASE_SCRIPT_TYPECLASS = None
class Container:
@@ -200,16 +201,25 @@ class GlobalScriptContainer(Container):
initialized.
"""
+ global _BASE_SCRIPT_TYPECLASS
+ if not _BASE_SCRIPT_TYPECLASS:
+ _BASE_SCRIPT_TYPECLASS = class_from_module(settings.BASE_SCRIPT_TYPECLASS)
+
if self.typeclass_storage is None:
self.typeclass_storage = {}
- for key, data in self.loaded_data.items():
+ for key, data in list(self.loaded_data.items()):
try:
typeclass = data.get("typeclass", settings.BASE_SCRIPT_TYPECLASS)
- self.typeclass_storage[key] = class_from_module(typeclass)
+ script_typeclass = class_from_module(typeclass)
+ assert issubclass(script_typeclass, _BASE_SCRIPT_TYPECLASS)
+ self.typeclass_storage[key] = script_typeclass
except Exception:
logger.log_trace(
- f"GlobalScriptContainer could not start import global script {key}."
+ f"GlobalScriptContainer could not start import global script {key}. "
+ "It will be removed (skipped)."
)
+ # Let's remove this key/value. We want to let other scripts load.
+ self.loaded_data.pop(key)
def get(self, key, default=None):
"""
diff --git a/evennia/utils/tests/test_containers.py b/evennia/utils/tests/test_containers.py
new file mode 100644
index 0000000000..0f46ec1bca
--- /dev/null
+++ b/evennia/utils/tests/test_containers.py
@@ -0,0 +1,81 @@
+import unittest
+
+from evennia.utils import containers
+from django.conf import settings
+from django.test import override_settings
+from evennia.utils.utils import class_from_module
+
+_BASE_SCRIPT_TYPECLASS = class_from_module(settings.BASE_SCRIPT_TYPECLASS)
+
+class GoodScript(_BASE_SCRIPT_TYPECLASS):
+ pass
+
+class BadScript:
+ """Not subclass of _BASE_SCRIPT_TYPECLASS,"""
+ pass
+
+class WorseScript(_BASE_SCRIPT_TYPECLASS):
+ """objects will fail upon call"""
+ @property
+ def objects(self):
+ from evennia import module_that_doesnt_exist
+
+class TestGlobalScriptContainer(unittest.TestCase):
+
+ def test_init_with_no_scripts(self):
+ gsc = containers.GlobalScriptContainer()
+
+ self.assertEqual(len(gsc.loaded_data), 0)
+
+ @override_settings(GLOBAL_SCRIPTS={'script_name': {}})
+ def test_init_with_typeclassless_script(self):
+
+ gsc = containers.GlobalScriptContainer()
+
+ self.assertEqual(len(gsc.loaded_data), 1)
+ self.assertIn('script_name', gsc.loaded_data)
+
+ def test_start_with_no_scripts(self):
+ gsc = containers.GlobalScriptContainer()
+
+ gsc.start()
+
+ self.assertEqual(len(gsc.typeclass_storage), 0)
+
+ @override_settings(GLOBAL_SCRIPTS={'script_name': {}})
+ def test_start_with_typeclassless_script_defaults_to_base(self):
+ gsc = containers.GlobalScriptContainer()
+
+ gsc.start()
+
+ self.assertEqual(len(gsc.typeclass_storage), 1)
+ self.assertIn('script_name', gsc.typeclass_storage)
+ self.assertEqual(gsc.typeclass_storage['script_name'], _BASE_SCRIPT_TYPECLASS)
+
+ @override_settings(GLOBAL_SCRIPTS={'script_name': {'typeclass': 'evennia.utils.tests.test_containers.GoodScript'}})
+ def test_start_with_typeclassed_script_loads_it(self):
+ gsc = containers.GlobalScriptContainer()
+
+ gsc.start()
+
+ self.assertEqual(len(gsc.typeclass_storage), 1)
+ self.assertIn('script_name', gsc.typeclass_storage)
+ self.assertEqual(gsc.typeclass_storage['script_name'], GoodScript)
+
+ @override_settings(GLOBAL_SCRIPTS={'script_name': {'typeclass': 'evennia.utils.tests.test_containers.BadScript'}})
+ def test_start_with_bad_typeclassed_script_skips_it(self):
+ gsc = containers.GlobalScriptContainer()
+
+ gsc.start()
+
+ self.assertEqual(len(gsc.typeclass_storage), 0)
+ self.assertNotIn('script_name', gsc.typeclass_storage)
+
+ @override_settings(GLOBAL_SCRIPTS={'script_name': {'typeclass': 'evennia.utils.tests.test_containers.WorstScript'}})
+ def test_start_with_worst_typeclassed_script_skips_it(self):
+ gsc = containers.GlobalScriptContainer()
+
+ gsc.start()
+
+ self.assertEqual(len(gsc.typeclass_storage), 0)
+ self.assertNotIn('script_name', gsc.typeclass_storage)
diff --git a/evennia/web/static/webclient/js/plugins/goldenlayout.js b/evennia/web/static/webclient/js/plugins/goldenlayout.js
index c722706f6d..b64a9d9e8a 100644
--- a/evennia/web/static/webclient/js/plugins/goldenlayout.js
+++ b/evennia/web/static/webclient/js/plugins/goldenlayout.js
@@ -335,9 +335,9 @@ let goldenlayout = (function () {
//
var onTabCreate = function (tab) {
//HTML for the typeDropdown
- let renameDropdownControl = $("🢒");
- let typeDropdownControl = $("⯁");
- let updateDropdownControl = $("⯈");
+ let renameDropdownControl = $("▸");
+ let typeDropdownControl = $("◆");
+ let updateDropdownControl = $("▸");
let splitControl = $("+");
// track dropdowns when the associated control is clicked
renameDropdownControl.click( tab, renameDropdown );