GUI -- Adjusted height of tables in tabular views, added new and removed columns…
… in Device View. Removed rounded bottom corners of tabular views, created table.css instead of using common.css Change-Id: I77ff4c3abe051e1e4e566eb805e4b4a695f011ba
Showing
6 changed files
with
161 additions
and
97 deletions
| ... | @@ -20,12 +20,18 @@ import com.fasterxml.jackson.databind.node.ObjectNode; | ... | @@ -20,12 +20,18 @@ import com.fasterxml.jackson.databind.node.ObjectNode; |
| 20 | import com.google.common.collect.ImmutableSet; | 20 | import com.google.common.collect.ImmutableSet; |
| 21 | import org.onosproject.mastership.MastershipService; | 21 | import org.onosproject.mastership.MastershipService; |
| 22 | import org.onosproject.net.Device; | 22 | import org.onosproject.net.Device; |
| 23 | +import org.onosproject.net.DeviceId; | ||
| 24 | +import org.onosproject.net.Port; | ||
| 23 | import org.onosproject.net.device.DeviceService; | 25 | import org.onosproject.net.device.DeviceService; |
| 26 | +import org.onosproject.net.link.LinkService; | ||
| 24 | 27 | ||
| 25 | import java.util.ArrayList; | 28 | import java.util.ArrayList; |
| 26 | import java.util.Arrays; | 29 | import java.util.Arrays; |
| 27 | import java.util.List; | 30 | import java.util.List; |
| 28 | 31 | ||
| 32 | +//import org.onosproject.net.Link; | ||
| 33 | +//import java.util.Set; | ||
| 34 | + | ||
| 29 | /** | 35 | /** |
| 30 | * Message handler for device view related messages. | 36 | * Message handler for device view related messages. |
| 31 | */ | 37 | */ |
| ... | @@ -46,7 +52,10 @@ public class DeviceViewMessageHandler extends AbstractTabularViewMessageHandler | ... | @@ -46,7 +52,10 @@ public class DeviceViewMessageHandler extends AbstractTabularViewMessageHandler |
| 46 | 52 | ||
| 47 | DeviceService service = get(DeviceService.class); | 53 | DeviceService service = get(DeviceService.class); |
| 48 | MastershipService mastershipService = get(MastershipService.class); | 54 | MastershipService mastershipService = get(MastershipService.class); |
| 49 | - TableRow[] rows = generateTableRows(service, mastershipService); | 55 | + LinkService linkService = get(LinkService.class); |
| 56 | + TableRow[] rows = generateTableRows(service, | ||
| 57 | + mastershipService, | ||
| 58 | + linkService); | ||
| 50 | RowComparator rc = | 59 | RowComparator rc = |
| 51 | new RowComparator(sortCol, RowComparator.direction(sortDir)); | 60 | new RowComparator(sortCol, RowComparator.direction(sortDir)); |
| 52 | Arrays.sort(rows, rc); | 61 | Arrays.sort(rows, rc); |
| ... | @@ -58,10 +67,14 @@ public class DeviceViewMessageHandler extends AbstractTabularViewMessageHandler | ... | @@ -58,10 +67,14 @@ public class DeviceViewMessageHandler extends AbstractTabularViewMessageHandler |
| 58 | } | 67 | } |
| 59 | 68 | ||
| 60 | private TableRow[] generateTableRows(DeviceService service, | 69 | private TableRow[] generateTableRows(DeviceService service, |
| 61 | - MastershipService mastershipService) { | 70 | + MastershipService mastershipService, |
| 71 | + LinkService linkService) { | ||
| 62 | List<TableRow> list = new ArrayList<>(); | 72 | List<TableRow> list = new ArrayList<>(); |
| 63 | for (Device dev : service.getDevices()) { | 73 | for (Device dev : service.getDevices()) { |
| 64 | - list.add(new DeviceTableRow(service, mastershipService, dev)); | 74 | + list.add(new DeviceTableRow(service, |
| 75 | + mastershipService, | ||
| 76 | + linkService, | ||
| 77 | + dev)); | ||
| 65 | } | 78 | } |
| 66 | return list.toArray(new TableRow[list.size()]); | 79 | return list.toArray(new TableRow[list.size()]); |
| 67 | } | 80 | } |
| ... | @@ -76,40 +89,70 @@ public class DeviceViewMessageHandler extends AbstractTabularViewMessageHandler | ... | @@ -76,40 +89,70 @@ public class DeviceViewMessageHandler extends AbstractTabularViewMessageHandler |
| 76 | private static final String AVAILABLE_IID = "_iconid_available"; | 89 | private static final String AVAILABLE_IID = "_iconid_available"; |
| 77 | private static final String TYPE_IID = "_iconid_type"; | 90 | private static final String TYPE_IID = "_iconid_type"; |
| 78 | private static final String DEV_ICON_PREFIX = "devIcon_"; | 91 | private static final String DEV_ICON_PREFIX = "devIcon_"; |
| 79 | - private static final String ROLE = "role"; | 92 | + private static final String NUM_PORTS = "num_ports"; |
| 93 | + private static final String NUM_EGRESS_LINKS = "num_elinks"; | ||
| 80 | private static final String MFR = "mfr"; | 94 | private static final String MFR = "mfr"; |
| 81 | private static final String HW = "hw"; | 95 | private static final String HW = "hw"; |
| 82 | private static final String SW = "sw"; | 96 | private static final String SW = "sw"; |
| 83 | - private static final String SERIAL = "serial"; | ||
| 84 | private static final String PROTOCOL = "protocol"; | 97 | private static final String PROTOCOL = "protocol"; |
| 85 | - private static final String CHASSISID = "chassisid"; | ||
| 86 | private static final String MASTERID = "masterid"; | 98 | private static final String MASTERID = "masterid"; |
| 99 | + private static final String CHASSISID = "chassisid"; | ||
| 100 | + private static final String SERIAL = "serial"; | ||
| 87 | 101 | ||
| 88 | private static final String[] COL_IDS = { | 102 | private static final String[] COL_IDS = { |
| 89 | - ID, AVAILABLE, AVAILABLE_IID, TYPE_IID, ROLE, | 103 | + AVAILABLE, AVAILABLE_IID, TYPE_IID, ID, |
| 90 | - MFR, HW, SW, SERIAL, PROTOCOL, CHASSISID, MASTERID | 104 | + NUM_PORTS, NUM_EGRESS_LINKS, MASTERID, MFR, HW, SW, |
| 105 | + PROTOCOL, CHASSISID, SERIAL | ||
| 91 | }; | 106 | }; |
| 92 | 107 | ||
| 93 | private static final String ICON_ID_ONLINE = "deviceOnline"; | 108 | private static final String ICON_ID_ONLINE = "deviceOnline"; |
| 94 | private static final String ICON_ID_OFFLINE = "deviceOffline"; | 109 | private static final String ICON_ID_OFFLINE = "deviceOffline"; |
| 95 | 110 | ||
| 111 | + // TODO: use in details pane | ||
| 112 | +// private String getPorts(List<Port> ports) { | ||
| 113 | +// String formattedString = ""; | ||
| 114 | +// int numPorts = 0; | ||
| 115 | +// | ||
| 116 | +// for (Port p : ports) { | ||
| 117 | +// numPorts++; | ||
| 118 | +// formattedString += p.number().toString() + ", "; | ||
| 119 | +// } | ||
| 120 | +// return formattedString + "Total: " + numPorts; | ||
| 121 | +// } | ||
| 122 | + | ||
| 123 | + // TODO: use in details pane | ||
| 124 | +// private String getEgressLinks(Set<Link> links) { | ||
| 125 | +// String formattedString = ""; | ||
| 126 | +// | ||
| 127 | +// for (Link l : links) { | ||
| 128 | +// formattedString += l.dst().port().toString() + ", "; | ||
| 129 | +// } | ||
| 130 | +// return formattedString; | ||
| 131 | +// } | ||
| 132 | + | ||
| 133 | + // TODO: include "extra" backend information in device details pane | ||
| 96 | public DeviceTableRow(DeviceService service, | 134 | public DeviceTableRow(DeviceService service, |
| 97 | MastershipService ms, | 135 | MastershipService ms, |
| 136 | + LinkService ls, | ||
| 98 | Device d) { | 137 | Device d) { |
| 99 | boolean available = service.isAvailable(d.id()); | 138 | boolean available = service.isAvailable(d.id()); |
| 100 | String iconId = available ? ICON_ID_ONLINE : ICON_ID_OFFLINE; | 139 | String iconId = available ? ICON_ID_ONLINE : ICON_ID_OFFLINE; |
| 140 | + DeviceId id = d.id(); | ||
| 141 | + List<Port> ports = service.getPorts(id); | ||
| 142 | +// Set<Link> links = ls.getDeviceEgressLinks(id); | ||
| 101 | 143 | ||
| 102 | - add(ID, d.id().toString()); | 144 | + add(ID, id.toString()); |
| 103 | add(AVAILABLE, Boolean.toString(available)); | 145 | add(AVAILABLE, Boolean.toString(available)); |
| 104 | add(AVAILABLE_IID, iconId); | 146 | add(AVAILABLE_IID, iconId); |
| 105 | add(TYPE_IID, getTypeIconId(d)); | 147 | add(TYPE_IID, getTypeIconId(d)); |
| 106 | - add(ROLE, service.getRole(d.id()).toString()); | ||
| 107 | add(MFR, d.manufacturer()); | 148 | add(MFR, d.manufacturer()); |
| 108 | add(HW, d.hwVersion()); | 149 | add(HW, d.hwVersion()); |
| 109 | add(SW, d.swVersion()); | 150 | add(SW, d.swVersion()); |
| 110 | - add(SERIAL, d.serialNumber()); | 151 | +// add(SERIAL, d.serialNumber()); |
| 111 | add(PROTOCOL, d.annotations().value(PROTOCOL)); | 152 | add(PROTOCOL, d.annotations().value(PROTOCOL)); |
| 112 | - add(CHASSISID, d.chassisId().toString()); | 153 | + add(NUM_PORTS, Integer.toString(ports.size())); |
| 154 | +// add(NUM_EGRESS_LINKS, Integer.toString(links.size())); | ||
| 155 | +// add(CHASSISID, d.chassisId().toString()); | ||
| 113 | add(MASTERID, ms.getMasterFor(d.id()).toString()); | 156 | add(MASTERID, ms.getMasterFor(d.id()).toString()); |
| 114 | } | 157 | } |
| 115 | 158 | ... | ... |
| ... | @@ -18,75 +18,3 @@ | ... | @@ -18,75 +18,3 @@ |
| 18 | ONOS GUI -- common -- CSS file | 18 | ONOS GUI -- common -- CSS file |
| 19 | */ | 19 | */ |
| 20 | 20 | ||
| 21 | -/* ------ for summary-list tables ------ */ | ||
| 22 | - | ||
| 23 | -table.summary-list { | ||
| 24 | - margin: 0 20px 16px 12px; | ||
| 25 | - font-size: 10pt; | ||
| 26 | - border-spacing: 0; | ||
| 27 | -} | ||
| 28 | - | ||
| 29 | -table.summary-list tbody { | ||
| 30 | - border-radius: 0 0 8px 8px; | ||
| 31 | -} | ||
| 32 | - | ||
| 33 | -table.summary-list td.nodata { | ||
| 34 | - text-align: center; | ||
| 35 | - font-style: italic; | ||
| 36 | -} | ||
| 37 | - | ||
| 38 | -.light table.summary-list tr:nth-child(even) { | ||
| 39 | - background-color: #ddd; | ||
| 40 | -} | ||
| 41 | -.light table.summary-list tr:nth-child(odd) { | ||
| 42 | - background-color: #eee; | ||
| 43 | -} | ||
| 44 | -.dark table.summary-list tr:nth-child(even) { | ||
| 45 | - background-color: #333; | ||
| 46 | -} | ||
| 47 | -.dark table.summary-list tr:nth-child(odd) { | ||
| 48 | - background-color: #444; | ||
| 49 | -} | ||
| 50 | - | ||
| 51 | -.light table.summary-list tr.selected { | ||
| 52 | - background-color: deepskyblue; | ||
| 53 | -} | ||
| 54 | - | ||
| 55 | -.dark table.summary-list tr.selected { | ||
| 56 | - background-color: #304860; | ||
| 57 | -} | ||
| 58 | - | ||
| 59 | -table.summary-list td,th { | ||
| 60 | - padding: 6px 6px 6px 6px; | ||
| 61 | - text-align: left; | ||
| 62 | -} | ||
| 63 | - | ||
| 64 | -table.summary-list th { | ||
| 65 | - letter-spacing: 0.02em; | ||
| 66 | - cursor: pointer; | ||
| 67 | -} | ||
| 68 | -table.summary-list th:first-child { | ||
| 69 | - border-radius: 8px 0 0 0; | ||
| 70 | -} | ||
| 71 | -table.summary-list th:last-child { | ||
| 72 | - border-radius: 0 8px 0 0; | ||
| 73 | -} | ||
| 74 | - | ||
| 75 | -.light table.summary-list th { | ||
| 76 | - background-color: #bbb; | ||
| 77 | -} | ||
| 78 | -.dark table.summary-list th { | ||
| 79 | - background-color: #222; | ||
| 80 | - color: #ccc; | ||
| 81 | -} | ||
| 82 | - | ||
| 83 | -/* rows are selectable */ | ||
| 84 | -table.summary-list td { | ||
| 85 | - cursor: pointer; | ||
| 86 | -} | ||
| 87 | - | ||
| 88 | -.dark table.summary-list td { | ||
| 89 | - color: #ccc; | ||
| 90 | -} | ||
| 91 | - | ||
| 92 | -/* ------------------------------------ */ | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2015 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +/* ------ for summary-list tables ------ */ | ||
| 18 | + | ||
| 19 | +table.summary-list { | ||
| 20 | + margin: 0 20px 16px 12px; | ||
| 21 | + font-size: 10pt; | ||
| 22 | + border-spacing: 0; | ||
| 23 | +} | ||
| 24 | + | ||
| 25 | +table.summary-list td.nodata { | ||
| 26 | + text-align: center; | ||
| 27 | + font-style: italic; | ||
| 28 | +} | ||
| 29 | + | ||
| 30 | +.light table.summary-list tr:nth-child(even) { | ||
| 31 | + background-color: #ddd; | ||
| 32 | +} | ||
| 33 | +.light table.summary-list tr:nth-child(odd) { | ||
| 34 | + background-color: #eee; | ||
| 35 | +} | ||
| 36 | +.dark table.summary-list tr:nth-child(even) { | ||
| 37 | + background-color: #333; | ||
| 38 | +} | ||
| 39 | +.dark table.summary-list tr:nth-child(odd) { | ||
| 40 | + background-color: #444; | ||
| 41 | +} | ||
| 42 | + | ||
| 43 | +.light table.summary-list tr.selected { | ||
| 44 | + background-color: deepskyblue; | ||
| 45 | +} | ||
| 46 | + | ||
| 47 | +.dark table.summary-list tr.selected { | ||
| 48 | + background-color: #304860; | ||
| 49 | +} | ||
| 50 | + | ||
| 51 | +table.summary-list td, | ||
| 52 | +table.summary-list th { | ||
| 53 | + padding: 6px; | ||
| 54 | + text-align: left; | ||
| 55 | +} | ||
| 56 | + | ||
| 57 | +table.summary-list th { | ||
| 58 | + letter-spacing: 0.02em; | ||
| 59 | + cursor: pointer; | ||
| 60 | +} | ||
| 61 | +table.summary-list th:first-child { | ||
| 62 | + border-radius: 8px 0 0 0; | ||
| 63 | +} | ||
| 64 | +table.summary-list th:last-child { | ||
| 65 | + border-radius: 0 8px 0 0; | ||
| 66 | +} | ||
| 67 | + | ||
| 68 | +.light table.summary-list th { | ||
| 69 | + background-color: #bbb; | ||
| 70 | +} | ||
| 71 | +.dark table.summary-list th { | ||
| 72 | + background-color: #222; | ||
| 73 | + color: #ccc; | ||
| 74 | +} | ||
| 75 | + | ||
| 76 | +/* rows are selectable */ | ||
| 77 | +table.summary-list td { | ||
| 78 | + cursor: pointer; | ||
| 79 | +} | ||
| 80 | + | ||
| 81 | +.dark table.summary-list td { | ||
| 82 | + color: #ccc; | ||
| 83 | +} |
| ... | @@ -21,11 +21,14 @@ | ... | @@ -21,11 +21,14 @@ |
| 21 | 'use strict'; | 21 | 'use strict'; |
| 22 | 22 | ||
| 23 | // injected refs | 23 | // injected refs |
| 24 | - var $log, $window, fs, is; | 24 | + var $log, $window, fs, mast, is; |
| 25 | 25 | ||
| 26 | // constants | 26 | // constants |
| 27 | var tableIconTdSize = 33, | 27 | var tableIconTdSize = 33, |
| 28 | - bottomMargin = 200, | 28 | + mastPdg = 8, |
| 29 | + h2Pdg = 40, | ||
| 30 | + thPdg = 12, | ||
| 31 | + tbodyPdg = 5, | ||
| 29 | colWidth = 'col-width', | 32 | colWidth = 'col-width', |
| 30 | tableIcon = 'table-icon'; | 33 | tableIcon = 'table-icon'; |
| 31 | 34 | ||
| ... | @@ -49,7 +52,8 @@ | ... | @@ -49,7 +52,8 @@ |
| 49 | // - icon width, | 52 | // - icon width, |
| 50 | // - and default width | 53 | // - and default width |
| 51 | // assumes assigned width is not given to icons | 54 | // assumes assigned width is not given to icons |
| 52 | - // returns the width of all columns that are not icons have an assigned width | 55 | + // returns the width of all columns that are not icons |
| 56 | + // or have an assigned width | ||
| 53 | function getDefaultWidth(headers) { | 57 | function getDefaultWidth(headers) { |
| 54 | var winWidth = fs.windowSize().width, | 58 | var winWidth = fs.windowSize().width, |
| 55 | iconCols = 0, | 59 | iconCols = 0, |
| ... | @@ -92,12 +96,17 @@ | ... | @@ -92,12 +96,17 @@ |
| 92 | }); | 96 | }); |
| 93 | } | 97 | } |
| 94 | 98 | ||
| 99 | + // get the size of the window and then subtract the extra space at the top | ||
| 100 | + // to get the height of the table | ||
| 95 | function setTableHeight(thead, tbody) { | 101 | function setTableHeight(thead, tbody) { |
| 96 | - var winHeight = fs.windowSize().height; | 102 | + var titleHeight = h2Pdg + fs.noPxStyle(d3.select('h2'), 'height'), |
| 103 | + thHeight = thPdg + fs.noPxStyle(d3.select('th'), 'height'), | ||
| 104 | + totalHeight = titleHeight + thHeight + tbodyPdg + mastPdg, | ||
| 105 | + tableHeight = fs.windowSize(mast.mastHeight() + totalHeight).height; | ||
| 97 | 106 | ||
| 98 | thead.style('display', 'block'); | 107 | thead.style('display', 'block'); |
| 99 | tbody.style({'display': 'block', | 108 | tbody.style({'display': 'block', |
| 100 | - 'height': ((winHeight - bottomMargin) + 'px'), | 109 | + 'height': (tableHeight + 'px'), |
| 101 | 'overflow': 'auto' | 110 | 'overflow': 'auto' |
| 102 | }); | 111 | }); |
| 103 | } | 112 | } |
| ... | @@ -150,11 +159,13 @@ | ... | @@ -150,11 +159,13 @@ |
| 150 | } | 159 | } |
| 151 | 160 | ||
| 152 | angular.module('onosWidget') | 161 | angular.module('onosWidget') |
| 153 | - .directive('onosFixedHeader', ['$window', 'FnService', | 162 | + .directive('onosFixedHeader', ['$window', 'FnService', 'MastService', |
| 154 | - function (_$window_, _fs_) { | 163 | + function (_$window_, _fs_, _mast_) { |
| 155 | return function (scope, element) { | 164 | return function (scope, element) { |
| 156 | $window = _$window_; | 165 | $window = _$window_; |
| 157 | fs = _fs_; | 166 | fs = _fs_; |
| 167 | + mast = _mast_; | ||
| 168 | + | ||
| 158 | var w = angular.element($window), | 169 | var w = angular.element($window), |
| 159 | table = d3.select(element[0]), | 170 | table = d3.select(element[0]), |
| 160 | thead = table.select('thead'), | 171 | thead = table.select('thead'), | ... | ... |
| ... | @@ -10,13 +10,12 @@ | ... | @@ -10,13 +10,12 @@ |
| 10 | <th colId="available" class="table-icon" sortable></th> | 10 | <th colId="available" class="table-icon" sortable></th> |
| 11 | <th colId="type" class="table-icon" sortable></th> | 11 | <th colId="type" class="table-icon" sortable></th> |
| 12 | <th colId="id" sortable>Device ID </th> | 12 | <th colId="id" sortable>Device ID </th> |
| 13 | + <th colId="masterid" sortable>Master Instance </th> | ||
| 14 | + <th colId="num_ports" sortable>Ports </th> | ||
| 13 | <th colId="mfr" sortable>Vendor </th> | 15 | <th colId="mfr" sortable>Vendor </th> |
| 14 | <th colId="hw" sortable>H/W Version </th> | 16 | <th colId="hw" sortable>H/W Version </th> |
| 15 | <th colId="sw" sortable>S/W Version </th> | 17 | <th colId="sw" sortable>S/W Version </th> |
| 16 | - <th colId="chassisid" sortable>Chassis ID </th> | ||
| 17 | - <th colId="serial" sortable>Serial # </th> | ||
| 18 | <th colId="protocol" sortable>Protocol </th> | 18 | <th colId="protocol" sortable>Protocol </th> |
| 19 | - <th colId="masterid" sortable>Master Instance </th> | ||
| 20 | </tr> | 19 | </tr> |
| 21 | </thead> | 20 | </thead> |
| 22 | 21 | ||
| ... | @@ -36,13 +35,12 @@ | ... | @@ -36,13 +35,12 @@ |
| 36 | <div icon icon-id="{{dev._iconid_type}}"></div> | 35 | <div icon icon-id="{{dev._iconid_type}}"></div> |
| 37 | </td> | 36 | </td> |
| 38 | <td>{{dev.id}}</td> | 37 | <td>{{dev.id}}</td> |
| 38 | + <td>{{dev.masterid}}</td> | ||
| 39 | + <td>{{dev.num_ports}}</td> | ||
| 39 | <td>{{dev.mfr}}</td> | 40 | <td>{{dev.mfr}}</td> |
| 40 | <td>{{dev.hw}}</td> | 41 | <td>{{dev.hw}}</td> |
| 41 | <td>{{dev.sw}}</td> | 42 | <td>{{dev.sw}}</td> |
| 42 | - <td>{{dev.chassisid}}</td> | ||
| 43 | - <td>{{dev.serial}}</td> | ||
| 44 | <td>{{dev.protocol}}</td> | 43 | <td>{{dev.protocol}}</td> |
| 45 | - <td>{{dev.masterid}}</td> | ||
| 46 | </tr> | 44 | </tr> |
| 47 | </tbody> | 45 | </tbody> |
| 48 | </table> | 46 | </table> | ... | ... |
| ... | @@ -90,6 +90,7 @@ | ... | @@ -90,6 +90,7 @@ |
| 90 | <link rel="stylesheet" href="app/fw/widget/button.css"> | 90 | <link rel="stylesheet" href="app/fw/widget/button.css"> |
| 91 | <link rel="stylesheet" href="app/fw/widget/toolbar.css"> | 91 | <link rel="stylesheet" href="app/fw/widget/toolbar.css"> |
| 92 | <link rel="stylesheet" href="app/fw/widget/tooltip.css"> | 92 | <link rel="stylesheet" href="app/fw/widget/tooltip.css"> |
| 93 | + <link rel="stylesheet" href="app/fw/widget/table.css"> | ||
| 93 | 94 | ||
| 94 | <!-- This is where contributed javascript will get injected --> | 95 | <!-- This is where contributed javascript will get injected --> |
| 95 | <!-- {INJECTED-JAVASCRIPT-START} --> | 96 | <!-- {INJECTED-JAVASCRIPT-START} --> | ... | ... |
-
Please register or login to post a comment