We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Accordion's active does not work correctly
#### ALL software version info
Python 3.7.6, panel==0.10.3

#### Description of expected behavior and the observed behavior
1. I would expect `accordion.active` to return list of active cards. Now it returns an empty list even if some card is open.
2. Also setting values to `accordion.active` I would expect to open only selected cards. Now it opens selected cards, but does not close the ones that were not selected.

#### Complete, minimal, self-contained example code that reproduces the issue

```python
# based on https://panel.holoviz.org/reference/layouts/Accordion.html
import panel as pn
pn.extension()

from bokeh.plotting import figure

p1 = figure(width=300, height=80, name='Scatter', margin=5)
p1.scatter([0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 2, 1, 0])

p2 = figure(width=300, height=80, name='Line', margin=5)
p2.line([0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 2, 1, 0])

accordion = pn.Accordion(p1, p2)
accordion

```

```
accordion.active
```

```
accordion.active = [0]
```

#### Screenshots or screencasts of the bug in action
![Peek 2021-02-25 12-42](https://user-images.githubusercontent.com/33317987/109148806-05f1c680-7767-11eb-9487-d8895d4fad4f.gif)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `panel/layout/card.py`
Content:
```
1 import param
2 
3 from ..models import Card as BkCard
4 from .base import Column, Row, ListPanel
5 
6 
7 class Card(Column):
8     """
9     A Card layout allows arranging multiple panel objects in a
10     collapsible, vertical container with a header bar.
11     """
12 
13     active_header_background = param.String(doc="""
14         A valid CSS color for the header background when not collapsed.""")
15 
16     button_css_classes = param.List(['card-button'], doc="""
17         CSS classes to apply to the button element.""")
18 
19     collapsible = param.Boolean(default=True, doc="""
20         Whether the Card should be expandable and collapsible.""")
21 
22     collapsed = param.Boolean(default=False, doc="""
23         Whether the contents of the Card are collapsed.""")
24 
25     css_classes = param.List(['card'], doc="""
26         CSS classes to apply to the overall Card.""")
27 
28     header = param.Parameter(doc="""
29         A Panel component to display in the header bar of the Card.
30         Will override the given title if defined.""")
31 
32     header_background = param.String(doc="""
33         A valid CSS color for the header background.""")
34 
35     header_color = param.String(doc="""
36         A valid CSS color to apply to the header text.""")
37 
38     header_css_classes = param.List(['card-header'], doc="""
39         CSS classes to apply to the header element.""")
40 
41     title_css_classes = param.List(['card-title'], doc="""
42         CSS classes to apply to the header title.""")
43 
44     margin = param.Parameter(default=5)
45 
46     title = param.String(doc="""
47         A title to be displayed in the Card header, will be overridden
48         by the header if defined.""")
49 
50     _bokeh_model = BkCard
51     
52     _rename = dict(Column._rename, title=None, header=None, title_css_classes=None)
53 
54     def __init__(self, *objects, **params):
55         self._header_layout = Row(css_classes=['card-header-row'],
56                                   sizing_mode='stretch_width')
57         super().__init__(*objects, **params)
58         self.param.watch(self._update_header, ['title', 'header', 'title_css_classes'])
59         self._update_header()
60 
61     def _cleanup(self, root):
62         super()._cleanup(root)
63         self._header_layout._cleanup(root)
64 
65     def _process_param_change(self, params):
66         scroll = params.pop('scroll', None)
67         css_classes = self.css_classes or []
68         if scroll:
69             params['css_classes'] = css_classes + ['scrollable']
70         elif scroll == False:
71             params['css_classes'] = css_classes
72         return super(ListPanel, self)._process_param_change(params)
73 
74     def _update_header(self, *events):
75         from ..pane import HTML, panel
76         if self.header is None:
77             item = HTML('%s' % (self.title or "&#8203;"),
78                         css_classes=self.title_css_classes,
79                         sizing_mode='stretch_width',
80                         margin=(2, 5))
81         else:
82             item = panel(self.header)
83         self._header_layout[:] = [item]
84 
85     def _get_objects(self, model, old_objects, doc, root, comm=None):
86         ref = root.ref['id']
87         if ref in self._header_layout._models:
88             header = self._header_layout._models[ref][0]
89         else:
90             header = self._header_layout._get_model(doc, root, model, comm)
91         objects = super()._get_objects(model, old_objects, doc, root, comm)
92         return [header]+objects
93
```

Path: `panel/layout/accordion.py`
Content:
```
1 import param
2 
3 from bokeh.models import Column as BkColumn, CustomJS
4 
5 from .base import NamedListPanel
6 from .card import Card
7 
8 
9 class Accordion(NamedListPanel):
10     
11     active_header_background = param.String(default='#ccc', doc="""
12         Color for currently active headers.""")
13 
14     active = param.List(default=[], doc="""
15         List of indexes of active cards.""")
16 
17     header_color = param.String(doc="""
18         A valid CSS color to apply to the expand button.""")
19 
20     header_background = param.String(doc="""
21         A valid CSS color for the header background.""")
22 
23     toggle = param.Boolean(default=False, doc="""
24         Whether to toggle between active cards or allow multiple cards""")
25 
26     _bokeh_model = BkColumn
27     
28     _rename = {'active': None, 'active_header_background': None,
29                'header_background': None, 'objects': 'children',
30                'dynamic': None, 'toggle': None, 'header_color': None}
31 
32     _toggle = """
33     for (var child of accordion.children) {
34       if ((child.id !== cb_obj.id) && (child.collapsed == cb_obj.collapsed) && !cb_obj.collapsed) {
35         child.collapsed = !cb_obj.collapsed
36       }
37     }
38     """
39 
40     _synced_properties = [
41         'active_header_background', 'header_background', 'width',
42         'sizing_mode', 'width_policy', 'height_policy', 'header_color'
43     ]
44 
45     def __init__(self, *objects, **params):
46         super().__init__(*objects, **params)
47         self.param.watch(self._update_active, ['active'])
48         self.param.watch(self._update_cards, self._synced_properties)
49 
50     def _get_objects(self, model, old_objects, doc, root, comm=None):
51         """
52         Returns new child models for the layout while reusing unchanged
53         models and cleaning up any dropped objects.
54         """
55         from panel.pane.base import RerenderError, panel
56         new_models = []
57         if len(self._names) != len(self):
58             raise ValueError('Accordion names do not match objects, ensure '
59                              'that the Tabs.objects are not modified '
60                              'directly. Found %d names, expected %d.' %
61                              (len(self._names), len(self)))
62         for i, (name, pane) in enumerate(zip(self._names, self)):
63             pane = panel(pane, name=name)
64             self.objects[i] = pane
65 
66         for obj in old_objects:
67             if obj not in self.objects:
68                 self._panels[id(obj)]._cleanup(root)
69 
70         params = {k: v for k, v in self.param.get_param_values()
71                   if k in self._synced_properties}
72 
73         ref = root.ref['id']
74         current_objects = list(self)
75         for i, (name, pane) in enumerate(zip(self._names, self)):
76             params.update(self._apply_style(i))
77             if id(pane) in self._panels:
78                 card = self._panels[id(pane)]
79             else:
80                 card = Card(
81                     pane, title=name, css_classes=['accordion'],
82                     header_css_classes=['accordion-header'],
83                     margin=self.margin
84                 )
85                 self._panels[id(pane)] = card
86             card.param.set_param(**params)
87             if ref in card._models:
88                 panel = card._models[ref][0]
89             else:
90                 try:
91                     panel = card._get_model(doc, root, model, comm)
92                     if self.toggle:
93                         cb = CustomJS(args={'accordion': model}, code=self._toggle)
94                         panel.js_on_change('collapsed', cb)
95                 except RerenderError:
96                     return self._get_objects(model, current_objects[:i], doc, root, comm)
97             
98             new_models.append(panel)
99         self._update_cards()
100         self._update_active()
101         return new_models
102 
103     def _cleanup(self, root):
104         for panel in self._panels.values():
105             panel._cleanup(root)
106         super()._cleanup(root)
107 
108     def _apply_style(self, i):
109         if i == 0:
110             margin = (5, 5, 0, 5)
111         elif i == (len(self)-1):
112             margin = (0, 5, 5, 5)
113         else:
114             margin = (0, 5, 0, 5)
115         return dict(margin=margin, collapsed = i not in self.active)
116 
117     def _update_active(self, *events):
118         for i, pane in enumerate(self.objects):
119             if id(pane) not in self._panels:
120                 continue
121             self._panels[id(pane)].collapsed = i not in self.active
122 
123     def _update_cards(self, *events):
124         params = {k: v for k, v in self.param.get_param_values()
125                   if k in self._synced_properties}
126         for panel in self._panels.values():
127             panel.param.set_param(**params)
128
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/panel/layout/accordion.py b/panel/layout/accordion.py
--- a/panel/layout/accordion.py
+++ b/panel/layout/accordion.py
@@ -44,6 +44,7 @@
 
     def __init__(self, *objects, **params):
         super().__init__(*objects, **params)
+        self._updating_active = False
         self.param.watch(self._update_active, ['active'])
         self.param.watch(self._update_cards, self._synced_properties)
 
@@ -82,6 +83,7 @@
                     header_css_classes=['accordion-header'],
                     margin=self.margin
                 )
+                card.param.watch(self._set_active, ['collapsed'])
                 self._panels[id(pane)] = card
             card.param.set_param(**params)
             if ref in card._models:
@@ -94,7 +96,6 @@
                         panel.js_on_change('collapsed', cb)
                 except RerenderError:
                     return self._get_objects(model, current_objects[:i], doc, root, comm)
-            
             new_models.append(panel)
         self._update_cards()
         self._update_active()
@@ -114,11 +115,32 @@
             margin = (0, 5, 0, 5)
         return dict(margin=margin, collapsed = i not in self.active)
 
+    def _set_active(self, *events):
+        if self._updating_active:
+            return
+        active = []
+        self._updating_active = True
+        try:
+            for i, pane in enumerate(self.objects):
+                if id(pane) not in self._panels:
+                    continue
+                elif not self._panels[id(pane)].collapsed:
+                    active.append(i)
+            self.active = active
+        finally:
+            self._updating_active = False
+
     def _update_active(self, *events):
-        for i, pane in enumerate(self.objects):
-            if id(pane) not in self._panels:
-                continue
-            self._panels[id(pane)].collapsed = i not in self.active
+        if self._updating_active:
+            return
+        self._updating_active = True
+        try:
+            for i, pane in enumerate(self.objects):
+                if id(pane) not in self._panels:
+                    continue
+                self._panels[id(pane)].collapsed = i not in self.active
+        finally:
+            self._updating_active = False
 
     def _update_cards(self, *events):
         params = {k: v for k, v in self.param.get_param_values()
diff --git a/panel/layout/card.py b/panel/layout/card.py
--- a/panel/layout/card.py
+++ b/panel/layout/card.py
@@ -49,6 +49,8 @@
 
     _bokeh_model = BkCard
     
+    _linked_props = ['collapsed']
+
     _rename = dict(Column._rename, title=None, header=None, title_css_classes=None)
 
     def __init__(self, *objects, **params):

{"golden_diff": "diff --git a/panel/layout/accordion.py b/panel/layout/accordion.py\n--- a/panel/layout/accordion.py\n+++ b/panel/layout/accordion.py\n@@ -44,6 +44,7 @@\n \n     def __init__(self, *objects, **params):\n         super().__init__(*objects, **params)\n+        self._updating_active = False\n         self.param.watch(self._update_active, ['active'])\n         self.param.watch(self._update_cards, self._synced_properties)\n \n@@ -82,6 +83,7 @@\n                     header_css_classes=['accordion-header'],\n                     margin=self.margin\n                 )\n+                card.param.watch(self._set_active, ['collapsed'])\n                 self._panels[id(pane)] = card\n             card.param.set_param(**params)\n             if ref in card._models:\n@@ -94,7 +96,6 @@\n                         panel.js_on_change('collapsed', cb)\n                 except RerenderError:\n                     return self._get_objects(model, current_objects[:i], doc, root, comm)\n-            \n             new_models.append(panel)\n         self._update_cards()\n         self._update_active()\n@@ -114,11 +115,32 @@\n             margin = (0, 5, 0, 5)\n         return dict(margin=margin, collapsed = i not in self.active)\n \n+    def _set_active(self, *events):\n+        if self._updating_active:\n+            return\n+        active = []\n+        self._updating_active = True\n+        try:\n+            for i, pane in enumerate(self.objects):\n+                if id(pane) not in self._panels:\n+                    continue\n+                elif not self._panels[id(pane)].collapsed:\n+                    active.append(i)\n+            self.active = active\n+        finally:\n+            self._updating_active = False\n+\n     def _update_active(self, *events):\n-        for i, pane in enumerate(self.objects):\n-            if id(pane) not in self._panels:\n-                continue\n-            self._panels[id(pane)].collapsed = i not in self.active\n+        if self._updating_active:\n+            return\n+        self._updating_active = True\n+        try:\n+            for i, pane in enumerate(self.objects):\n+                if id(pane) not in self._panels:\n+                    continue\n+                self._panels[id(pane)].collapsed = i not in self.active\n+        finally:\n+            self._updating_active = False\n \n     def _update_cards(self, *events):\n         params = {k: v for k, v in self.param.get_param_values()\ndiff --git a/panel/layout/card.py b/panel/layout/card.py\n--- a/panel/layout/card.py\n+++ b/panel/layout/card.py\n@@ -49,6 +49,8 @@\n \n     _bokeh_model = BkCard\n     \n+    _linked_props = ['collapsed']\n+\n     _rename = dict(Column._rename, title=None, header=None, title_css_classes=None)\n \n     def __init__(self, *objects, **params):\n", "issue": "Accordion's active does not work correctly\n#### ALL software version info\r\nPython 3.7.6, panel==0.10.3\r\n\r\n#### Description of expected behavior and the observed behavior\r\n1. I would expect `accordion.active` to return list of active cards. Now it returns an empty list even if some card is open.\r\n2. Also setting values to `accordion.active` I would expect to open only selected cards. Now it opens selected cards, but does not close the ones that were not selected.\r\n\r\n#### Complete, minimal, self-contained example code that reproduces the issue\r\n\r\n```python\r\n# based on https://panel.holoviz.org/reference/layouts/Accordion.html\r\nimport panel as pn\r\npn.extension()\r\n\r\nfrom bokeh.plotting import figure\r\n\r\np1 = figure(width=300, height=80, name='Scatter', margin=5)\r\np1.scatter([0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 2, 1, 0])\r\n\r\np2 = figure(width=300, height=80, name='Line', margin=5)\r\np2.line([0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 2, 1, 0])\r\n\r\naccordion = pn.Accordion(p1, p2)\r\naccordion\r\n\r\n```\r\n\r\n```\r\naccordion.active\r\n```\r\n\r\n```\r\naccordion.active = [0]\r\n```\r\n\r\n#### Screenshots or screencasts of the bug in action\r\n![Peek 2021-02-25 12-42](https://user-images.githubusercontent.com/33317987/109148806-05f1c680-7767-11eb-9487-d8895d4fad4f.gif)\r\n\n", "before_files": [{"content": "import param\n\nfrom ..models import Card as BkCard\nfrom .base import Column, Row, ListPanel\n\n\nclass Card(Column):\n    \"\"\"\n    A Card layout allows arranging multiple panel objects in a\n    collapsible, vertical container with a header bar.\n    \"\"\"\n\n    active_header_background = param.String(doc=\"\"\"\n        A valid CSS color for the header background when not collapsed.\"\"\")\n\n    button_css_classes = param.List(['card-button'], doc=\"\"\"\n        CSS classes to apply to the button element.\"\"\")\n\n    collapsible = param.Boolean(default=True, doc=\"\"\"\n        Whether the Card should be expandable and collapsible.\"\"\")\n\n    collapsed = param.Boolean(default=False, doc=\"\"\"\n        Whether the contents of the Card are collapsed.\"\"\")\n\n    css_classes = param.List(['card'], doc=\"\"\"\n        CSS classes to apply to the overall Card.\"\"\")\n\n    header = param.Parameter(doc=\"\"\"\n        A Panel component to display in the header bar of the Card.\n        Will override the given title if defined.\"\"\")\n\n    header_background = param.String(doc=\"\"\"\n        A valid CSS color for the header background.\"\"\")\n\n    header_color = param.String(doc=\"\"\"\n        A valid CSS color to apply to the header text.\"\"\")\n\n    header_css_classes = param.List(['card-header'], doc=\"\"\"\n        CSS classes to apply to the header element.\"\"\")\n\n    title_css_classes = param.List(['card-title'], doc=\"\"\"\n        CSS classes to apply to the header title.\"\"\")\n\n    margin = param.Parameter(default=5)\n\n    title = param.String(doc=\"\"\"\n        A title to be displayed in the Card header, will be overridden\n        by the header if defined.\"\"\")\n\n    _bokeh_model = BkCard\n    \n    _rename = dict(Column._rename, title=None, header=None, title_css_classes=None)\n\n    def __init__(self, *objects, **params):\n        self._header_layout = Row(css_classes=['card-header-row'],\n                                  sizing_mode='stretch_width')\n        super().__init__(*objects, **params)\n        self.param.watch(self._update_header, ['title', 'header', 'title_css_classes'])\n        self._update_header()\n\n    def _cleanup(self, root):\n        super()._cleanup(root)\n        self._header_layout._cleanup(root)\n\n    def _process_param_change(self, params):\n        scroll = params.pop('scroll', None)\n        css_classes = self.css_classes or []\n        if scroll:\n            params['css_classes'] = css_classes + ['scrollable']\n        elif scroll == False:\n            params['css_classes'] = css_classes\n        return super(ListPanel, self)._process_param_change(params)\n\n    def _update_header(self, *events):\n        from ..pane import HTML, panel\n        if self.header is None:\n            item = HTML('%s' % (self.title or \"&#8203;\"),\n                        css_classes=self.title_css_classes,\n                        sizing_mode='stretch_width',\n                        margin=(2, 5))\n        else:\n            item = panel(self.header)\n        self._header_layout[:] = [item]\n\n    def _get_objects(self, model, old_objects, doc, root, comm=None):\n        ref = root.ref['id']\n        if ref in self._header_layout._models:\n            header = self._header_layout._models[ref][0]\n        else:\n            header = self._header_layout._get_model(doc, root, model, comm)\n        objects = super()._get_objects(model, old_objects, doc, root, comm)\n        return [header]+objects\n", "path": "panel/layout/card.py"}, {"content": "import param\n\nfrom bokeh.models import Column as BkColumn, CustomJS\n\nfrom .base import NamedListPanel\nfrom .card import Card\n\n\nclass Accordion(NamedListPanel):\n    \n    active_header_background = param.String(default='#ccc', doc=\"\"\"\n        Color for currently active headers.\"\"\")\n\n    active = param.List(default=[], doc=\"\"\"\n        List of indexes of active cards.\"\"\")\n\n    header_color = param.String(doc=\"\"\"\n        A valid CSS color to apply to the expand button.\"\"\")\n\n    header_background = param.String(doc=\"\"\"\n        A valid CSS color for the header background.\"\"\")\n\n    toggle = param.Boolean(default=False, doc=\"\"\"\n        Whether to toggle between active cards or allow multiple cards\"\"\")\n\n    _bokeh_model = BkColumn\n    \n    _rename = {'active': None, 'active_header_background': None,\n               'header_background': None, 'objects': 'children',\n               'dynamic': None, 'toggle': None, 'header_color': None}\n\n    _toggle = \"\"\"\n    for (var child of accordion.children) {\n      if ((child.id !== cb_obj.id) && (child.collapsed == cb_obj.collapsed) && !cb_obj.collapsed) {\n        child.collapsed = !cb_obj.collapsed\n      }\n    }\n    \"\"\"\n\n    _synced_properties = [\n        'active_header_background', 'header_background', 'width',\n        'sizing_mode', 'width_policy', 'height_policy', 'header_color'\n    ]\n\n    def __init__(self, *objects, **params):\n        super().__init__(*objects, **params)\n        self.param.watch(self._update_active, ['active'])\n        self.param.watch(self._update_cards, self._synced_properties)\n\n    def _get_objects(self, model, old_objects, doc, root, comm=None):\n        \"\"\"\n        Returns new child models for the layout while reusing unchanged\n        models and cleaning up any dropped objects.\n        \"\"\"\n        from panel.pane.base import RerenderError, panel\n        new_models = []\n        if len(self._names) != len(self):\n            raise ValueError('Accordion names do not match objects, ensure '\n                             'that the Tabs.objects are not modified '\n                             'directly. Found %d names, expected %d.' %\n                             (len(self._names), len(self)))\n        for i, (name, pane) in enumerate(zip(self._names, self)):\n            pane = panel(pane, name=name)\n            self.objects[i] = pane\n\n        for obj in old_objects:\n            if obj not in self.objects:\n                self._panels[id(obj)]._cleanup(root)\n\n        params = {k: v for k, v in self.param.get_param_values()\n                  if k in self._synced_properties}\n\n        ref = root.ref['id']\n        current_objects = list(self)\n        for i, (name, pane) in enumerate(zip(self._names, self)):\n            params.update(self._apply_style(i))\n            if id(pane) in self._panels:\n                card = self._panels[id(pane)]\n            else:\n                card = Card(\n                    pane, title=name, css_classes=['accordion'],\n                    header_css_classes=['accordion-header'],\n                    margin=self.margin\n                )\n                self._panels[id(pane)] = card\n            card.param.set_param(**params)\n            if ref in card._models:\n                panel = card._models[ref][0]\n            else:\n                try:\n                    panel = card._get_model(doc, root, model, comm)\n                    if self.toggle:\n                        cb = CustomJS(args={'accordion': model}, code=self._toggle)\n                        panel.js_on_change('collapsed', cb)\n                except RerenderError:\n                    return self._get_objects(model, current_objects[:i], doc, root, comm)\n            \n            new_models.append(panel)\n        self._update_cards()\n        self._update_active()\n        return new_models\n\n    def _cleanup(self, root):\n        for panel in self._panels.values():\n            panel._cleanup(root)\n        super()._cleanup(root)\n\n    def _apply_style(self, i):\n        if i == 0:\n            margin = (5, 5, 0, 5)\n        elif i == (len(self)-1):\n            margin = (0, 5, 5, 5)\n        else:\n            margin = (0, 5, 0, 5)\n        return dict(margin=margin, collapsed = i not in self.active)\n\n    def _update_active(self, *events):\n        for i, pane in enumerate(self.objects):\n            if id(pane) not in self._panels:\n                continue\n            self._panels[id(pane)].collapsed = i not in self.active\n\n    def _update_cards(self, *events):\n        params = {k: v for k, v in self.param.get_param_values()\n                  if k in self._synced_properties}\n        for panel in self._panels.values():\n            panel.param.set_param(**params)\n", "path": "panel/layout/accordion.py"}], "after_files": [{"content": "import param\n\nfrom ..models import Card as BkCard\nfrom .base import Column, Row, ListPanel\n\n\nclass Card(Column):\n    \"\"\"\n    A Card layout allows arranging multiple panel objects in a\n    collapsible, vertical container with a header bar.\n    \"\"\"\n\n    active_header_background = param.String(doc=\"\"\"\n        A valid CSS color for the header background when not collapsed.\"\"\")\n\n    button_css_classes = param.List(['card-button'], doc=\"\"\"\n        CSS classes to apply to the button element.\"\"\")\n\n    collapsible = param.Boolean(default=True, doc=\"\"\"\n        Whether the Card should be expandable and collapsible.\"\"\")\n\n    collapsed = param.Boolean(default=False, doc=\"\"\"\n        Whether the contents of the Card are collapsed.\"\"\")\n\n    css_classes = param.List(['card'], doc=\"\"\"\n        CSS classes to apply to the overall Card.\"\"\")\n\n    header = param.Parameter(doc=\"\"\"\n        A Panel component to display in the header bar of the Card.\n        Will override the given title if defined.\"\"\")\n\n    header_background = param.String(doc=\"\"\"\n        A valid CSS color for the header background.\"\"\")\n\n    header_color = param.String(doc=\"\"\"\n        A valid CSS color to apply to the header text.\"\"\")\n\n    header_css_classes = param.List(['card-header'], doc=\"\"\"\n        CSS classes to apply to the header element.\"\"\")\n\n    title_css_classes = param.List(['card-title'], doc=\"\"\"\n        CSS classes to apply to the header title.\"\"\")\n\n    margin = param.Parameter(default=5)\n\n    title = param.String(doc=\"\"\"\n        A title to be displayed in the Card header, will be overridden\n        by the header if defined.\"\"\")\n\n    _bokeh_model = BkCard\n    \n    _linked_props = ['collapsed']\n\n    _rename = dict(Column._rename, title=None, header=None, title_css_classes=None)\n\n    def __init__(self, *objects, **params):\n        self._header_layout = Row(css_classes=['card-header-row'],\n                                  sizing_mode='stretch_width')\n        super().__init__(*objects, **params)\n        self.param.watch(self._update_header, ['title', 'header', 'title_css_classes'])\n        self._update_header()\n\n    def _cleanup(self, root):\n        super()._cleanup(root)\n        self._header_layout._cleanup(root)\n\n    def _process_param_change(self, params):\n        scroll = params.pop('scroll', None)\n        css_classes = self.css_classes or []\n        if scroll:\n            params['css_classes'] = css_classes + ['scrollable']\n        elif scroll == False:\n            params['css_classes'] = css_classes\n        return super(ListPanel, self)._process_param_change(params)\n\n    def _update_header(self, *events):\n        from ..pane import HTML, panel\n        if self.header is None:\n            item = HTML('%s' % (self.title or \"&#8203;\"),\n                        css_classes=self.title_css_classes,\n                        sizing_mode='stretch_width',\n                        margin=(2, 5))\n        else:\n            item = panel(self.header)\n        self._header_layout[:] = [item]\n\n    def _get_objects(self, model, old_objects, doc, root, comm=None):\n        ref = root.ref['id']\n        if ref in self._header_layout._models:\n            header = self._header_layout._models[ref][0]\n        else:\n            header = self._header_layout._get_model(doc, root, model, comm)\n        objects = super()._get_objects(model, old_objects, doc, root, comm)\n        return [header]+objects\n", "path": "panel/layout/card.py"}, {"content": "import param\n\nfrom bokeh.models import Column as BkColumn, CustomJS\n\nfrom .base import NamedListPanel\nfrom .card import Card\n\n\nclass Accordion(NamedListPanel):\n    \n    active_header_background = param.String(default='#ccc', doc=\"\"\"\n        Color for currently active headers.\"\"\")\n\n    active = param.List(default=[], doc=\"\"\"\n        List of indexes of active cards.\"\"\")\n\n    header_color = param.String(doc=\"\"\"\n        A valid CSS color to apply to the expand button.\"\"\")\n\n    header_background = param.String(doc=\"\"\"\n        A valid CSS color for the header background.\"\"\")\n\n    toggle = param.Boolean(default=False, doc=\"\"\"\n        Whether to toggle between active cards or allow multiple cards\"\"\")\n\n    _bokeh_model = BkColumn\n    \n    _rename = {'active': None, 'active_header_background': None,\n               'header_background': None, 'objects': 'children',\n               'dynamic': None, 'toggle': None, 'header_color': None}\n\n    _toggle = \"\"\"\n    for (var child of accordion.children) {\n      if ((child.id !== cb_obj.id) && (child.collapsed == cb_obj.collapsed) && !cb_obj.collapsed) {\n        child.collapsed = !cb_obj.collapsed\n      }\n    }\n    \"\"\"\n\n    _synced_properties = [\n        'active_header_background', 'header_background', 'width',\n        'sizing_mode', 'width_policy', 'height_policy', 'header_color'\n    ]\n\n    def __init__(self, *objects, **params):\n        super().__init__(*objects, **params)\n        self._updating_active = False\n        self.param.watch(self._update_active, ['active'])\n        self.param.watch(self._update_cards, self._synced_properties)\n\n    def _get_objects(self, model, old_objects, doc, root, comm=None):\n        \"\"\"\n        Returns new child models for the layout while reusing unchanged\n        models and cleaning up any dropped objects.\n        \"\"\"\n        from panel.pane.base import RerenderError, panel\n        new_models = []\n        if len(self._names) != len(self):\n            raise ValueError('Accordion names do not match objects, ensure '\n                             'that the Tabs.objects are not modified '\n                             'directly. Found %d names, expected %d.' %\n                             (len(self._names), len(self)))\n        for i, (name, pane) in enumerate(zip(self._names, self)):\n            pane = panel(pane, name=name)\n            self.objects[i] = pane\n\n        for obj in old_objects:\n            if obj not in self.objects:\n                self._panels[id(obj)]._cleanup(root)\n\n        params = {k: v for k, v in self.param.get_param_values()\n                  if k in self._synced_properties}\n\n        ref = root.ref['id']\n        current_objects = list(self)\n        for i, (name, pane) in enumerate(zip(self._names, self)):\n            params.update(self._apply_style(i))\n            if id(pane) in self._panels:\n                card = self._panels[id(pane)]\n            else:\n                card = Card(\n                    pane, title=name, css_classes=['accordion'],\n                    header_css_classes=['accordion-header'],\n                    margin=self.margin\n                )\n                card.param.watch(self._set_active, ['collapsed'])\n                self._panels[id(pane)] = card\n            card.param.set_param(**params)\n            if ref in card._models:\n                panel = card._models[ref][0]\n            else:\n                try:\n                    panel = card._get_model(doc, root, model, comm)\n                    if self.toggle:\n                        cb = CustomJS(args={'accordion': model}, code=self._toggle)\n                        panel.js_on_change('collapsed', cb)\n                except RerenderError:\n                    return self._get_objects(model, current_objects[:i], doc, root, comm)\n            new_models.append(panel)\n        self._update_cards()\n        self._update_active()\n        return new_models\n\n    def _cleanup(self, root):\n        for panel in self._panels.values():\n            panel._cleanup(root)\n        super()._cleanup(root)\n\n    def _apply_style(self, i):\n        if i == 0:\n            margin = (5, 5, 0, 5)\n        elif i == (len(self)-1):\n            margin = (0, 5, 5, 5)\n        else:\n            margin = (0, 5, 0, 5)\n        return dict(margin=margin, collapsed = i not in self.active)\n\n    def _set_active(self, *events):\n        if self._updating_active:\n            return\n        active = []\n        self._updating_active = True\n        try:\n            for i, pane in enumerate(self.objects):\n                if id(pane) not in self._panels:\n                    continue\n                elif not self._panels[id(pane)].collapsed:\n                    active.append(i)\n            self.active = active\n        finally:\n            self._updating_active = False\n\n    def _update_active(self, *events):\n        if self._updating_active:\n            return\n        self._updating_active = True\n        try:\n            for i, pane in enumerate(self.objects):\n                if id(pane) not in self._panels:\n                    continue\n                self._panels[id(pane)].collapsed = i not in self.active\n        finally:\n            self._updating_active = False\n\n    def _update_cards(self, *events):\n        params = {k: v for k, v in self.param.get_param_values()\n                  if k in self._synced_properties}\n        for panel in self._panels.values():\n            panel.param.set_param(**params)\n", "path": "panel/layout/accordion.py"}]}