========================= Saturday, August 30, 2014 ========================= I am working on a frustrating problem with Javascript/ExtJS. How to reproduce it =================== To show the context without requiring you to install :ref:`welfare`, I extended :mod:`lino.projects.min1` (a minimal demo application used for certain tests): - it now installs :mod:`lino_xl.lib.cal` (a basic calendar module) - it now defines a :meth:`lino.core.site.Site.get_admin_main_items` method which yields :class:`ml.cal.MyEvents`:: def get_admin_main_items(self, ar): yield self.modules.cal.MyEvents The :meth:`lino.core.site.Site.get_admin_main_items` method is expected to yield a list of tables to be displayed in the body of the main page using "plain html". Here is how :mod:`lino.projects.min1` now looks after Robin logged in: .. image:: 0830a.png :scale: 90 You should be able to reproduce the above by installing the latest development version of Lino (as explained in :ref:`lino.dev.install`) and executing:: $ cd ~/repositories/lino/lino/projects/min1 $ python manage.py initdb_demo $ runserver .. |link| image:: link.png Now please note the |link| symbol after the table's title ("My events"). Clicking on this symbol opens the given table in a "real" window with an editable ExtJS grid. The initial problem report then was: - When I add an event in the "My events" table, then that event isn't displayed in main page after closing the window. This was an easy pick, the problem came because Lino didn't refresh the main page. I just needed to add a call to `Lino.viewport.refresh()` when the last window has been closed. Summary of the relevant JavaScript code:: Lino.close_window = function(status_update, norestore) { var ww = Lino.window_history.pop(); ... if (ww) { ... Lino.current_window = ww.window; } else { Lino.current_window = null; Lino.viewport.refresh(); // new since 20140829 } ... }; That worked. But it has a side effect: Once the main page has been refreshed that way (by closing the last window, not by reloading the whole page), the |link| doesn't work anymore. The window just doesn't open, and there is no error message. If you were able to follow until here, then please try help me to solve this problem! A first explanation =================== Joe suggested the following explanation: I think your JS problem is pretty standard. When you replace some HTML content, script tags included are not executed and of course all event bindings are discarded together with old HTML code. Possibilities to fix: #. Make the html-replacing code execute script tags and bind the actions in replaced HTML code. Ext JS has built-in support. My first pull request was just about it: https://gitlab.com/lino-framework/lino/pull/1/files #. Use "correct" way of action binding using top-level element catching bubbling events from child elements. See http://api.jquery.com/on/ that explains it. The essence is to bind the event on top element that is not replaced. After the child elements are replaces all bindings are still there and events bubbles-up normally. #. Manually re-bind actions after reload. My answer: I don't understand this explanation. Because where are those event bindings that might get discarded? In fact I even believe that the reason must be somewhere else. Two observations to explain why: **Observation 1** The `Lino.Viewport.refresh()` function sends an AJAX request and receives the following html fragment as response::

Quick links: [Detail Persons]...

Hi, Robin!

This is a Lino demo site. ...

My events

...
Then it updates the `main_area` with this fragment:: if (result.html) { var cmp = Ext.getCmp('main_area'); cmp.update(result.html); } I tried to specify ``true`` for the `Component.update() `_ method:: cmp.update(result.html, true); Which didn't solve the problem. AFAICS the HTML of `main_area` does not use script tags, just a `javascript:` anchor. And the specified code (`Lino.cal.MyEvents.grid.run(null)`) continues to be executed when I click on the symbol. **Observation 2** Here is the definition of `Lino.WindowAction` whose `run()` method is being called:: Lino.WindowAction = Ext.extend(Lino.WindowAction,{ window : null, get_window : function() { if (this.window == null) { // if (true) { this.windowConfig.main_item = this.main_item_fn(); this.window = new Lino.Window(this.windowConfig); } return this.window; }, run : function(requesting_panel, status) { Lino.open_window(this.get_window(), status, requesting_panel); } }); This code does a kind of "caching" of the `Ext.Window` object, and this caching is related to our problem because when I disable it (by writing `if (true)` instead of `if (this.window == null)`), then the problem *does not* occur.