The layout is basically the one reccommended by ExtJS, however since we route apps through Django, there are minor differences:
appname/
models.py
urls.py
...
static/
appname/
app/
Application.js
TestApplication.js
JasmineTestApplication.js
controller/
model/
store/
view/
TODO
Typically looks something like this:
from django.conf.urls.defaults import patterns
from devilry.apps.jsapp.views import create_urls
urlpatterns = patterns('devilry.apps.myapp',
*create_urls('myapp',
with_css=True,
libs=['jsapp', 'themebase']))
See devilry.apps.jsapp.views.create_urls(). Notice that we specify two libs. You will usually need these two. jsapp provides the architecture for the app framework, and themebase provides the default theme, re-usable layouts and common widgets.
Refer to ExtJS docs.
A subclass of Ext.app.Application.
A subclass of <appname>.Application.
Add your CSS to <appname>/static/<appname>/resources/stylesheets/<appname>.css and update urls.py with the with_css=True argument to devilry.apps.jsapp.views.create_urls().
We reccommend Compass:
$ cd <appname>/static/<appname>/
$ compass create resources
$ cd resources
$ rm sass/ie.scss sass/screen.scss sass/print.scss
Add your styles to sass/<appname>.scss and compile using:
$ compass compile
You may also autocompile on file changes using:
$ compass watch
The natural structure of the data controlled by the app should be organized in a directory-like routing scheme:
#/
List all items
#/someitem
Show "someitem"
#/someitem/
Show all children of "someitem"
#/someitem/childitem
Show "childitem"
Cross cutting and non-hierarchial routes should use the following format:
#/@@some-action
#/someitem/@@some-action
Prefixing with @@ makes it clear to developers that these are not part of the normal hierarchy browsing.
Libraries are just like apps, however they should put their data in extjs classes in lib/ instead of app.
Use the TestApplication.js views with selenium to test views. Your selenium tests should inherit from devilry.apps.jsapp.seleniumhelpers.SeleniumTestCase. Example:
from devilry.apps.jsapp.seleniumhelpers import SeleniumTestCase
class TestSomething(SeleniumTestCase):
appname = 'something'
def test_chooseperiod_render(self):
self.browseToTest('/@@create-something')
self.waitForCssSelector('.somecssclass')
self.assertTrue('Something something' in self.driver.page_source)
Run tests just like any other django-nose test. Example:
bin/django_dev.py test devilry.apps.something
You must be running the Django server at port 8080 for this to work.
TestApplication.js must not require any persistence on the server. Mock everything. See the devilry.apps.subjectadmin for examples.
Add Jasmine test specs to static/<appname>/jasminespecs/. Use the JasmineTestApplication.js view (http://localhost:8080/APPNAME/jasminetest) to run your tests during development. Add them to the regular test suite as a selenium test like so:
class TestSomething(SeleniumTestCase):
...
def test_jasmine(self):
self.runJasmineTests()
The order of statements in requires: [...] should be:
Example:
requires: [
'Ext.form.field.ComboBox',
'Ext.form.field.Text',
'Ext.form.field.Hidden',
'Ext.toolbar.Toolbar',
'devilry.extjshelpers.formfields.DateTimeField',
'themebase.CreateButton',
'themebase.AlertMessageList',
'themebase.form.Help',
'view.SomeView',
'view.AnotherView'
]
Private methods should be prefixed with _. These methods should never be used outside the class, not even in subclasses.