1 2 3<!DOCTYPE html> 4<html lang="en"> 5<head> 6 <title>OmOmega | omDoc â Document center</title> 7 8 <meta charset="utf-8"> 9 <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> 10 <meta name="description" content="OmOmega - Trợ lý riêng cá»§a bạn"> 11 <meta name="keywords" content="OmOmega, omomega, omChat, omchat, omBot, ombot, omDoc, omdoc, trà tuá» nhân tạo, ai, machine learning, deep learning"> 12 <meta name="robots" content="index,follow"> 13 <meta name="DC.title" content="OmOmega Trợ lý riêng cá»§a bạn"> 14 15 <meta property="og:image" content="/static/img/logo/omomega-icon218.png"> 16 17 <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,300i" rel="stylesheet"> 18 19 <link rel="stylesheet" type="text/css" href="/static/css/font-awesome.min.css"/> 20 <link rel="stylesheet" type="text/css" href="/static/css/themify-icons.css"/> 21 22 <!-- Styles --> 23 <link href="/static/css/core.min.css" rel="stylesheet"> 24 <link href="/static/css/app.min.css" rel="stylesheet"> 25 <link href="/static/css/style.min.css" rel="stylesheet"> 26 <link href="/static/css/om-style.css" rel="stylesheet"> 27 28 <!-- Favicons --> 29 <link rel="apple-touch-icon" href="/static/img/logo-icon-light.png"> 30 <link rel="icon" href="/static/img/logo-icon-light.png"> 31 32 <!-- Google AdSense--> 33
33<script data-ad-client="ca-pub-4642668630048169" async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
33 34 <link href="/static/vendor/toastr/css/toastr.min.css" rel="stylesheet"/> 35 36 37 38 39 <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet"> 40 <link href="/static/css/omdoc/omdoc_home.css" rel="stylesheet"> 41 42</head> 43<body> 44 45 46 47 <!-- Topbar --> 48 49<!-- top bar --> 50<header class="topbar"> 51 <div class="topbar-left"> 52 53 <a class="topbar-btn d-none d-md-block" href="/" title="Home" style="margin-top: 0"> 54 <i class="material-icons fa fa-home"></i> 55 </a> 56 57 <a class="topbar-btn d-none d-md-block" href="#" data-provide="fullscreen tooltip" title="Fullscreen" 58 onclick="on_click_btn_full_screen();"> 59 <i class="material-icons fullscreen-default">fullscreen</i> 60 <i class="material-icons fullscreen-active">fullscreen_exit</i> 61 </a> 62 63
63<script> 64 function on_click_btn_full_screen() { 65 if (document.fullscreenElement) { 66 document.exitFullscreen(); 67 } else { 68 document.documentElement.requestFullscreen().catch(err => { 69 console.error('Lá»i khi và o chế Äá» fullscreen:', err); 70 }); 71 } 72 } 73 </script>
73 74 75 <div class="dropdown d-none d-md-block"> 76 <span class="topbar-btn" data-toggle="dropdown"><i class="ti-layout-grid3-alt"></i></span> 77 <div class="dropdown-menu dropdown-grid"> 78 <a class="dropdown-item" href="/"> 79 <span data-i8-icon="home"></span> 80 <span class="title">Trang chá»§</span> 81 </a> 82 <a class="dropdown-item" href="/omdoc/"> 83 <span data-i8-icon="reading_ebook"></span> 84 <span class="title">omDoc</span> 85 </a> 86 <a class="dropdown-item" href="/ombot/"> 87 <span data-i8-icon="safe"></span> 88 <span class="title">omBot</span> 89 </a> 90 <a class="dropdown-item" href="/omtask/"> 91 <span data-i8-icon="calendar"></span> 92 <span class="title">Công viá»c</span> 93 </a> 94 <a class="dropdown-item" href="/omchat/"> 95 <span data-i8-icon="sms"></span> 96 <span class="title">Chat</span> 97 </a> 98 99 <a class="dropdown-item" href="/ommap/"> 100 <span data-i8-icon="globe"></span> 101 <span class="title">Map</span> 102 </a> 103 <a class="dropdown-item" href="/about/contact/"> 104 <span data-i8-icon="contacts"></span> 105 <span class="title">Liên há»</span> 106 </a> 107 <a class="dropdown-item" href="/rules/"> 108 <span data-i8-icon="plus"></span> 109 <span class="title">Thông tin</span> 110 </a> 111 </div> 112 </div> 113 114 <div class="topbar-divider d-none d-md-block"></div> 115 116 <div class="lookup d-none d-xl-block topbar-search" id="om-search"> 117 <input class="form-control" id="om-search-input" type="text" autocomplete="off"> 118 <div class="lookup-placeholder"> 119 <i class="ti-search"></i> 120 <span data-provide="typing" 121 data-type="entered<strong> Overview</strong>|entered<strong> Notifications</strong>|entered<strong> Statistics</strong>|entered<strong> Data layer</strong>|Search<strong> ...</strong>" 122 data-loop="false" data-type-speed="90" data-back-speed="50" data-show-cursor="false">Search<strong> ...</strong></span> 123 </div> 124 </div> 125 </div> 126 127 <div class="topbar-right"> 128 <ul class="topbar-btns"> 129 <li class=""> 130 <!-- Language switcher --> 131 132 133<!-- Language switcher --> 134<span class="topbar-btn om-lang-btn" data-toggle="dropdown" data-provide="tooltip" 135 data-tooltip-color="light" title="Language"> 136 <i class="ti-world"></i> 137 <span class="om-lang-code d-none d-md-inline-block">EN</span> 138 <i class="ion-android-arrow-down"></i> 139</span> 140<div class="dropdown-menu dropdown-menu-right om-lang-menu"> 141 <h6 class="dropdown-header">Language</h6> 142 143 <form action="/i18n/setlang/" method="post" class="om-lang-form"> 144 <input type="hidden" name="csrfmiddlewaretoken" value="U7ZuojYWq3QyruS54JxcqKbYsAyBwxndLZlfG2t3jnDhl0nHtgSyGRkvQcX1jbw4"> 145 <input type="hidden" name="next" value="/omdoc/"> 146 <input type="hidden" name="language" value="vi"> 147 <button type="submit" class="dropdown-item om-lang-item "> 148 <span class="om-lang-flag">ð»ð³</span> 149 <span class="om-lang-name">Tiếng Viá»t</span> 150 151 </button> 152 </form> 153 154 <form action="/i18n/setlang/" method="post" class="om-lang-form"> 155 <input type="hidden" name="csrfmiddlewaretoken" value="U7ZuojYWq3QyruS54JxcqKbYsAyBwxndLZlfG2t3jnDhl0nHtgSyGRkvQcX1jbw4"> 156 <input type="hidden" name="next" value="/omdoc/"> 157 <input type="hidden" name="language" value="en"> 158 <button type="submit" class="dropdown-item om-lang-item active">
159 <span class="om-lang-flag">ð¬ð§</span> 160 <span class="om-lang-name">English</span> 161 <i class="ti-check om-lang-check"></i> 162 </button> 163 </form> 164</div> 165 166<style> 167 /* Language switcher â match the topbar's clean, professional look */ 168 .om-lang-btn { display: inline-flex; align-items: center; gap: 4px; } 169 .om-lang-code { font-size: 13px; font-weight: 600; letter-spacing: 0.5px; } 170 .om-lang-menu { min-width: 190px; padding: 6px 0; } 171 .om-lang-form { margin: 0; } 172 .om-lang-item { 173 display: flex; align-items: center; gap: 10px; width: 100%; 174 background: none; border: 0; text-align: left; cursor: pointer; 175 padding: 8px 16px; font-size: 14px; color: #333; 176 } 177 .om-lang-item:hover { background-color: #f5f7fa; } 178 .om-lang-item.active { color: #36753f; font-weight: 600; } 179 .om-lang-flag { font-size: 16px; line-height: 1; } 180 .om-lang-name { flex-grow: 1; } 181 .om-lang-check { color: #36753f; } 182</style> 183<!-- END Language switcher --> 184 185 <!-- END Language switcher --> 186 </li> 187 <li class=""> 188 <!-- Global quickview --> 189 190<!-- Global quickview --> 191<span class="topbar-btn" data-toggle="dropdown"><i class="ti-align-right"></i></span> 192<div class="dropdown-menu dropdown-menu-right"> 193 <div class="media-list media-list-divided media-list-hover media-list-xs scrollable" 194 style="height: 482px"> 195 <i class="nav-link">Contents</i> 196 <div class="quickview-body"> 197 <div class="tab-content"> 198 <div class="tab-pane fade active show"> 199 <div class="media-list media-list-xs media-list-hover media-list-divided"> 200 201 202 <a class="media media-vertical bb-0" href="/"> 203 <h6>Home</h6> 204 <small>omomega.com</small> 205 </a> 206 207 <div class="divider text-uppercase fw-500 fs-10 ls-2 mb-0 mt-0">Products</div> 208 209 <a class="media media-vertical bb-0" href="/omdoc/"> 210 <h6>omDoc</h6> 211 <small>Knowledge sharing</small> 212 </a> 213 214 <a class="media media-vertical" href="/ombot/"> 215 <h6>omBot</h6> 216 <small>AI tools</small> 217 </a> 218 219 <a class="media media-vertical" href="/omchat/"> 220 <h6>omChat</h6> 221 <small>Internal messaging</small> 222 </a> 223 224 <a class="media media-vertical" href="/ommap/"> 225 <h6>omMap</h6> 226 <small>Personal map</small> 227 </a> 228 229 <a class="media media-vertical" href="/omtask/"> 230 <h6>omTask</h6> 231 <small>Task management</small> 232 </a> 233 234 235 236 <div class="divider text-uppercase fw-500 fs-10 ls-2 mb-0 mt-0">Statistics</div> 237 238 <a class="media media-vertical" href=""> 239 <h6>Online</h6> 240 <small>3</small> 241 </a> 242 243 <a class="media media-vertical" href=""> 244 <h6>Total visits</h6> 245 <small>1260644</small> 246 </a> 247 248 <div class="divider text-uppercase fw-500 fs-10 ls-2 mb-0 mt-0">Terms</div> 249 250 <a class="media media-vertical" href="/rules/"> 251 <h6>Terms</h6> 252 <small>OmOmega's commitment</small> 253 </a> 254 255 <div class="divider text-uppercase fw-500 fs-10 ls-2 mb-0 mt-0">Contact</div> 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 <a class="media media-vertical" href="/about/contact/"> 273 <h6>Contact</h6> 274 <small>Contact info, send feedback</small> 275 </a> 276 </div> 277 </div> 278 </div> 279 </div> 280 </div> 281</div> 282<!-- END Global quickview --> 283 284 <!-- END Global quickview --> 285 </li> 286 <li class="d-none d-xl-block"> 287 <!-- Setting --> 288 289<!-- Global quickview --> 290<span class="topbar-btn" data-toggle="dropdown"><i class="ti-settings"></i></span> 291<div class="dropdown-menu dropdown-menu-right"> 292 <div class="media-list media-list-divided media-list-hover media-list-xs scrollable" 293 style="height: 482px"> 294 <div class="media"> 295 <div class="media-body"> 296 <p><strong>Header bar color</strong></p> 297 <p>You can change the color of the header bar</p> 298 299 <div class="color-selector color-selector-sm mt-12"> 300 <label class="inverse"> 301 <input type="radio" value="default" name="global-topbar-color" checked>
302 <span style="background-color:#ffffff"></span> 303 </label> 304 305 <label> 306 <input type="radio" value="33cabb" name="global-topbar-color"> 307 <span style="background-color:#33cabb"></span> 308 </label> 309 310 <label> 311 <input type="radio" value="48b0f7" name="global-topbar-color"> 312 <span style="background-color:#48b0f7"></span> 313 </label> 314 315 <label> 316 <input type="radio" value="faa64b" name="global-topbar-color"> 317 <span style="background-color:#faa64b"></span> 318 </label> 319 320 <label> 321 <input type="radio" value="f96868" name="global-topbar-color"> 322 <span style="background-color:#f96868"></span> 323 </label> 324 325 <label> 326 <input type="radio" value="926dde" name="global-topbar-color"> 327 <span style="background-color:#926dde"></span> 328 </label> 329 330 <label> 331 <input type="radio" value="57c7d4" name="global-topbar-color"> 332 <span style="background-color:#57c7d4"></span> 333 </label> 334 335 <label> 336 <input type="radio" value="3f4a59" name="global-topbar-color"> 337 <span style="background-color:#3f4a59"></span> 338 </label> 339 </div> 340 </div> 341 </div> 342 </div> 343</div> 344<!-- END Global quickview --> 345 <!-- End Setting --> 346 </li> 347 </ul> 348 349 <div class="topbar-divider"></div> 350 <div> 351 352 <ul class="topbar-btns"> 353 <li> 354 <span class="topbar-btn"> 355 <a href="#" onclick="om_login();"><i class="ti-user"></i></a></span> 356 </li> 357 </ul> 358 359 </div> 360 <div class="d-none d-xl-block"> 361 <a href="#" target="_blank" data-toggle="modal" data-target="#modal_download_app"> 362 <img src="/static/img/logo/download_appstore.jpg" width="80" alt="OmOmega"> 363 </a> 364 </div> 365 366 <div class="topbar-divider d-none d-md-block"></div> 367 <!-- Copy current time button --> 368 <span id="btn-copy-time" class="d-none d-md-block" onclick="copyCurrentTime(event)" 369 title="Copy time" 370 style="cursor:pointer; display:inline-flex !important; align-items:center; margin-right:4px; transition: opacity 0.2s;"> 371 <i class="ti-files" style="color:#8aba6e; font-size:14px;"></i> 372 </span> 373 <div onclick="openOmCalendarModal()" class="d-none d-md-block"> 374 <span><b id="date-clock" class="text-success fs-22 fw-500"></b>, </span> 375 <span>(Lunar:<b id="lunar-date-clock" class="text-info fs-18 fw-500"></b> 376 377 ) 378 </span> 379
379<script src="/static/js/utils/lunar.js"></script>
379 380
380<script> 381 document.addEventListener("DOMContentLoaded", () => { 382 setInterval(function () { 383 updateTime(); 384 }, 1000); 385 }); 386 387 function addZero(i) { 388 if (i < 10) { 389 i = "0" + i; 390 } 391 return i; 392 } 393 394 function updateTime() { 395 const d = new Date(); 396 const day = d.getDay(); 397 const date = d.getDate(); 398 const month = d.getMonth() + 1; 399 const year = d.getFullYear(); 400 const h = d.getHours(); 401 const m = d.getMinutes(); 402 const s = d.getSeconds(); 403 404 let time_str = `${addZero(h)}:${addZero(m)}:${addZero(s)}`; 405 $("#time-clock").text(time_str); 406 let date_str = `${date}/${month}/${year}`; 407 $("#date-clock").text(date_str); 408 409 const days_of_week = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; 410 $("#day-clock").text(days_of_week[day]); 411 412 const solar = Solar.fromYmd(year, month, date); 413 const lunar = solar.getLunar(); 414 const lunar_day = lunar.getDay();
415 var lunar_month = lunar.getMonth(); 416 const lunar_str = `${lunar_day}/${lunar_month}/${lunar.getYear()}`; 417 $("#lunar-date-clock").text(lunar_str); 418 419 420 } 421 422 // Copy the current time display text to clipboard 423 function copyCurrentTime(event) { 424 event.stopPropagation(); 425 const day = $("#day-clock").text(); 426 const time = $("#time-clock").text(); 427 const date = $("#date-clock").text(); 428 const lunar = $("#lunar-date-clock").text(); 429 let copyText = `${day}, ${time} ${date}, (Lunar: ${lunar}`; 430 431 copyText += ')'; 432 navigator.clipboard.writeText(copyText).then(function() { 433 // Visual feedback: briefly change icon to checkmark 434 const $btn = $('#btn-copy-time'); 435 const $icon = $btn.find('i'); 436 $icon.removeClass('ti-files').addClass('ti-check'); 437 $icon.css('color', '#4CAF50'); 438 setTimeout(function() { 439 $icon.removeClass('ti-check').addClass('ti-files'); 440 $icon.css('color', '#8aba6e'); 441 }, 1200); 442 if (typeof toastr !== 'undefined') { 443 toastr.success(copyText, 'Copied!'); 444 } 445 }); 446 } 447 </script>
447 448 </div> 449 <div> 450 <span><b id="day-clock" class="text-primary fs-18 fw-500"></b>, </span> 451 <span><b id="time-clock" class="fs-26 fw-500" style="color:#819824;"></b> </span> 452 </div> 453 </div> 454</header> 455 456<!-- OmOmega Search Popup --> 457<div class="om-search-overlay" id="omSearchOverlay"></div> 458<div class="om-search-popup" id="omSearchPopup"> 459 <div class="om-search-popup-header"> 460 <h6>Kết quả cho <strong id="omSearchQuery"></strong></h6> 461 <button class="om-search-popup-close" id="omSearchClose">×</button> 462 </div> 463 <div class="om-search-results" id="omSearchResults"></div> 464 <div class="om-search-footer"> 465 <span><kbd>â</kbd> <kbd>â</kbd> Chá»n <kbd>Enter</kbd> Má» <kbd>Esc</kbd> Äóng</span> 466 <span>OmOmega Search</span> 467 </div> 468</div> 469 470<div class="modal modal-center fade" id="modal_download_app" tabindex="-1"> 471 <div class="modal-dialog"> 472 <div class="modal-content"> 473 <div class="modal-header"> 474 <h4 class="modal-title" id="myModalLabel">Tải ứng dụng <b 475 style="color: darkgreen; font-weight: bold;" href="#">OmOmega</b></h4> 476 <button type="button" class="close" data-dismiss="modal"> 477 <span aria-hidden="true">×</span> 478 </button> 479 </div> 480 <div class="modal-body"> 481 <div class="card"> 482 <h5>Quét mã QR Äá» tải ứng dụng (sá» dụng camera cá»§a Äiá»n thoại)</h5> 483 <!-- Nav tabs --> 484 <ul class="nav nav-tabs nav-tabs-danger nav-justified" role="tablist"> 485 <li class="nav-item"> 486 <a class="nav-link active" data-toggle="tab" href="#ios_store_link" role="tab">iOS</a> 487 </li> 488 <li class="nav-item"> 489 <a class="nav-link" data-toggle="tab" href="#android_store_link" role="tab">Android</a> 490 </li> 491 </ul> 492 493 <!-- Tab panes --> 494 <div class="card-body tab-content"> 495 <div class="tab-pane fade active show" id="ios_store_link"> 496 <h6>Quét mã QR hoặc truy cáºp <a style="color: darkgreen; font-weight: bold;" href="https://apps.apple.com/vn/app/omomega/id6612094647" target="_blank">App Store</a></h6> 497 <div class="card-body carousel-item active"> 498 <img src="/static/img/qr/mobile_app/omomega_ios_app_store.jpg" alt="OmOmega" width="289"> 499 </div> 500 </div> 501 <div class="tab-pane fade" id="android_store_link"> 502 <h6>Quét mã QR hoặc truy cáºp <a style="color: darkgreen; font-weight: bold;" href="https://play.google.com/store/apps/details?id=com.omomega.OmOmegaApp" target="_blank">Google Play</a></h6> 503 <div class="card-body carousel-item active"> 504 <img src="/static/img/qr/mobile_app/omomega_android_google_play.png" alt="OmOmega" width="289"> 505 </div> 506 </div> 507 </div> 508 </div> 509 </div> 510 <div class="modal-footer"> 511 <button type="button" class="btn btn-bold btn-pure btn-secondary" data-dismiss="modal">Äóng</button> 512 </div> 513 </div> 514 </div> 515</div> 516 517 518
518<script type="text/javascript"> 519 function om_login() { 520 url_path = window.location.pathname; 521 window.location.href = '/user/login?next=' + url_path 522 } 523 </script>
523 524 525<!-- OmOmega Search Script -->
526<script> 527(function() { 528 var omSearchData = []; 529 var omActiveIdx = -1; 530 var omPopupOpen = false; 531 532 // Load search data once 533 fetch('/static/data/json/om-search-data.json') 534 .then(function(r) { return r.json(); }) 535 .then(function(d) { omSearchData = d; }) 536 .catch(function(e) { console.warn('OmSearch: data load failed', e); }); 537 538 // Helper: normalize Vietnamese text for matching 539 function omNorm(s) { 540 return (s || '').toLowerCase() 541 .normalize('NFD').replace(/[\u0300-\u036f]/g, '') 542 .replace(/Ä/g, 'd').replace(/Ä/g, 'D'); 543 } 544 545 // Helper: highlight matching text in a string 546 function omHighlight(text, queryWords) { 547 if (!queryWords.length) return text; 548 var escaped = queryWords.map(function(w) { 549 return w.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); 550 }); 551 var re = new RegExp('(' + escaped.join('|') + ')', 'gi'); 552 return text.replace(re, '<mark>$1</mark>'); 553 } 554 555 // Search and filter data 556 function omDoSearch(query) { 557 var normQ = omNorm(query); 558 var words = normQ.split(/\s+/).filter(function(w) { return w.length > 0; }); 559 if (!words.length) return []; 560 561 var scored = []; 562 omSearchData.forEach(function(item) { 563 var normTitle = omNorm(item.title); 564 var normTokens = omNorm(item.tokens); 565 var normDesc = omNorm(item.description); 566 var allText = normTitle + ' ' + normTokens + ' ' + normDesc; 567 568 // All query words must match somewhere 569 var allMatch = words.every(function(w) { return allText.indexOf(w) >= 0; }); 570 if (!allMatch) return; 571 572 // Scoring: title match > token match > desc match 573 var score = 0; 574 words.forEach(function(w) { 575 if (normTitle.indexOf(w) >= 0) score += 10; 576 if (normTokens.indexOf(w) >= 0) score += 5; 577 if (normDesc.indexOf(w) >= 0) score += 2; 578 }); 579 // Exact title start bonus 580 if (normTitle.indexOf(normQ) === 0) score += 20; 581 582 scored.push({ item: item, score: score }); 583 }); 584 585 scored.sort(function(a, b) { return b.score - a.score; }); 586 return scored.map(function(s) { return s.item; }); 587 } 588 589 // Render results into popup 590 function omRenderResults(results, query) { 591 var container = document.getElementById('omSearchResults'); 592 var queryWords = query.split(/\s+/).filter(function(w) { return w.length > 0; }); 593 container.innerHTML = ''; 594 595 if (!results.length) { 596 container.innerHTML = '<div class="om-search-empty">' + 597 '<i class="ti-search"></i>' + 598 '<p>Không tìm thấy kết quả cho "' + query + '"</p></div>'; 599 return; 600 } 601 602 // Group by category 603 var groups = {}; 604 var catOrder = []; 605 results.forEach(function(item) { 606 var cat = item.category || 'Khác'; 607 if (!groups[cat]) { groups[cat] = []; catOrder.push(cat); } 608 groups[cat].push(item); 609 }); 610 611 var globalIdx = 0; 612 catOrder.forEach(function(cat) { 613 var label = document.createElement('div'); 614 label.className = 'om-search-category-label'; 615 label.textContent = cat; 616 container.appendChild(label); 617 618 groups[cat].forEach(function(item) { 619 var el = document.createElement('a'); 620 el.className = 'om-search-item'; 621 el.href = item.url; 622 el.setAttribute('data-idx', globalIdx); 623 el.innerHTML = 624 '<div class="om-search-item-icon"><i class="' + item.icon + '"></i></div>' + 625 '<div class="om-search-item-info">' + 626 '<div class="om-search-item-title">' + omHighlight(item.title, queryWords) + '</div>' + 627 '<div class="om-search-item-desc">' + omHighlight(item.description, queryWords) + '</div>' + 628 '</div>' + 629 '<span class="om-search-item-arrow"><i class="ti-angle-right"></i></span>'; 630 el.addEventListener('click', function(e) { 631 // Navigate on click (default <a> behavior) 632 omClosePopup(); 633 }); 634 container.appendChild(el); 635 globalIdx++; 636 }); 637 }); 638 } 639 640 // Open popup 641 function omOpenPopup(query) { 642 var results = omDoSearch(query); 643 document.getElementById('omSearchQuery').textContent = query;
644 omRenderResults(results, query); 645 646 document.getElementById('omSearchOverlay').classList.add('show'); 647 document.getElementById('omSearchPopup').classList.add('show'); 648 omActiveIdx = -1; 649 omPopupOpen = true; 650 } 651 652 // Close popup 653 function omClosePopup() { 654 document.getElementById('omSearchOverlay').classList.remove('show'); 655 document.getElementById('omSearchPopup').classList.remove('show'); 656 omActiveIdx = -1; 657 omPopupOpen = false; 658 } 659 660 // Keyboard navigation inside popup 661 function omNavigateResults(dir) { 662 var items = document.querySelectorAll('#omSearchResults .om-search-item'); 663 if (!items.length) return; 664 items.forEach(function(el) { el.classList.remove('active'); }); 665 omActiveIdx += dir; 666 if (omActiveIdx < 0) omActiveIdx = items.length - 1; 667 if (omActiveIdx >= items.length) omActiveIdx = 0; 668 items[omActiveIdx].classList.add('active'); 669 items[omActiveIdx].scrollIntoView({ block: 'nearest' }); 670 } 671 672 function omSelectActive() { 673 var items = document.querySelectorAll('#omSearchResults .om-search-item'); 674 if (omActiveIdx >= 0 && omActiveIdx < items.length) { 675 window.location.href = items[omActiveIdx].getAttribute('href'); 676 omClosePopup(); 677 } 678 } 679 680 // Bind events after DOM ready 681 document.addEventListener('DOMContentLoaded', function() { 682 var input = document.getElementById('om-search-input'); 683 if (!input) return; 684 685 // Handle placeholder visibility 686 var placeholder = input.parentElement.querySelector('.lookup-placeholder'); 687 688 input.addEventListener('focus', function() { 689 if (placeholder) placeholder.querySelector('span').style.opacity = '0'; 690 }); 691 input.addEventListener('blur', function() { 692 if (!this.value && placeholder) placeholder.querySelector('span').style.opacity = '1'; 693 }); 694 input.addEventListener('input', function() { 695 if (placeholder) { 696 placeholder.querySelector('span').style.opacity = this.value ? '0' : '1'; 697 } 698 }); 699 700 // Enter to search 701 input.addEventListener('keydown', function(e) { 702 if (e.key === 'Enter') { 703 e.preventDefault(); 704 var q = this.value.trim(); 705 if (q.length > 0) { 706 omOpenPopup(q); 707 this.blur(); 708 } 709 } 710 }); 711 712 // Global keyboard handler 713 document.addEventListener('keydown', function(e) { 714 if (!omPopupOpen) return; 715 if (e.key === 'Escape') { 716 e.preventDefault(); 717 omClosePopup(); 718 input.focus(); 719 } else if (e.key === 'ArrowDown') { 720 e.preventDefault(); 721 omNavigateResults(1); 722 } else if (e.key === 'ArrowUp') { 723 e.preventDefault(); 724 omNavigateResults(-1); 725 } else if (e.key === 'Enter' && omActiveIdx >= 0) { 726 e.preventDefault(); 727 omSelectActive(); 728 } 729 }); 730 731 // Close on overlay click 732 document.getElementById('omSearchOverlay').addEventListener('click', omClosePopup); 733 document.getElementById('omSearchClose').addEventListener('click', omClosePopup); 734 }); 735})(); 736</script>
736 737<!-- END Topbar --> 738 739 740<style> 741 .om-cal-wrapper { 742 padding: 10px; 743 background-color: #fcfcfc; 744 } 745 746 .om-cal-grid { 747 display: grid; 748 grid-template-columns: repeat(7, 1fr); 749 gap: 6px; 750 } 751 752 .om-cal-header-day { 753 text-align: center; 754 font-weight: 600; 755 color: #555; 756 padding-bottom: 8px; 757 font-size: 14px; 758 } 759 760 .om-cal-day { 761 border: 1px solid transparent; 762 border-radius: 8px; 763 padding: 6px; 764 text-align: center; 765 cursor: pointer; 766 min-height: 70px; 767 display: flex; 768 flex-direction: column; 769 align-items: center; 770 justify-content: center; 771 background-color: #ffffff; 772 box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); 773 transition: all 0.2s ease-in-out; 774 } 775 776 .om-cal-day:hover { 777 background-color: #f8f9fa; 778 transform: translateY(-2px); 779 box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); 780 } 781 782 .om-cal-day.is-today { 783 border: 3px solid #0ea89e; 784 box-shadow: 0 0 0 2px rgba(14, 168, 158, 0.25), 0 2px 6px rgba(14, 168, 158, 0.2); 785 } 786 787 /* OmOmega App Primary Style */ 788 .om-cal-day.is-weekend { 789 background-color: #FBCCCC; 790 } 791 792 .om-cal-day.is-holiday { 793 background-color: #FFA5A5; 794 } 795 796 .om-cal-gregorian { 797 font-size: 16px; 798 font-weight: bold; 799 color: #333; 800 line-height: 1.2; 801 } 802 803 .om-cal-lunar { 804 font-size: 11px; 805 color: #555; 806 margin-top: 2px; 807 } 808 809 .om-cal-bm { 810 font-size: 11px; 811 color: #007bff; 812 font-weight: bold; 813 text-transform: capitalize; 814 } 815 816 .om-cal-empty { 817 background: transparent; 818 box-shadow: none; 819 cursor: default; 820 } 821 822 .om-cal-empty:hover { 823 transform: none; 824 background: transparent; 825 box-shadow: none; 826 } 827 828 /* Bát Môn Wheel Styles */ 829 .om-bm-wheel { 830 max-height: 180px; 831 overflow-y: auto; 832 border: 1px solid #eee; 833 border-radius: 8px; 834 padding: 4px 0; 835 background: #fafafa; 836 scroll-behavior: smooth; 837 } 838 839 .om-bm-wheel::-webkit-scrollbar {
840 width: 6px; 841 } 842 843 .om-bm-wheel::-webkit-scrollbar-thumb { 844 background: #ccc; 845 border-radius: 4px; 846 } 847 848 .om-bm-wheel-item { 849 padding: 8px 12px; 850 border-bottom: 1px solid #f1f1f1; 851 text-align: center; 852 font-size: 14px; 853 color: #333; 854 } 855 856 .om-bm-wheel-item:last-child { 857 border-bottom: none; 858 } 859 860 .om-bm-wheel-item.active { 861 background-color: #e6f7ff; 862 font-weight: bold; 863 color: #007bff; 864 border-radius: 4px; 865 margin: 0 4px; 866 } 867 868 /* BM Meaning Card Styles */ 869 .om-bm-meaning-card { 870 width: 100%; 871 padding: 10px 12px; 872 margin-bottom: 10px; 873 background: #ffffff; 874 border: 1px solid #e8e8e8; 875 border-radius: 10px; 876 box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06); 877 } 878 879 .om-bm-meaning-label { 880 font-size: 11px; 881 font-weight: 600; 882 color: #888; 883 text-transform: uppercase; 884 letter-spacing: 0.5px; 885 margin-bottom: 4px; 886 } 887 888 .om-bm-meaning-header { 889 display: flex; 890 align-items: center; 891 justify-content: space-between; 892 margin-bottom: 4px; 893 } 894 895 .om-bm-meaning-title { 896 font-size: 15px; 897 font-weight: 700; 898 color: #007bff; 899 text-transform: capitalize; 900 } 901 902 .om-bm-meaning-window { 903 font-size: 12px; 904 color: #888; 905 white-space: nowrap; 906 } 907 908 .om-bm-meaning-text { 909 font-size: 13px; 910 color: #333; 911 line-height: 1.4; 912 margin: 0; 913 } 914 915 .om-bm-meaning-text.is-empty { 916 color: #aaa; 917 font-style: italic; 918 } 919</style> 920 921<div class="modal fade" id="modal_monthly_calendar" tabindex="-1" role="dialog" aria-hidden="true"> 922 <div class="modal-dialog modal-dialog-centered" style="max-width: 480px;" role="document"> 923 <div class="modal-content om-cal-wrapper"> 924 <div class="modal-header d-flex align-items-center justify-content-between pb-3 border-bottom-0"> 925 <button class="btn btn-sm btn-light" onclick="omCalPrevMonth()"><i class="fa fa-chevron-left"></i> 926 </button> 927 <div class="d-flex align-items-center"> 928 <select id="om_cal_month" class="form-control form-control-sm mx-1" 929 style="width: auto; font-weight: bold; cursor: pointer;" 930 onchange="omCalChangeSelect()"></select> 931 <select id="om_cal_year" class="form-control form-control-sm mx-1" 932 style="width: auto; font-weight: bold; cursor: pointer;" 933 onchange="omCalChangeSelect()"></select> 934 </div> 935 <div> 936 <button class="btn btn-sm btn-info" onclick="omCalGoToday()" title="Hôm nay"><i 937 class="fa fa-crosshairs"></i></button> 938 <button class="btn btn-sm btn-light ml-1" onclick="omCalNextMonth()"><i 939 class="fa fa-chevron-right"></i></button> 940 </div> 941 </div> 942 943 <div class="modal-body pt-0"> 944 <div class="om-cal-grid" style="padding-bottom: 0;"> 945 <div class="om-cal-header-day">Mo</div> 946 <div class="om-cal-header-day">Tu</div> 947 <div class="om-cal-header-day">We</div> 948 <div class="om-cal-header-day">Th</div> 949 <div class="om-cal-header-day">Fr</div> 950 <div class="om-cal-header-day">Sa</div> 951 <div class="om-cal-header-day">Su</div> 952 </div> 953 <div class="om-cal-grid" id="om_cal_days_container" style="padding-top: 0;"></div> 954 955 </div> 956 </div> 957 </div> 958</div> 959 960<div class="modal fade" id="modal_om_cal_day_details" tabindex="-1" role="dialog" aria-hidden="true"> 961 <div class="modal-dialog modal-dialog-centered" style="max-width: 360px;" role="document"> 962 <div class="modal-content"> 963 <div class="modal-header pb-2 border-bottom-0"> 964 <h5 class="modal-title w-100 text-center font-weight-bold">Chi tiết ngà y</h5> 965 </div> 966 <div class="modal-body pt-1"> 967 <p class="mb-1"><strong>Thứ:</strong> <span id="om_cal_detail_weekday"></span></p> 968 <p class="mb-1"><strong>Ngà y dương lá»ch:</strong> <span id="om_cal_detail_gregorian"></span></p> 969 <p class="mb-1"><strong>Ngà y âm lá»ch:</strong> <span id="om_cal_detail_lunar"></span></p> 970 971 972 </div> 973 <div class="modal-footer justify-content-center border-top-0 pt-0"> 974 <button type="button" class="btn btn-primary" id="btn_om_cal_add_task" style="display: none;">Äầu viá»c</button> 975 <button type="button" class="btn btn-secondary" data-dismiss="modal">Äóng</button> 976 </div> 977 </div> 978 </div> 979</div> 980
981<script> 982 const omCalBmNames = ['hưu', 'sanh', 'thương', 'Äá»', 'kiá»n', 'tá»', 'kinh', 'khai']; 983 const omCalBmOffsets = [-1, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 0, 0]; 984 const omCalGregHolidays = ["1/1", "30/4", "1/5", "1/9", "2/9"]; 985 const omCalLunarHolidays = ["1/1", "2/1", "3/1", "10/3"]; 986 const omCalWeekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; 987 const omCalBmTimeByMonths = [[-1, -1], [0, 30], [0, 40], [0, 50], [1, 0], [1, 10], [1, 0], [0, 50], [0, 40], [0, 30], [0, 20], [0, 10], [0, 20]]; 988 989 // BM Meaning store â fetched once from /omapi/bm-meanings/ and cached 990 let omCalBmMeanings = {}; 991 let omCalBmMeaningsLoaded = false; 992 let omCalBmMeaningTimer = null; 993 994 function omCalFetchBmMeanings() { 995 fetch('/omapi/bm-meanings/') 996 .then(r => r.json()) 997 .then(data => { 998 if (data.status === 1 && data.items) { 999 omCalBmMeanings = data.items; 1000 omCalBmMeaningsLoaded = true; 1001 omCalUpdateBmMeaningCard(); 1002 } 1003 }) 1004 .catch(() => {}); 1005 } 1006 1007 /** 1008 * Compute the current BM hour segment for right now: 1009 * returns {dayGate, hourGate, startStr, endStr} 1010 */ 1011 function omCalGetCurrentBmSegment() { 1012 let now = new Date(); 1013 let solarD = Solar.fromYmd(now.getFullYear(), now.getMonth() + 1, now.getDate()); 1014 let lunarD = solarD.getLunar(); 1015 let lDay = lunarD.getDay(); 1016 let absLMonth = Math.abs(lunarD.getMonth()); 1017 1018 // Day gate index 1019 let bmDayIndex = (omCalBmOffsets[absLMonth] + lDay - 1) % 8; 1020 let dayGate = omCalBmNames[bmDayIndex]; 1021 1022 // Hour segment 1023 let startMins = omCalBmTimeByMonths[absLMonth][0] * 60 + omCalBmTimeByMonths[absLMonth][1]; 1024 let currentMins = now.getHours() * 60 + now.getMinutes(); 1025 let dist = (currentMins - startMins + 1440) % 1440; 1026 let hourIndex = Math.floor(dist / 120) % 12; 1027 1028 let hourGate = omCalBmNames[(bmDayIndex + hourIndex) % 8]; 1029 1030 let segStart = (startMins + hourIndex * 120 + 1440) % 1440; 1031 let segEnd = (segStart + 120) % 1440; 1032 let h1 = Math.floor(segStart / 60).toString().padStart(2, '0'); 1033 let m1 = (segStart % 60).toString().padStart(2, '0'); 1034 let h2 = Math.floor(segEnd / 60).toString().padStart(2, '0'); 1035 let m2 = (segEnd % 60).toString().padStart(2, '0'); 1036 1037 return { 1038 dayGate: dayGate, 1039 hourGate: hourGate, 1040 startStr: `${h1}:${m1}`, 1041 endStr: `${h2}:${m2}` 1042 }; 1043 } 1044 1045 function omCalUpdateBmMeaningCard() { 1046 let titleEl = document.getElementById('om_cal_bm_meaning_title'); 1047 if (!titleEl) return; // BM not enabled for this user 1048 1049 let seg = omCalGetCurrentBmSegment(); 1050 1051 // Title: capitalize first letter of dayGate + space + hourGate 1052 let title = seg.dayGate.charAt(0).toUpperCase() + seg.dayGate.slice(1) + ' ' + seg.hourGate; 1053 titleEl.innerText = title; 1054 1055 document.getElementById('om_cal_bm_meaning_window').innerText = `${seg.startStr} â ${seg.endStr}`; 1056 1057 let textEl = document.getElementById('om_cal_bm_meaning_text'); 1058 let key = `${seg.dayGate}|${seg.hourGate}`; 1059 let meaning = omCalBmMeanings[key]; 1060 1061 if (meaning && meaning.trim()) { 1062 textEl.innerText = meaning; 1063 textEl.classList.remove('is-empty'); 1064 } else if (omCalBmMeaningsLoaded) { 1065 textEl.innerText = 'Chưa có ná»i dung'; 1066 textEl.classList.add('is-empty'); 1067 } else { 1068 textEl.innerText = 'Äang tải...'; 1069 textEl.classList.add('is-empty'); 1070 } 1071 } 1072 1073 // Start BM Meaning auto-update timer and fetch on modal show 1074 document.addEventListener('DOMContentLoaded', () => { 1075 let bmModal = document.getElementById('modal_monthly_calendar'); 1076 if (bmModal) { 1077 $(bmModal).on('shown.bs.modal', () => { 1078 // Fetch meanings if not loaded yet 1079 if (!omCalBmMeaningsLoaded) omCalFetchBmMeanings(); 1080 // Immediately update the card 1081 omCalUpdateBmMeaningCard(); 1082 // Start 1-minute ticker 1083 if (omCalBmMeaningTimer) clearInterval(omCalBmMeaningTimer); 1084 omCalBmMeaningTimer = setInterval(omCalUpdateBmMeaningCard, 60000); 1085 }); 1086 $(bmModal).on('hidden.bs.modal', () => { 1087 // Stop ticker when modal is closed 1088 if (omCalBmMeaningTimer) { 1089 clearInterval(omCalBmMeaningTimer); 1090 omCalBmMeaningTimer = null; 1091 } 1092 }); 1093 } 1094 }); 1095 1096 let omCalCurYear = new Date().getFullYear(); 1097 let omCalCurMonth = new Date().getMonth() + 1; 1098 1099 // Initialize Dropdowns 1100 document.addEventListener("DOMContentLoaded", () => { 1101 let mSelect = document.getElementById("om_cal_month"); 1102 for (let i = 1; i <= 12; i++) { 1103 mSelect.add(new Option("Month " + i, i)); 1104 } 1105 let ySelect = document.getElementById("om_cal_year"); 1106 for (let i = 1900; i <= 2100; i++) { 1107 ySelect.add(new Option(i, i)); 1108 } 1109 }); 1110 1111 function omCalCheckLunarHoliday(ld, lm, y, m, d) { 1112 if (omCalLunarHolidays.includes(`${ld}/${Math.abs(lm)}
1112`)) return true; 1113 if (Math.abs(lm) === 12) { 1114 let nextD = new Date(y, m - 1, d + 1); 1115 let nextSolar = Solar.fromYmd(nextD.getFullYear(), nextD.getMonth() + 1, nextD.getDate()); 1116 if (Math.abs(nextSolar.getLunar().getMonth()) !== 12) return true; 1117 } 1118 return false; 1119 } 1120 1121 function renderOmCalendar(year, month) { 1122 omCalCurYear = year; 1123 omCalCurMonth = month; 1124 document.getElementById("om_cal_month").value = month; 1125 document.getElementById("om_cal_year").value = year; 1126 1127 let container = document.getElementById("om_cal_days_container"); 1128 container.innerHTML = ""; 1129 1130 let firstDay = new Date(year, month - 1, 1); 1131 let daysInMonth = new Date(year, month, 0).getDate(); 1132 1133 let offset = firstDay.getDay() - 1; 1134 if (offset < 0) offset = 6; 1135 1136 let today = new Date(); 1137 1138 for (let i = 0; i < offset; i++) { 1139 container.innerHTML += `<div class="om-cal-day om-cal-empty"></div>`; 1140 } 1141 1142 for (let i = 1; i <= daysInMonth; i++) { 1143 let curD = new Date(year, month - 1, i); 1144 let solarD = Solar.fromYmd(year, month, i); 1145 let lunarD = solarD.getLunar(); 1146 let lDay = lunarD.getDay(); 1147 let lMonth = lunarD.getMonth(); 1148 let absLMonth = Math.abs(lMonth); 1149 1150 let isToday = (year === today.getFullYear() && month === today.getMonth() + 1 && i === today.getDate()); 1151 let isWeekend = (curD.getDay() === 0 || curD.getDay() === 6); 1152 let isHol = omCalGregHolidays.includes(`${i}/${month}`) || omCalCheckLunarHoliday(lDay, absLMonth, year, month, i); 1153 1154 let bmIndex = (omCalBmOffsets[absLMonth] + lDay - 1) % 8; 1155 let bmName = omCalBmNames[bmIndex]; 1156 1157 let classes = "om-cal-day"; 1158 if (isToday) classes += " is-today"; 1159 if (isHol) classes += " is-holiday"; 1160 else if (isWeekend) classes += " is-weekend"; 1161 1162 let lStr = lMonth < 0 ? `${lDay}/${absLMonth}*` : `${lDay}/${absLMonth}`; 1163 1164 container.innerHTML += ` 1165 <div class="${classes}" onclick="omCalShowDetails(${year}, ${month}, ${i}, ${lDay}, ${absLMonth}, ${curD.getDay()}, '${bmName}', ${bmIndex}, '${lStr}')"> 1166 <span class="om-cal-gregorian">${i}</span> 1167 <span class="om-cal-lunar">${lStr}</span> 1168 1169 </div> 1170 `; 1171 } 1172 } 1173 1174 function omCalPrevMonth() { 1175 omCalCurMonth--; 1176 if (omCalCurMonth < 1) { 1177 omCalCurMonth = 12; 1178 omCalCurYear--; 1179 } 1180 renderOmCalendar(omCalCurYear, omCalCurMonth); 1181 } 1182 1183 function omCalNextMonth() { 1184 omCalCurMonth++; 1185 if (omCalCurMonth > 12) { 1186 omCalCurMonth = 1; 1187 omCalCurYear++; 1188 } 1189 renderOmCalendar(omCalCurYear, omCalCurMonth); 1190 } 1191 1192 function omCalGoToday() { 1193 let t = new Date(); 1194 renderOmCalendar(t.getFullYear(), t.getMonth() + 1); 1195 } 1196 1197 function omCalChangeSelect() { 1198 renderOmCalendar(parseInt(document.getElementById("om_cal_year").value), parseInt(document.getElementById("om_cal_month").value)); 1199 } 1200 1201 function omCalShowDetails(y, m, d, lDay, absLMonth, wDay, bmName, bmDayIndex, lStr) { 1202 // Set basic info 1203 document.getElementById('om_cal_detail_weekday').innerText = omCalWeekdays[wDay]; 1204 document.getElementById('om_cal_detail_gregorian').innerText = `${d}/${m}/${y}`; 1205 1206 let lunarEl = document.getElementById('om_cal_detail_lunar'); 1207 let wheelEl = document.getElementById('om_cal_detail_bm_wheel'); 1208 1209 if (wheelEl) { 1210 // User has Bát Môn enabled 1211 lunarEl.innerText = `${lStr}, ${bmName}`; 1212 1213 // Generate the hour wheel 1214 const startMins = omCalBmTimeByMonths[absLMonth][0] * 60 + omCalBmTimeByMonths[absLMonth][1]; 1215 1216 let wheelHtml = ''; 1217 let now = new Date(); 1218 let isExactlyToday = (y === now.getFullYear() && m === (now.getMonth() + 1) && d === now.getDate()); 1219 let currentMins = now.getHours() * 60 + now.getMinutes(); 1220 1221 for (let i = 0; i < 12; i++) { 1222 let curStart = (startMins + i * 120 + 1440) % 1440; 1223 let curEnd = (curStart + 120) % 1440; 1224 let h1 = Math.floor(curStart / 60).toString().padStart(2, '0'); 1225 let m1 = (curStart % 60).toString().padStart(2, '0'); 1226 let h2 = Math.floor(curEnd / 60).toString().padStart(2, '0'); 1227 let m2 = (curEnd % 60).toString().padStart(2, '0');
1228 let bmStr = omCalBmNames[(bmDayIndex + i) % 8]; 1229 1230 // Highlight active time segment if the selected date is today 1231 let isActive = false; 1232 if (isExactlyToday) { 1233 let dist = (currentMins - startMins + 1440) % 1440; 1234 let currentHourIndex = Math.floor(dist / 120) % 12; 1235 if (currentHourIndex === i) { 1236 isActive = true; 1237 } 1238 } 1239 1240 let activeClass = isActive ? 'active' : ''; 1241 wheelHtml += `<div class="om-bm-wheel-item ${activeClass}">${h1}:${m1} - ${h2}:${m2} : <b class="text-uppercase">${bmStr}</b></div>`; 1242 } 1243 wheelEl.innerHTML = wheelHtml; 1244 1245 // Auto-scroll the wheel to the active item 1246 setTimeout(() => { 1247 let activeItem = wheelEl.querySelector('.active'); 1248 if (activeItem) { 1249 activeItem.scrollIntoView({behavior: 'smooth', block: 'center'}); 1250 } 1251 }, 200); 1252 1253 } else { 1254 // User does not have Bát Môn enabled 1255 lunarEl.innerText = `${lStr}`; 1256 } 1257 1258 // Handle "Thêm Äầu viá»c" button visibility 1259 let btnAdd = document.getElementById('btn_om_cal_add_task'); 1260 let selectedDate = new Date(y, m - 1, d); 1261 let todayDate = new Date(); 1262 todayDate.setHours(0, 0, 0, 0); 1263 1264 if (selectedDate >= todayDate) { 1265 btnAdd.style.display = 'inline-block'; 1266 btnAdd.onclick = function () { 1267 // Hide both modals and redirect (or trigger your custom web task creation modal here) 1268 $('#modal_om_cal_day_details').modal('hide'); 1269 $('#modal_monthly_calendar').modal('hide'); 1270 1271 // Currently redirects to /omtask/ passing the date. Adjust this to your add-task function if needed. 1272 window.location.href = `/omtask/daily/?date=${d.toString().padStart(2, '0')}/${m.toString().padStart(2, '0')}/${y}`; 1273 }; 1274 } else { 1275 btnAdd.style.display = 'none'; 1276 } 1277 1278 $('#modal_om_cal_day_details').modal('show'); 1279 } 1280</script>
vendor: 1 bytes, line 1280
1280
1281<script> 1282 function openOmCalendarModal() { 1283 let t = new Date(); 1284 renderOmCalendar(t.getFullYear(), t.getMonth() + 1); 1285 $('#modal_monthly_calendar').modal('show'); 1286 } 1287</script>
1287 1288 <!-- END Topbar --> 1289 1290 <!-- Main container --> 1291 <main class="main-container"> 1292 <div class="main-content"> 1293 <div class="omdoc-home" id="omdoc-home"> 1294 1295 <!-- Hero Section --> 1296 <div class="omdoc-home__hero"> 1297 <div class="omdoc-home__icon"> 1298 <i class="ti-book"></i> 1299 </div> 1300 <h1 class="omdoc-home__title"><span>omDoc</span></h1> 1301 <p class="omdoc-home__subtitle"> 1302 OmOmega's document & knowledge center â explore system guides and level up your programming skills 1303 </p> 1304 </div> 1305 1306 <!-- Category Cards --> 1307 <div class="omdoc-home__grid"> 1308 1309 <!-- Card 1: Tà i liá»u OmRadio (IoT/Device-oriented) --> 1310 <a href="/omdoc/omradio/" class="omdoc-home__card omdoc-home__card--iot" id="omdoc-card-omradio"> 1311 <div class="omdoc-home__card-icon"> 1312 <i class="ti-plug"></i> 1313 </div> 1314 <h2 class="omdoc-home__card-title">OmRadio documentation</h2> 1315 <p class="omdoc-home__card-desc"> 1316 Usage guides, technical notes and updates for the OmIoT, OmHub devices and the OmRadio hardware ecosystem. 1317 </p> 1318 <span class="omdoc-home__card-btn"> 1319 Explore <i class="ti-arrow-right"></i> 1320 </span> 1321 </a> 1322 1323 <!-- Card 2: Kiến thức Python má» rá»ng --> 1324 <a href="/omdoc/python/" class="omdoc-home__card omdoc-home__card--python" id="omdoc-card-python"> 1325 <div class="omdoc-home__card-icon"> 1326 <i class="ti-desktop"></i> 1327 </div> 1328 <h2 class="omdoc-home__card-title">Extended Python knowledge</h2> 1329 <p class="omdoc-home__card-desc"> 1330 Improve your Python programming skills; explore libraries, frameworks and advanced techniques for software developers. 1331 </p> 1332 <span class="omdoc-home__card-btn"> 1333 Learn more <i class="ti-arrow-right"></i> 1334 </span> 1335 </a> 1336 1337 <!-- Card 3: omDoc English Study --> 1338 <a href="/omdoc/ielts-study/" class="omdoc-home__card omdoc-home__card--ielts" id="omdoc-card-ielts"> 1339 <div class="omdoc-home__card-icon"> 1340 <i class="ti-pencil-alt"></i> 1341 </div> 1342 <h2 class="omdoc-home__card-title">omDoc English Study</h2> 1343 <p class="omdoc-home__card-desc"> 1344 Practice and improve your English â Vocabulary, Reading, Listening, Writing, Speaking. An 18-unit program from 4.0 to 6.5. 1345 </p> 1346 <span class="omdoc-home__card-btn"> 1347 Get started <i class="ti-arrow-right"></i> 1348 </span> 1349 </a> 1350 1351 <!-- Card 4: Health Exercise --> 1352 <a href="/omdoc/health-exercise/" class="omdoc-home__card omdoc-home__card--health" id="omdoc-card-health"> 1353 <div class="omdoc-home__health-visual" aria-hidden="true"> 1354 <img src="/static/media/health_images/tiger.png" alt=""> 1355 <span class="omdoc-home__health-orbit"></span> 1356 </div> 1357 <span class="omdoc-home__card-kicker">Today's Practice</span> 1358 <h2 class="omdoc-home__card-title">Health Practice</h2> 1359 <p class="omdoc-home__card-desc"> 1360 Breath-coordinated exercises with the Five Animal Frolics â Tiger, Deer, Bear, Monkey, Crane. Sessions include guided breathing and progress tracking. 1361 </p>
1362 <span class="omdoc-home__card-btn"> 1363 Get started <i class="ti-arrow-right"></i> 1364 </span> 1365 </a> 1366 1367 <!-- Card 5: Agriculture Research --> 1368 <a href="/omdoc/agriculture/" class="omdoc-home__card omdoc-home__card--agriculture" id="omdoc-card-agriculture"> 1369 <div class="omdoc-home__card-icon"> 1370 <i class="ti-leaf"></i> 1371 </div> 1372 <h2 class="omdoc-home__card-title">Agriculture AI/IoT Research</h2> 1373 <p class="omdoc-home__card-desc"> 1374 Nghiên cứu ứng dụng trà tuá» nhân tạo và IoT trong nông nghiá»p, các kỹ thuáºt tá»i ưu hóa cây trá»ng và công nghá» thông minh. 1375 </p> 1376 <span class="omdoc-home__card-btn"> 1377 Explore <i class="ti-arrow-right"></i> 1378 </span> 1379 </a> 1380 1381 </div> 1382 1383 <!-- Stats Row --> 1384 <div class="omdoc-home__stats"> 1385 <div class="omdoc-home__stat"> 1386 <div class="omdoc-home__stat-number">53</div> 1387 <div class="omdoc-home__stat-label">Articles</div> 1388 </div> 1389 <div class="omdoc-home__stat"> 1390 <div class="omdoc-home__stat-number">11</div> 1391 <div class="omdoc-home__stat-label">Topics</div> 1392 </div> 1393 <div class="omdoc-home__stat"> 1394 <div class="omdoc-home__stat-number">7</div> 1395 <div class="omdoc-home__stat-label">Documents</div> 1396 </div> 1397 </div> 1398 1399 </div> 1400 </div> 1401 1402 <!-- Footer --> 1403 1404 1405 1406<!-- Footer --> 1407<footer class="site-footer"> 1408 <div class="row"> 1409 <div class="col-6"> 1410 <p class="text-center text-md-left"><b>© 2022 </b><a href="/about/contact/"><b style="color: #5b880c;">OmOmega</b></a> | 1411 Online: <b>3</b> | Visits: <b>1,260,644</b></p> 1412 </div> 1413 1414 <div class="col-6"> 1415 <ul class="nav nav-primary nav-dotted nav-dot-separated justify-content-center justify-content-md-end"> 1416 <li class="nav-item"> 1417 <a class="nav-link" href="#" target="_blank" data-toggle="modal" data-target="#modal_download_app">OmOmega Mobile</a> 1418 </li> 1419 <li class="nav-item"> 1420 <a class="nav-link" href="/rules/">Terms</a> 1421 </li> 1422 <li class="nav-item"> 1423 <a class="nav-link" href="/about/contact/">Contact</a> 1424 </li> 1425 </ul> 1426 </div> 1427 </div> 1428</footer> 1429<!-- END Footer --> 1430 <!-- END Footer --> 1431 </main> 1432 <!-- END Main container --> 1433 1434 1435 1436 <!-- Scripts --> 1437
1437<script src="/static/js/core.min.js" ></script>
1437 1438
1438<script src="/static/js/app.min.js"></script>
1438 1439
1439<script src="/static/js/script.min.js"></script>
1439 1440
1440<script src="/static/vendor/toastr/js/toastr.min.js"></script>
1440 1441 1442 1443 1444 1445 1446</body> 1447</html> 1448
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.