Merge pull request #82 from dr-dolomite/QuecManager
Added fixes and improvements
This commit is contained in:
@@ -302,7 +302,7 @@
|
|||||||
<div id="loading-content" style="display: none">
|
<div id="loading-content" style="display: none">
|
||||||
<div class="custom-loader"></div>
|
<div class="custom-loader"></div>
|
||||||
<div class="countdown-text">
|
<div class="countdown-text">
|
||||||
Rebooting... <span id="countdown">80</span>s
|
Rebooting... <span id="countdown">90</span>s
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons" id="modal-buttons">
|
<div class="buttons" id="modal-buttons">
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
<script defer src="/js/auth/auth.js"></script>
|
<script defer src="/js/auth/auth.js"></script>
|
||||||
<script src="/js/advance/at-terminal.js"></script>
|
<script src="/js/advance/at-terminal.js"></script>
|
||||||
<script src="/js/advance/ttl-control.js"></script>
|
<script src="/js/advance/ttl-control.js"></script>
|
||||||
<script src="/js/advance/fetch-current.settings.js"></script>
|
<script src="/js/advance/fetch-current-settings.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
(function () {
|
(function () {
|
||||||
@@ -513,7 +513,7 @@
|
|||||||
<div id="loading-content" style="display: none">
|
<div id="loading-content" style="display: none">
|
||||||
<div class="custom-loader"></div>
|
<div class="custom-loader"></div>
|
||||||
<div class="countdown-text">
|
<div class="countdown-text">
|
||||||
Rebooting... <span id="countdown">80</span>s
|
Rebooting... <span id="countdown">90</span>s
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons" id="modal-buttons">
|
<div class="buttons" id="modal-buttons">
|
||||||
|
|||||||
@@ -325,7 +325,7 @@
|
|||||||
<div id="loading-content" style="display: none">
|
<div id="loading-content" style="display: none">
|
||||||
<div class="custom-loader"></div>
|
<div class="custom-loader"></div>
|
||||||
<div class="countdown-text">
|
<div class="countdown-text">
|
||||||
Rebooting... <span id="countdown">80</span>s
|
Rebooting... <span id="countdown">90</span>s
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons" id="modal-buttons">
|
<div class="buttons" id="modal-buttons">
|
||||||
|
|||||||
@@ -89,7 +89,10 @@
|
|||||||
<div class="navbar-item">
|
<div class="navbar-item">
|
||||||
<div class="buttons is-flex-direction-column-mobile">
|
<div class="buttons is-flex-direction-column-mobile">
|
||||||
<div class="control is-expanded-mobile">
|
<div class="control is-expanded-mobile">
|
||||||
<div id="restartConnectionBtn" class="button is-link is-outlined is-fullwidth-mobile">
|
<div
|
||||||
|
id="restartConnectionBtn"
|
||||||
|
class="button is-link is-outlined is-fullwidth-mobile"
|
||||||
|
>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<i class="fas fa-arrows-rotate"></i>
|
<i class="fas fa-arrows-rotate"></i>
|
||||||
</span>
|
</span>
|
||||||
@@ -136,224 +139,222 @@
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="column-margin">
|
<div class="column-margin">
|
||||||
<div class="fixed-grid has-2-cols has-1-cols-mobile">
|
<div class="columns">
|
||||||
<div class="grid is-gap-5">
|
<div class="column">
|
||||||
<div class="cell">
|
<div class="card">
|
||||||
<div class="card">
|
<div class="card-header">
|
||||||
<div class="card-header">
|
<div class="card-header-title">4G LTE Cell Locking</div>
|
||||||
<div class="card-header-title">4G LTE Cell Locking</div>
|
</div>
|
||||||
</div>
|
<div class="card-content">
|
||||||
<div class="card-content">
|
<div class="fixed-grid has-2-cols">
|
||||||
<div class="fixed-grid has-2-cols">
|
<div class="grid">
|
||||||
<div class="grid">
|
<!-- Entry 1 Start -->
|
||||||
<!-- Entry 1 Start -->
|
<div class="cell">
|
||||||
<div class="cell">
|
<div class="field">
|
||||||
<div class="field">
|
<label class="label">EARFCN 1</label>
|
||||||
<label class="label">EARFCN 1</label>
|
<div class="control has-icons-left">
|
||||||
<div class="control has-icons-left">
|
<input
|
||||||
<input
|
class="input"
|
||||||
class="input"
|
type="email"
|
||||||
type="email"
|
placeholder="EARFCN"
|
||||||
placeholder="EARFCN"
|
/>
|
||||||
/>
|
<span class="icon is-left">
|
||||||
<span class="icon is-left">
|
<i class="fas fa-bolt"></i>
|
||||||
<i class="fas fa-bolt"></i>
|
</span>
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="cell">
|
|
||||||
<div class="field">
|
|
||||||
<label class="label">PCI 1</label>
|
|
||||||
<div class="control has-icons-left">
|
|
||||||
<input class="input" type="email" placeholder="PCI" />
|
|
||||||
<span class="icon is-left">
|
|
||||||
<i class="fa-solid fa-signal"></i>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- Entry 1 End -->
|
|
||||||
|
|
||||||
<!-- Entry 2 Start -->
|
|
||||||
<div class="cell">
|
|
||||||
<div class="field">
|
|
||||||
<label class="label">EARFCN 2</label>
|
|
||||||
<div class="control has-icons-left">
|
|
||||||
<input
|
|
||||||
class="input"
|
|
||||||
type="email"
|
|
||||||
placeholder="EARFCN"
|
|
||||||
/>
|
|
||||||
<span class="icon is-left">
|
|
||||||
<i class="fas fa-bolt"></i>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="cell">
|
|
||||||
<div class="field">
|
|
||||||
<label class="label">PCI 2</label>
|
|
||||||
<div class="control has-icons-left">
|
|
||||||
<input class="input" type="email" placeholder="PCI" />
|
|
||||||
<span class="icon is-left">
|
|
||||||
<i class="fa-solid fa-signal"></i>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- Entry 2 End -->
|
|
||||||
|
|
||||||
<!-- Entry 3 Start -->
|
|
||||||
<div class="cell">
|
|
||||||
<div class="field">
|
|
||||||
<label class="label">EARFCN 3</label>
|
|
||||||
<div class="control has-icons-left">
|
|
||||||
<input
|
|
||||||
class="input"
|
|
||||||
type="email"
|
|
||||||
placeholder="EARFCN"
|
|
||||||
/>
|
|
||||||
<span class="icon is-left">
|
|
||||||
<i class="fas fa-bolt"></i>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="cell">
|
|
||||||
<div class="field">
|
|
||||||
<label class="label">PCI 3</label>
|
|
||||||
<div class="control has-icons-left">
|
|
||||||
<input class="input" type="email" placeholder="PCI" />
|
|
||||||
<span class="icon is-left">
|
|
||||||
<i class="fa-solid fa-signal"></i>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- Entry 3 End -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-footer">
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
|
|
||||||
>
|
|
||||||
Lock LTE Cells
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a
|
<div class="cell">
|
||||||
href="#"
|
<div class="field">
|
||||||
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
|
<label class="label">PCI 1</label>
|
||||||
>
|
<div class="control has-icons-left">
|
||||||
Reset
|
<input class="input" type="email" placeholder="PCI" />
|
||||||
</a>
|
<span class="icon is-left">
|
||||||
|
<i class="fa-solid fa-signal"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Entry 1 End -->
|
||||||
|
|
||||||
|
<!-- Entry 2 Start -->
|
||||||
|
<div class="cell">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">EARFCN 2</label>
|
||||||
|
<div class="control has-icons-left">
|
||||||
|
<input
|
||||||
|
class="input"
|
||||||
|
type="email"
|
||||||
|
placeholder="EARFCN"
|
||||||
|
/>
|
||||||
|
<span class="icon is-left">
|
||||||
|
<i class="fas fa-bolt"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cell">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">PCI 2</label>
|
||||||
|
<div class="control has-icons-left">
|
||||||
|
<input class="input" type="email" placeholder="PCI" />
|
||||||
|
<span class="icon is-left">
|
||||||
|
<i class="fa-solid fa-signal"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Entry 2 End -->
|
||||||
|
|
||||||
|
<!-- Entry 3 Start -->
|
||||||
|
<div class="cell">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">EARFCN 3</label>
|
||||||
|
<div class="control has-icons-left">
|
||||||
|
<input
|
||||||
|
class="input"
|
||||||
|
type="email"
|
||||||
|
placeholder="EARFCN"
|
||||||
|
/>
|
||||||
|
<span class="icon is-left">
|
||||||
|
<i class="fas fa-bolt"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cell">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">PCI 3</label>
|
||||||
|
<div class="control has-icons-left">
|
||||||
|
<input class="input" type="email" placeholder="PCI" />
|
||||||
|
<span class="icon is-left">
|
||||||
|
<i class="fa-solid fa-signal"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Entry 3 End -->
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
|
||||||
|
>
|
||||||
|
Lock LTE Cells
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
|
||||||
|
>
|
||||||
|
Reset
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="cell">
|
<div class="column">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<div class="card-header-title">5G-NR SA Cell Locking</div>
|
<div class="card-header-title">5G-NR SA Cell Locking</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<div class="fixed-grid has-2-cols">
|
<div class="fixed-grid has-2-cols">
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<!-- Entry 1 Start -->
|
<!-- Entry 1 Start -->
|
||||||
<div class="cell">
|
<div class="cell">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">NR ARFCN</label>
|
<label class="label">NR ARFCN</label>
|
||||||
<div class="control has-icons-left">
|
<div class="control has-icons-left">
|
||||||
<input
|
<input
|
||||||
class="input"
|
class="input"
|
||||||
type="email"
|
type="email"
|
||||||
placeholder="NR-ARFCN"
|
placeholder="NR-ARFCN"
|
||||||
/>
|
/>
|
||||||
<span class="icon is-left">
|
<span class="icon is-left">
|
||||||
<i class="fas fa-bolt"></i>
|
<i class="fas fa-bolt"></i>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="cell">
|
|
||||||
<div class="field">
|
|
||||||
<label class="label">NR PCI</label>
|
|
||||||
<div class="control has-icons-left">
|
|
||||||
<input
|
|
||||||
class="input"
|
|
||||||
type="email"
|
|
||||||
placeholder="NR PCI"
|
|
||||||
/>
|
|
||||||
<span class="icon is-left">
|
|
||||||
<i class="fa-solid fa-signal"></i>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- Entry 1 End -->
|
|
||||||
|
|
||||||
<!-- Entry 2 Start -->
|
|
||||||
<div class="cell">
|
|
||||||
<div class="field">
|
|
||||||
<label class="label">SCS</label>
|
|
||||||
<div class="control has-icons-left">
|
|
||||||
<span class="select">
|
|
||||||
<select>
|
|
||||||
<option selected>Select SCS</option>
|
|
||||||
<option>15 kHz</option>
|
|
||||||
<option>30 kHz</option>
|
|
||||||
<option>60 kHz</option>
|
|
||||||
<option>120 kHz</option>
|
|
||||||
<option>240 kHz</option>
|
|
||||||
</select>
|
|
||||||
</span>
|
|
||||||
<span class="icon is-left">
|
|
||||||
<i class="fas fa-bolt"></i>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="cell">
|
|
||||||
<div class="field">
|
|
||||||
<label class="label">NR Band</label>
|
|
||||||
<div class="control has-icons-left">
|
|
||||||
<input
|
|
||||||
class="input"
|
|
||||||
type="email"
|
|
||||||
placeholder="NR Band"
|
|
||||||
/>
|
|
||||||
<span class="icon is-left">
|
|
||||||
<i class="fa-solid fa-signal"></i>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- Entry 2 End -->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="cell">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">NR PCI</label>
|
||||||
|
<div class="control has-icons-left">
|
||||||
|
<input
|
||||||
|
class="input"
|
||||||
|
type="email"
|
||||||
|
placeholder="NR PCI"
|
||||||
|
/>
|
||||||
|
<span class="icon is-left">
|
||||||
|
<i class="fa-solid fa-signal"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Entry 1 End -->
|
||||||
|
|
||||||
|
<!-- Entry 2 Start -->
|
||||||
|
<div class="cell">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">SCS</label>
|
||||||
|
<div class="control has-icons-left">
|
||||||
|
<span class="select">
|
||||||
|
<select>
|
||||||
|
<option selected>Select SCS</option>
|
||||||
|
<option>15 kHz</option>
|
||||||
|
<option>30 kHz</option>
|
||||||
|
<option>60 kHz</option>
|
||||||
|
<option>120 kHz</option>
|
||||||
|
<option>240 kHz</option>
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
|
<span class="icon is-left">
|
||||||
|
<i class="fas fa-bolt"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cell">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">NR Band</label>
|
||||||
|
<div class="control has-icons-left">
|
||||||
|
<input
|
||||||
|
class="input"
|
||||||
|
type="email"
|
||||||
|
placeholder="NR Band"
|
||||||
|
/>
|
||||||
|
<span class="icon is-left">
|
||||||
|
<i class="fa-solid fa-signal"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Entry 2 End -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer">
|
</div>
|
||||||
<a
|
<div class="card-footer">
|
||||||
href="#"
|
<a
|
||||||
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
|
href="#"
|
||||||
>
|
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
|
||||||
Lock SA Cells
|
>
|
||||||
</a>
|
Lock SA Cells
|
||||||
|
</a>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
|
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
|
||||||
>
|
>
|
||||||
Reset
|
Reset
|
||||||
</a>
|
</a>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -408,7 +409,7 @@
|
|||||||
<div id="loading-content" style="display: none">
|
<div id="loading-content" style="display: none">
|
||||||
<div class="custom-loader"></div>
|
<div class="custom-loader"></div>
|
||||||
<div class="countdown-text">
|
<div class="countdown-text">
|
||||||
Rebooting... <span id="countdown">80</span>s
|
Rebooting... <span id="countdown">90</span>s
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons" id="modal-buttons">
|
<div class="buttons" id="modal-buttons">
|
||||||
|
|||||||
@@ -468,7 +468,7 @@
|
|||||||
<div id="loading-content" style="display: none">
|
<div id="loading-content" style="display: none">
|
||||||
<div class="custom-loader"></div>
|
<div class="custom-loader"></div>
|
||||||
<div class="countdown-text">
|
<div class="countdown-text">
|
||||||
Rebooting... <span id="countdown">80</span>s
|
Rebooting... <span id="countdown">90</span>s
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons" id="modal-buttons">
|
<div class="buttons" id="modal-buttons">
|
||||||
|
|||||||
@@ -439,7 +439,7 @@
|
|||||||
<div id="loading-content" style="display: none">
|
<div id="loading-content" style="display: none">
|
||||||
<div class="custom-loader"></div>
|
<div class="custom-loader"></div>
|
||||||
<div class="countdown-text">
|
<div class="countdown-text">
|
||||||
Rebooting... <span id="countdown">80</span>s
|
Rebooting... <span id="countdown">90</span>s
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons" id="modal-buttons">
|
<div class="buttons" id="modal-buttons">
|
||||||
|
|||||||
@@ -403,7 +403,7 @@
|
|||||||
<div id="loading-content" style="display: none">
|
<div id="loading-content" style="display: none">
|
||||||
<div class="custom-loader"></div>
|
<div class="custom-loader"></div>
|
||||||
<div class="countdown-text">
|
<div class="countdown-text">
|
||||||
Rebooting... <span id="countdown">80</span>s
|
Rebooting... <span id="countdown">90</span>s
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons" id="modal-buttons">
|
<div class="buttons" id="modal-buttons">
|
||||||
|
|||||||
@@ -179,10 +179,6 @@ html.theme-light {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cell-table tbody {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cell-carousel {
|
.cell-carousel {
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -191,8 +187,8 @@ html.theme-light {
|
|||||||
|
|
||||||
.cell-carousel__container {
|
.cell-carousel__container {
|
||||||
display: flex;
|
display: flex;
|
||||||
transition: transform 0.3s ease;
|
transition: transform 0.3s ease-out;
|
||||||
min-height: 300px; /* Adjust based on your content */
|
min-height: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cell-carousel__slide {
|
.cell-carousel__slide {
|
||||||
@@ -201,6 +197,21 @@ html.theme-light {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cell-carousel__slide--new {
|
||||||
|
animation: slideIn 0.3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(50px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.cell-card {
|
.cell-card {
|
||||||
border: 1px solid #dbdbdb;
|
border: 1px solid #dbdbdb;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -216,31 +227,22 @@ html.theme-light {
|
|||||||
border-bottom: 1px solid #dbdbdb;
|
border-bottom: 1px solid #dbdbdb;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cell-card__item:last-child {
|
.cell-card__value {
|
||||||
border-bottom: none;
|
transition: opacity 0.3s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cell-card__label {
|
.cell-card__value--updating {
|
||||||
font-weight: bold;
|
opacity: 0;
|
||||||
margin-right: 1rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Navigation buttons */
|
.cell-card__value--updated {
|
||||||
.cell-carousel__nav {
|
animation: fadeIn 0.3s ease-out;
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* .cell-carousel__btn {
|
@keyframes fadeIn {
|
||||||
background: #3273dc;
|
from { opacity: 0; }
|
||||||
color: white;
|
to { opacity: 1; }
|
||||||
border: none;
|
}
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
margin: 0 0.5rem;
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
} */
|
|
||||||
|
|
||||||
.cell-carousel__indicators {
|
.cell-carousel__indicators {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -255,6 +257,7 @@ html.theme-light {
|
|||||||
background: #dbdbdb;
|
background: #dbdbdb;
|
||||||
margin: 0 4px;
|
margin: 0 4px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cell-carousel__dot--active {
|
.cell-carousel__dot--active {
|
||||||
|
|||||||
@@ -485,7 +485,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<div id="loading-content" style="display: none;">
|
<div id="loading-content" style="display: none;">
|
||||||
<div class="custom-loader"></div>
|
<div class="custom-loader"></div>
|
||||||
<div class="countdown-text">Rebooting... <span id="countdown">80</span>s</div>
|
<div class="countdown-text">Rebooting... <span id="countdown">90</span>s</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons" id="modal-buttons">
|
<div class="buttons" id="modal-buttons">
|
||||||
<button class="button is-warning" id="rebootModem">Reboot</button>
|
<button class="button is-warning" id="rebootModem">Reboot</button>
|
||||||
|
|||||||
405
www/js/advance/fetch-current-settings.js
Normal file
405
www/js/advance/fetch-current-settings.js
Normal file
@@ -0,0 +1,405 @@
|
|||||||
|
// API Module - Handles all server communications
|
||||||
|
const api = {
|
||||||
|
async fetchCurrentSettings() {
|
||||||
|
try {
|
||||||
|
const response = await fetch("/cgi-bin/advanced_settings.sh");
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
console.log("Current settings:", data);
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching settings:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async fetchConnectedDevices() {
|
||||||
|
try {
|
||||||
|
const response = await fetch("/cgi-bin/fetch_macs.sh");
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching devices:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async sendATCommand(command) {
|
||||||
|
try {
|
||||||
|
const response = await fetch("/cgi-bin/atinout_handler.sh", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
},
|
||||||
|
body: "command=" + encodeURIComponent(command)
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
console.log("AT command response:", data);
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error sending AT command:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// UI Manager Module - Handles all DOM interactions and UI updates
|
||||||
|
const uiManager = {
|
||||||
|
elements: {
|
||||||
|
ipPassthrough: () => document.getElementById("ip-passthrough-mode"),
|
||||||
|
dnsProxy: () => document.getElementById("dns-proxy-mode"),
|
||||||
|
usbModem: () => document.getElementById("usb-modem-protocol"),
|
||||||
|
connectedDevices: () => document.getElementById("connected-devices"),
|
||||||
|
loadingContent: () => document.getElementById("loading-content"),
|
||||||
|
modalButtons: () => document.getElementById("modal-buttons"),
|
||||||
|
countdown: () => document.getElementById("countdown"),
|
||||||
|
rebootModal: () => document.getElementById("reboot-modal"),
|
||||||
|
advancedSettingsIcons: () => document.querySelectorAll(".advanced-settings i")
|
||||||
|
},
|
||||||
|
|
||||||
|
showLoadingSpinners() {
|
||||||
|
this.elements.advancedSettingsIcons().forEach(icon => {
|
||||||
|
icon.classList.add("fa-spinner", "fa-spin");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
hideLoadingSpinners() {
|
||||||
|
this.elements.advancedSettingsIcons().forEach(icon => {
|
||||||
|
icon.classList.remove("fa-spinner", "fa-spin");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
updatePassthroughModeState(isEnabled) {
|
||||||
|
const select = this.elements.ipPassthrough();
|
||||||
|
if (!select) return;
|
||||||
|
|
||||||
|
const helpText = select.parentElement.querySelector(".help");
|
||||||
|
|
||||||
|
if (isEnabled) {
|
||||||
|
select.removeAttribute("disabled");
|
||||||
|
select.classList.remove("is-warning");
|
||||||
|
if (helpText) {
|
||||||
|
helpText.textContent = "Select a passthrough mode to apply.";
|
||||||
|
helpText.classList.remove("is-warning");
|
||||||
|
helpText.classList.add("is-info");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
select.setAttribute("disabled", "disabled");
|
||||||
|
select.classList.add("is-warning");
|
||||||
|
select.value = "Select IP Passthrough Mode";
|
||||||
|
if (helpText) {
|
||||||
|
helpText.textContent = "Please select a device first.";
|
||||||
|
helpText.classList.remove("is-info");
|
||||||
|
helpText.classList.add("is-warning");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
populateConnectedDevices(devices) {
|
||||||
|
const select = this.elements.connectedDevices();
|
||||||
|
if (!select) {
|
||||||
|
console.error("Connected devices select element not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear existing options except the first one
|
||||||
|
while (select.options.length > 1) {
|
||||||
|
select.remove(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new options
|
||||||
|
devices.forEach(device => {
|
||||||
|
const option = document.createElement("option");
|
||||||
|
option.value = device.mac;
|
||||||
|
option.textContent = `${device.hostname} - ${device.mac}`;
|
||||||
|
select.appendChild(option);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
showModal() {
|
||||||
|
const modal = this.elements.rebootModal();
|
||||||
|
if (modal) {
|
||||||
|
modal.classList.add("is-active");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
showLoadingContent() {
|
||||||
|
this.elements.loadingContent().style.display = "flex";
|
||||||
|
this.elements.modalButtons().style.display = "none";
|
||||||
|
this.showModal();
|
||||||
|
},
|
||||||
|
|
||||||
|
startCountdown(duration) {
|
||||||
|
const countdownElement = this.elements.countdown();
|
||||||
|
let countdown = duration;
|
||||||
|
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
countdown--;
|
||||||
|
countdownElement.textContent = countdown;
|
||||||
|
|
||||||
|
if (countdown <= 0) {
|
||||||
|
clearInterval(interval);
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
},
|
||||||
|
|
||||||
|
// showSuccessMessage(message) {
|
||||||
|
// // Implement based on your UI framework
|
||||||
|
// console.log("Success:", message);
|
||||||
|
// // Example: Show a toast notification
|
||||||
|
// if (window.bulmaToast) {
|
||||||
|
// bulmaToast.toast({
|
||||||
|
// message: message,
|
||||||
|
// type: 'is-success',
|
||||||
|
// duration: 3000,
|
||||||
|
// position: 'top-center',
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
|
||||||
|
// showErrorMessage(message) {
|
||||||
|
// // Implement based on your UI framework
|
||||||
|
// console.error("Error:", message);
|
||||||
|
// // Example: Show a toast notification
|
||||||
|
// if (window.bulmaToast) {
|
||||||
|
// bulmaToast.toast({
|
||||||
|
// message: message,
|
||||||
|
// type: 'is-danger',
|
||||||
|
// duration: 5000,
|
||||||
|
// position: 'top-center',
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
|
||||||
|
setElementLoading(element, isLoading) {
|
||||||
|
if (isLoading) {
|
||||||
|
element.disabled = true;
|
||||||
|
element.classList.add('is-loading');
|
||||||
|
} else {
|
||||||
|
element.disabled = false;
|
||||||
|
element.classList.remove('is-loading');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Settings Manager Module - Handles settings logic and updates
|
||||||
|
const settingsManager = {
|
||||||
|
async updateSettings(data) {
|
||||||
|
const elements = {
|
||||||
|
ipPassthrough: uiManager.elements.ipPassthrough(),
|
||||||
|
dnsProxy: uiManager.elements.dnsProxy(),
|
||||||
|
usbModem: uiManager.elements.usbModem()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Validate required elements
|
||||||
|
const missingElements = Object.entries(elements)
|
||||||
|
.filter(([, element]) => !element)
|
||||||
|
.map(([key]) => key);
|
||||||
|
|
||||||
|
if (missingElements.length > 0) {
|
||||||
|
console.error("Missing DOM elements:", missingElements);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
uiManager.updatePassthroughModeState(false);
|
||||||
|
|
||||||
|
// Update IP Passthrough Mode
|
||||||
|
const mpdnRuleLine = data[0].response.split("\n")[1];
|
||||||
|
if (mpdnRuleLine) {
|
||||||
|
const mpdnRule = mpdnRuleLine.split(":")[1].trim();
|
||||||
|
const passthroughMode = this.getPassthroughModeValue(mpdnRule);
|
||||||
|
elements.ipPassthrough.value = passthroughMode;
|
||||||
|
elements.ipPassthrough.setAttribute("data-current-mode", passthroughMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update DNS Proxy
|
||||||
|
const dnsProxyLine = data[1].response.split("\n")[1].split(":")[1].split(",")[1].trim();
|
||||||
|
const dnsProxyMode = dnsProxyLine === '"disable"' ? "Disabled" : "Enabled";
|
||||||
|
elements.dnsProxy.value = dnsProxyMode;
|
||||||
|
elements.dnsProxy.setAttribute("data-current-mode", dnsProxyMode);
|
||||||
|
|
||||||
|
// Update USB Modem Protocol
|
||||||
|
const usbModemProtocolLine = data[2].response.split("\n")[1].split(":")[1].split(",")[1].trim();
|
||||||
|
const usbModemMode = this.getUsbModemProtocolValue(usbModemProtocolLine);
|
||||||
|
elements.usbModem.value = usbModemMode;
|
||||||
|
elements.usbModem.setAttribute("data-current-protocol", usbModemMode);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error updating settings:", error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getPassthroughModeValue(mpdnRule) {
|
||||||
|
const modes = {
|
||||||
|
'"MPDN_rule",0,0,0,0,0': "Disabled",
|
||||||
|
'"MPDN_rule",0,1,0,1,1': "ETH Only",
|
||||||
|
'"MPDN_rule",0,1,0,3,1': "USB Only"
|
||||||
|
};
|
||||||
|
return modes[mpdnRule] || "Select IP Passthrough Mode";
|
||||||
|
},
|
||||||
|
|
||||||
|
getUsbModemProtocolValue(protocol) {
|
||||||
|
const protocols = {
|
||||||
|
"0": "RMNET",
|
||||||
|
"1": "ECM (Recommended)",
|
||||||
|
"2": "MBIM",
|
||||||
|
"3": "RNDIS"
|
||||||
|
};
|
||||||
|
return protocols[protocol] || "Select USB Modem Protocol";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Event Handlers Module - Handles all event listeners
|
||||||
|
const eventHandlers = {
|
||||||
|
async handleDnsProxyChange(e) {
|
||||||
|
const element = e.target;
|
||||||
|
const selectedMode = element.value;
|
||||||
|
const currentMode = element.getAttribute("data-current-mode");
|
||||||
|
|
||||||
|
if (selectedMode !== currentMode) {
|
||||||
|
const command = selectedMode === "Enabled"
|
||||||
|
? 'AT+QMAP="DHCPV4DNS","enable"'
|
||||||
|
: 'AT+QMAP="DHCPV4DNS","disable"';
|
||||||
|
|
||||||
|
uiManager.setElementLoading(element, true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await api.sendATCommand(command);
|
||||||
|
if (response.output.includes("OK")) {
|
||||||
|
element.setAttribute("data-current-mode", selectedMode);
|
||||||
|
// uiManager.showSuccessMessage("DNS Proxy setting updated successfully");
|
||||||
|
} else {
|
||||||
|
element.value = currentMode;
|
||||||
|
// uiManager.showErrorMessage("Failed to update DNS Proxy setting");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error sending AT command:", error);
|
||||||
|
element.value = currentMode;
|
||||||
|
// uiManager.showErrorMessage("Error updating DNS Proxy setting");
|
||||||
|
} finally {
|
||||||
|
// uiManager.setElementLoading(element, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async handleIpPassthroughChange(e) {
|
||||||
|
const element = e.target;
|
||||||
|
const selectedMode = element.value;
|
||||||
|
const currentMode = element.getAttribute("data-current-mode");
|
||||||
|
const selectedDeviceMAC = uiManager.elements.connectedDevices().value;
|
||||||
|
|
||||||
|
if (selectedMode !== currentMode) {
|
||||||
|
const commands = {
|
||||||
|
"Disabled": 'AT+QMAP="MPDN_rule",0;+QPOWD=1',
|
||||||
|
"ETH Only": `AT+QMAP="MPDN_rule",0,1,0,1,1,"${selectedDeviceMAC}";+QPOWD=1`,
|
||||||
|
"USB Only": `AT+QMAP="MPDN_rule",0,1,0,3,1,"${selectedDeviceMAC}";+QPOWD=1`
|
||||||
|
};
|
||||||
|
|
||||||
|
const command = commands[selectedMode];
|
||||||
|
if (command) {
|
||||||
|
uiManager.showLoadingContent();
|
||||||
|
uiManager.startCountdown(90);
|
||||||
|
try {
|
||||||
|
await api.sendATCommand(command);
|
||||||
|
} catch (error) {
|
||||||
|
uiManager.showErrorMessage("Error updating IP Passthrough mode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async handleUsbModemProtocolChange(e) {
|
||||||
|
const element = e.target;
|
||||||
|
const selectedProtocol = element.value;
|
||||||
|
const currentProtocol = element.getAttribute("data-current-protocol");
|
||||||
|
|
||||||
|
if (selectedProtocol !== currentProtocol) {
|
||||||
|
const commands = {
|
||||||
|
"RMNET": 'AT+QCFG="usbnet",0;+CFUN=1,1',
|
||||||
|
"ECM (Recommended)": 'AT+QCFG="usbnet",1;+CFUN=1,1',
|
||||||
|
"MBIM": 'AT+QCFG="usbnet",2;+CFUN=1,1',
|
||||||
|
"RNDIS": 'AT+QCFG="usbnet",3;+CFUN=1,1'
|
||||||
|
};
|
||||||
|
|
||||||
|
const command = commands[selectedProtocol];
|
||||||
|
if (command) {
|
||||||
|
uiManager.showLoadingContent();
|
||||||
|
uiManager.startCountdown(90);
|
||||||
|
try {
|
||||||
|
await api.sendATCommand(command);
|
||||||
|
} catch (error) {
|
||||||
|
uiManager.showErrorMessage("Error updating USB Modem Protocol");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleDeviceSelection(e) {
|
||||||
|
const selectedMAC = e.target.value;
|
||||||
|
const selectedHostname = e.target.options[e.target.selectedIndex].text;
|
||||||
|
console.log("Selected device:", { mac: selectedMAC, hostname: selectedHostname });
|
||||||
|
|
||||||
|
const isDeviceSelected = selectedMAC !== "Select Device MAC";
|
||||||
|
uiManager.updatePassthroughModeState(isDeviceSelected);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Application Initialization
|
||||||
|
async function init() {
|
||||||
|
uiManager.showLoadingSpinners();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [settings, devices] = await Promise.all([
|
||||||
|
api.fetchCurrentSettings(),
|
||||||
|
api.fetchConnectedDevices()
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (settings) {
|
||||||
|
const updateSuccess = await settingsManager.updateSettings(settings);
|
||||||
|
if (updateSuccess) {
|
||||||
|
// Set up event listeners
|
||||||
|
const dnsProxyElement = uiManager.elements.dnsProxy();
|
||||||
|
const ipPassthroughElement = uiManager.elements.ipPassthrough();
|
||||||
|
const usbModemElement = uiManager.elements.usbModem();
|
||||||
|
const connectedDevicesElement = uiManager.elements.connectedDevices();
|
||||||
|
|
||||||
|
if (dnsProxyElement) {
|
||||||
|
dnsProxyElement.addEventListener("change", eventHandlers.handleDnsProxyChange);
|
||||||
|
}
|
||||||
|
if (ipPassthroughElement) {
|
||||||
|
ipPassthroughElement.addEventListener("change", eventHandlers.handleIpPassthroughChange);
|
||||||
|
}
|
||||||
|
if (usbModemElement) {
|
||||||
|
usbModemElement.addEventListener("change", eventHandlers.handleUsbModemProtocolChange);
|
||||||
|
}
|
||||||
|
if (connectedDevicesElement) {
|
||||||
|
connectedDevicesElement.addEventListener("change", eventHandlers.handleDeviceSelection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devices) {
|
||||||
|
uiManager.populateConnectedDevices(devices);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Initialization error:", error);
|
||||||
|
uiManager.showErrorMessage("Error initializing settings");
|
||||||
|
} finally {
|
||||||
|
uiManager.hideLoadingSpinners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize when DOM is ready
|
||||||
|
document.addEventListener("DOMContentLoaded", init);
|
||||||
@@ -645,31 +645,31 @@ function createBandTableRow(bandData, networkType, servingCellJSON) {
|
|||||||
<div class="cell-card">
|
<div class="cell-card">
|
||||||
<div class="cell-card__item">
|
<div class="cell-card__item">
|
||||||
<span class="cell-card__label">Name</span>
|
<span class="cell-card__label">Name</span>
|
||||||
<span>${formattedBandNumber || "N/A"}</span>
|
<span class="cell-card__value">${formattedBandNumber || "N/A"}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="cell-card__item">
|
<div class="cell-card__item">
|
||||||
<span class="cell-card__label">EARFCN</span>
|
<span class="cell-card__label">EARFCN</span>
|
||||||
<span>${earfcn || "N/A"}</span>
|
<span class="cell-card__value">${earfcn || "N/A"}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="cell-card__item">
|
<div class="cell-card__item">
|
||||||
<span class="cell-card__label">Bandwidth</span>
|
<span class="cell-card__label">Bandwidth</span>
|
||||||
<span>${bandwidth || "N/A"}</span>
|
<span class="cell-card__value">${bandwidth || "N/A"}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="cell-card__item">
|
<div class="cell-card__item">
|
||||||
<span class="cell-card__label">Physical ID</span>
|
<span class="cell-card__label">Physical ID</span>
|
||||||
<span>${pci || "N/A"}</span>
|
<span class="cell-card__value">${pci || "N/A"}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="cell-card__item">
|
<div class="cell-card__item">
|
||||||
<span class="cell-card__label">RSRP</span>
|
<span class="cell-card__label">RSRP</span>
|
||||||
<span>${rsrp ? createSignalTag(rsrp, "RSRP") : "N/A"}</span>
|
<span class="cell-card__value">${rsrp ? createSignalTag(rsrp, "RSRP") : "N/A"}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="cell-card__item">
|
<div class="cell-card__item">
|
||||||
<span class="cell-card__label">RSRQ</span>
|
<span class="cell-card__label">RSRQ</span>
|
||||||
<span>${rsrq ? createSignalTag(rsrq, "RSRQ") : "N/A"}</span>
|
<span class="cell-card__value">${rsrq ? createSignalTag(rsrq, "RSRQ") : "N/A"}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="cell-card__item">
|
<div class="cell-card__item">
|
||||||
<span class="cell-card__label">SINR</span>
|
<span class="cell-card__label">SINR</span>
|
||||||
<span>${sinr ? createSignalTag(sinr, "SINR") : "N/A"}</span>
|
<span class="cell-card__value">${sinr ? createSignalTag(sinr, "SINR") : "N/A"}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1090,9 +1090,12 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
setupEventListeners();
|
setupEventListeners();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Mobile Band Cards
|
||||||
let carouselInitialized = false;
|
let carouselInitialized = false;
|
||||||
let currentSlide = 0;
|
let currentSlide = 0;
|
||||||
|
let previousRowCount = 0;
|
||||||
|
|
||||||
|
// Modify the mobile carousel initialization to ensure proper setup
|
||||||
function initMobileCarousel() {
|
function initMobileCarousel() {
|
||||||
const table = document.getElementById("bandTable");
|
const table = document.getElementById("bandTable");
|
||||||
const tbody = table.querySelector("tbody");
|
const tbody = table.querySelector("tbody");
|
||||||
@@ -1102,7 +1105,7 @@ function initMobileCarousel() {
|
|||||||
let carouselWrapper = document.querySelector(".cell-carousel");
|
let carouselWrapper = document.querySelector(".cell-carousel");
|
||||||
|
|
||||||
if (!carouselInitialized) {
|
if (!carouselInitialized) {
|
||||||
// Create carousel structure only if it doesn't exist
|
// Create carousel structure
|
||||||
carouselWrapper = document.createElement("div");
|
carouselWrapper = document.createElement("div");
|
||||||
carouselWrapper.className = "cell-carousel";
|
carouselWrapper.className = "cell-carousel";
|
||||||
|
|
||||||
@@ -1111,27 +1114,31 @@ function initMobileCarousel() {
|
|||||||
|
|
||||||
carouselWrapper.appendChild(carouselContainer);
|
carouselWrapper.appendChild(carouselContainer);
|
||||||
|
|
||||||
// Add touch event listeners only once
|
// Add touch event listeners
|
||||||
carouselContainer.addEventListener("touchstart", handleTouchStart, false);
|
carouselContainer.addEventListener("touchstart", handleTouchStart, false);
|
||||||
carouselContainer.addEventListener("touchmove", handleTouchMove, false);
|
carouselContainer.addEventListener("touchmove", handleTouchMove, false);
|
||||||
carouselContainer.addEventListener("touchend", handleTouchEnd, false);
|
carouselContainer.addEventListener("touchend", handleTouchEnd, false);
|
||||||
|
|
||||||
// Insert carousel into DOM
|
// Insert carousel before table
|
||||||
table.style.display = "none";
|
table.style.display = "none";
|
||||||
table.parentNode.insertBefore(carouselWrapper, table);
|
table.parentNode.insertBefore(carouselWrapper, table);
|
||||||
|
|
||||||
carouselInitialized = true;
|
carouselInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update carousel content
|
// Always ensure carousel is visible and table is hidden
|
||||||
|
carouselWrapper.style.display = "";
|
||||||
|
table.style.display = "none";
|
||||||
|
|
||||||
|
// Update content
|
||||||
updateCarouselContent(rows);
|
updateCarouselContent(rows);
|
||||||
} else {
|
} else {
|
||||||
// Restore desktop view
|
// Desktop view
|
||||||
const carousel = document.querySelector(".cell-carousel");
|
const carousel = document.querySelector(".cell-carousel");
|
||||||
if (carousel) {
|
if (carousel) {
|
||||||
carousel.style.display = "none";
|
carousel.style.display = "none";
|
||||||
table.style.display = "";
|
|
||||||
}
|
}
|
||||||
|
table.style.display = "";
|
||||||
|
|
||||||
rows.forEach((row) => {
|
rows.forEach((row) => {
|
||||||
row.innerHTML = row.getAttribute("data-desktop");
|
row.innerHTML = row.getAttribute("data-desktop");
|
||||||
@@ -1139,29 +1146,93 @@ function initMobileCarousel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add CSS class for smooth transitions
|
||||||
|
const style = document.createElement('style');
|
||||||
|
style.textContent = `
|
||||||
|
.cell-carousel__container {
|
||||||
|
display: flex;
|
||||||
|
transition: transform 0.3s ease-out;
|
||||||
|
min-height: 300px;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell-carousel__slide {
|
||||||
|
flex: 0 0 100%;
|
||||||
|
padding: 1rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 0.3s ease-out;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
function updateCarouselContent(rows) {
|
function updateCarouselContent(rows) {
|
||||||
const carouselContainer = document.querySelector(".cell-carousel__container");
|
const carouselContainer = document.querySelector(".cell-carousel__container");
|
||||||
const indicators = document.querySelector(".cell-carousel__indicators");
|
|
||||||
|
|
||||||
if (!carouselContainer) return;
|
if (!carouselContainer) return;
|
||||||
|
|
||||||
|
// Preserve existing transform to maintain current slide position
|
||||||
|
const currentTransform = carouselContainer.style.transform;
|
||||||
|
|
||||||
// Clear existing content
|
// Clear existing content
|
||||||
carouselContainer.innerHTML = "";
|
carouselContainer.innerHTML = '';
|
||||||
if (indicators) indicators.remove();
|
|
||||||
|
// Create and append all slides at once
|
||||||
// Add new slides
|
|
||||||
rows.forEach((row) => {
|
rows.forEach((row) => {
|
||||||
carouselContainer.insertAdjacentHTML(
|
const slide = document.createElement("div");
|
||||||
"beforeend",
|
slide.className = "cell-carousel__slide";
|
||||||
row.getAttribute("data-mobile")
|
slide.innerHTML = row.getAttribute("data-mobile");
|
||||||
);
|
carouselContainer.appendChild(slide);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Restore transform to maintain position
|
||||||
|
carouselContainer.style.transform = currentTransform;
|
||||||
|
|
||||||
// Update indicators
|
// Update indicators
|
||||||
|
updateIndicators(rows.length);
|
||||||
|
|
||||||
|
// Ensure current slide is within bounds
|
||||||
|
if (currentSlide >= rows.length) {
|
||||||
|
currentSlide = Math.max(0, rows.length - 1);
|
||||||
|
updateCarouselPosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSlideValues(slide, newDataHtml) {
|
||||||
|
const tempDiv = document.createElement('div');
|
||||||
|
tempDiv.innerHTML = newDataHtml;
|
||||||
|
const newCard = tempDiv.querySelector('.cell-card');
|
||||||
|
const currentCard = slide.querySelector('.cell-card');
|
||||||
|
|
||||||
|
if (!currentCard || !newCard) {
|
||||||
|
slide.innerHTML = newDataHtml;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentItems = currentCard.querySelectorAll('.cell-card__item');
|
||||||
|
const newItems = newCard.querySelectorAll('.cell-card__item');
|
||||||
|
|
||||||
|
currentItems.forEach((item, index) => {
|
||||||
|
const currentValueSpan = item.querySelector('span:not(.cell-card__label)');
|
||||||
|
const newItem = newItems[index];
|
||||||
|
const newValueSpan = newItem ? newItem.querySelector('span:not(.cell-card__label)') : null;
|
||||||
|
|
||||||
|
if (currentValueSpan && newValueSpan && currentValueSpan.innerHTML !== newValueSpan.innerHTML) {
|
||||||
|
currentValueSpan.innerHTML = newValueSpan.innerHTML;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateIndicators(slideCount) {
|
||||||
|
const carouselWrapper = document.querySelector(".cell-carousel");
|
||||||
|
let indicators = carouselWrapper.querySelector(".cell-carousel__indicators");
|
||||||
|
|
||||||
|
if (indicators) {
|
||||||
|
indicators.remove();
|
||||||
|
}
|
||||||
|
|
||||||
const indicatorsHTML = `
|
const indicatorsHTML = `
|
||||||
<div class="cell-carousel__indicators">
|
<div class="cell-carousel__indicators">
|
||||||
${Array.from(
|
${Array.from(
|
||||||
{ length: rows.length },
|
{ length: slideCount },
|
||||||
(_, i) =>
|
(_, i) =>
|
||||||
`<span class="cell-carousel__dot ${
|
`<span class="cell-carousel__dot ${
|
||||||
i === currentSlide ? "cell-carousel__dot--active" : ""
|
i === currentSlide ? "cell-carousel__dot--active" : ""
|
||||||
@@ -1171,14 +1242,27 @@ function updateCarouselContent(rows) {
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
carouselContainer.parentNode.insertAdjacentHTML("beforeend", indicatorsHTML);
|
carouselWrapper.insertAdjacentHTML("beforeend", indicatorsHTML);
|
||||||
|
|
||||||
// Reset to first slide and update display
|
|
||||||
currentSlide = 0;
|
|
||||||
updateCarousel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Your existing touch handling functions remain the same
|
// Add a helper function to ensure smooth transitions
|
||||||
|
function updateCarouselPosition() {
|
||||||
|
const container = document.querySelector(".cell-carousel__container");
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
// Apply transform with a slight delay to ensure smooth transition
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
container.style.transform = `translateX(-${currentSlide * 100}%)`;
|
||||||
|
});
|
||||||
|
|
||||||
|
const dots = document.querySelectorAll(".cell-carousel__dot");
|
||||||
|
dots.forEach((dot, index) => {
|
||||||
|
dot.classList.toggle("cell-carousel__dot--active", index === currentSlide);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Touch handling functions remain the same
|
||||||
let touchStartX = 0;
|
let touchStartX = 0;
|
||||||
let touchEndX = 0;
|
let touchEndX = 0;
|
||||||
|
|
||||||
@@ -1207,27 +1291,15 @@ function handleSwipe() {
|
|||||||
} else if (diffX < 0 && currentSlide > 0) {
|
} else if (diffX < 0 && currentSlide > 0) {
|
||||||
currentSlide--;
|
currentSlide--;
|
||||||
}
|
}
|
||||||
updateCarousel();
|
updateCarouselPosition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function goToSlide(index) {
|
function goToSlide(index) {
|
||||||
currentSlide = index;
|
currentSlide = index;
|
||||||
updateCarousel();
|
updateCarouselPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateCarousel() {
|
// Event listeners
|
||||||
const container = document.querySelector(".cell-carousel__container");
|
|
||||||
if (!container) return;
|
|
||||||
|
|
||||||
container.style.transform = `translateX(-${currentSlide * 100}%)`;
|
|
||||||
|
|
||||||
const dots = document.querySelectorAll(".cell-carousel__dot");
|
|
||||||
dots.forEach((dot, index) => {
|
|
||||||
dot.classList.toggle("cell-carousel__dot--active", index === currentSlide);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update your event listeners
|
|
||||||
window.addEventListener("load", initMobileCarousel);
|
window.addEventListener("load", initMobileCarousel);
|
||||||
window.addEventListener("resize", initMobileCarousel);
|
window.addEventListener("resize", initMobileCarousel);
|
||||||
@@ -22,12 +22,12 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
if (countdownInterval) {
|
if (countdownInterval) {
|
||||||
clearInterval(countdownInterval);
|
clearInterval(countdownInterval);
|
||||||
}
|
}
|
||||||
countdownElement.textContent = '80';
|
countdownElement.textContent = '90';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function startCountdown() {
|
function startCountdown() {
|
||||||
let timeLeft = 80;
|
let timeLeft = 90;
|
||||||
|
|
||||||
// Update display for countdown
|
// Update display for countdown
|
||||||
modalMessage.style.display = 'none';
|
modalMessage.style.display = 'none';
|
||||||
@@ -75,7 +75,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
},
|
},
|
||||||
body: 'command=' + encodeURIComponent('AT+CFUN=1,1')
|
body: 'command=' + encodeURIComponent('AT+QPOWD=1')
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
|||||||
Reference in New Issue
Block a user