From dd1b77f1c3cac96ce744552d3cbcc70a94048023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=A4=80=ED=9D=A0?= Date: Tue, 18 Nov 2025 16:54:55 +0900 Subject: [PATCH] dbmsv4 init...1 --- .gitignore | 17 + LICENSE | 22 + README.md | 68 ++ app/Config/App.php | 202 +++++ app/Config/Autoload.php | 92 ++ app/Config/Boot/development.php | 34 + app/Config/Boot/production.php | 25 + app/Config/Boot/testing.php | 38 + app/Config/CURLRequest.php | 20 + app/Config/Cache.php | 162 ++++ app/Config/Constants.php | 535 +++++++++++ app/Config/ContentSecurityPolicy.php | 176 ++++ app/Config/Cookie.php | 107 +++ app/Config/Cors.php | 105 +++ app/Config/Database.php | 203 +++++ app/Config/DocTypes.php | 43 + app/Config/Email.php | 121 +++ app/Config/Encryption.php | 92 ++ app/Config/Events.php | 55 ++ app/Config/Exceptions.php | 106 +++ app/Config/Feature.php | 37 + app/Config/Filters.php | 113 +++ app/Config/ForeignCharacters.php | 12 + app/Config/Format.php | 64 ++ app/Config/Generators.php | 44 + app/Config/Honeypot.php | 42 + app/Config/Images.php | 31 + app/Config/Kint.php | 63 ++ app/Config/Logger.php | 151 ++++ app/Config/Migrations.php | 50 ++ app/Config/Mimes.php | 534 +++++++++++ app/Config/Modules.php | 82 ++ app/Config/Optimize.php | 30 + app/Config/Pager.php | 39 + app/Config/Paths.php | 75 ++ app/Config/Publisher.php | 28 + app/Config/Routes.php | 307 +++++++ app/Config/Routing.php | 140 +++ app/Config/Security.php | 86 ++ app/Config/Services.php | 111 +++ app/Config/Session.php | 127 +++ app/Config/Toolbar.php | 122 +++ app/Config/UserAgents.php | 252 ++++++ app/Config/Validation.php | 44 + app/Config/View.php | 62 ++ app/Controllers/AbstractCRUDController.php | 100 +++ app/Controllers/AbstractWebController.php | 162 ++++ app/Controllers/Admin/AdminController.php | 35 + .../Admin/Customer/AccountController.php | 229 +++++ .../Admin/Customer/ClientController.php | 238 +++++ .../Admin/Customer/CustomerController.php | 20 + app/Controllers/Admin/Home.php | 37 + app/Controllers/Admin/MylogController.php | 211 +++++ app/Controllers/Admin/UserController.php | 213 +++++ app/Controllers/Auth/AuthController.php | 75 ++ app/Controllers/Auth/GoogleController.php | 55 ++ app/Controllers/Auth/LocalController.php | 55 ++ app/Controllers/BaseController.php | 58 ++ app/Controllers/CLI/Collector.php | 57 ++ app/Controllers/CommonController.php | 271 ++++++ app/Controllers/Home.php | 11 + app/DTOs/Auth/AuthDTO.php | 14 + app/DTOs/Auth/GoogleDTO.php | 25 + app/DTOs/Auth/LocalDTO.php | 27 + app/DTOs/CommonDTO.php | 26 + app/DTOs/Customer/AccountDTO.php | 29 + app/DTOs/MylogDTO.php | 22 + app/DTOs/UserDTO.php | 39 + app/Database/Migrations/.gitkeep | 0 app/Database/Seeds/.gitkeep | 0 app/Database/traffic_test1.sql | 156 ++++ app/Database/user.sql | 62 ++ app/Entities/BoardEntity.php | 17 + app/Entities/CommonEntity.php | 48 + app/Entities/Customer/AccountEntity.php | 25 + app/Entities/Customer/ClientEntity.php | 49 + app/Entities/Customer/CouponEntity.php | 25 + app/Entities/Customer/CustomerEntity.php | 13 + app/Entities/Customer/PointEntity.php | 25 + app/Entities/Customer/ServiceEntity.php | 76 ++ app/Entities/Equipment/EquipmentEntity.php | 13 + app/Entities/Equipment/LineEntity.php | 16 + app/Entities/Equipment/ServerEntity.php | 49 + app/Entities/Equipment/ServerPartEntity.php | 61 ++ app/Entities/MylogEntity.php | 13 + app/Entities/Part/CPUEntity.php | 25 + app/Entities/Part/CSEntity.php | 26 + app/Entities/Part/DISKEntity.php | 29 + app/Entities/Part/IPEntity.php | 25 + app/Entities/Part/PartEntity.php | 34 + app/Entities/Part/RAMEntity.php | 25 + app/Entities/Part/SOFTWAREEntity.php | 25 + app/Entities/Part/SWITCHEntity.php | 17 + app/Entities/PaymentEntity.php | 65 ++ app/Entities/UserEntity.php | 86 ++ app/Entities/UserSNSEntity.php | 30 + app/Filters/.gitkeep | 0 app/Filters/AuthFilter.php | 60 ++ app/Forms/Auth/GoogleForm.php | 25 + app/Forms/Auth/LocalForm.php | 30 + app/Forms/CollectorForm.php | 46 + app/Forms/CommonForm.php | 196 ++++ app/Forms/Customer/AccountForm.php | 39 + app/Forms/MylogForm.php | 33 + app/Forms/UserForm.php | 51 ++ app/Helpers/.gitkeep | 0 app/Helpers/AuthHelper.php | 23 + app/Helpers/CollectorHelper.php | 32 + app/Helpers/CommonHelper.php | 293 ++++++ app/Helpers/Customer/AccountHelper.php | 29 + app/Helpers/MylogHelper.php | 13 + app/Helpers/UserHelper.php | 43 + app/Language/.gitkeep | 0 app/Language/en/Auth/Local.php | 8 + app/Language/en/Board.php | 25 + app/Language/en/Customer/Account.php | 29 + app/Language/en/Customer/Client.php | 31 + app/Language/en/Customer/Coupon.php | 18 + app/Language/en/Customer/Point.php | 18 + app/Language/en/Customer/Service.php | 48 + app/Language/en/Equipment/Line.php | 25 + app/Language/en/Equipment/Server.php | 62 ++ app/Language/en/Equipment/ServerPart.php | 42 + app/Language/en/Mylog.php | 14 + app/Language/en/Part/CPU.php | 18 + app/Language/en/Part/CS.php | 28 + app/Language/en/Part/DISK.php | 19 + app/Language/en/Part/IP.php | 22 + app/Language/en/Part/RAM.php | 18 + app/Language/en/Part/SOFTWARE.php | 18 + app/Language/en/Part/SWITCH.php | 20 + app/Language/en/Payment.php | 33 + app/Language/en/User.php | 31 + app/Language/en/Validation.php | 4 + app/Libraries/.gitkeep | 0 app/Libraries/AuthContext.php | 137 +++ app/Libraries/CommonLibrary.php | 23 + app/Libraries/MySocket/GoogleSocket/API.php | 128 +++ app/Libraries/MySocket/GoogleSocket/CURL.php | 171 ++++ .../MySocket/GoogleSocket/GoogleSocket.php | 75 ++ app/Libraries/MySocket/MySocket.php | 91 ++ app/Libraries/MySocket/WebSocket.php | 48 + app/Libraries/MyStorage/FileStorage.php | 111 +++ app/Libraries/OperationContext.php | 21 + app/Libraries/PipelineStep.php | 50 ++ app/Libraries/PipelineStepInterface.php | 16 + app/Libraries/SNMPLibrary.php | 37 + app/Models/.gitkeep | 0 app/Models/BoardModel.php | 54 ++ app/Models/CommonModel.php | 86 ++ app/Models/Customer/AccountModel.php | 32 + app/Models/Customer/ClientModel.php | 71 ++ app/Models/Customer/CouponModel.php | 53 ++ app/Models/Customer/CustomerModel.php | 44 + app/Models/Customer/PointModel.php | 53 ++ app/Models/Customer/ServiceModel.php | 88 ++ app/Models/Equipment/EquipmentModel.php | 41 + app/Models/Equipment/LineModel.php | 49 + app/Models/Equipment/ServerModel.php | 100 +++ app/Models/Equipment/ServerPartModel.php | 65 ++ app/Models/MylogModel.php | 27 + app/Models/Part/CPUModel.php | 29 + app/Models/Part/CSModel.php | 58 ++ app/Models/Part/DISKModel.php | 30 + app/Models/Part/IPModel.php | 59 ++ app/Models/Part/PartModel.php | 42 + app/Models/Part/RAMModel.php | 29 + app/Models/Part/SOFTWAREModel.php | 29 + app/Models/Part/SWITCHModel.php | 45 + app/Models/PaymentModel.php | 67 ++ app/Models/UserModel.php | 30 + app/Models/UserSNSModel.php | 56 ++ app/Services/Auth/AuthService.php | 118 +++ app/Services/Auth/GoogleService.php | 67 ++ app/Services/Auth/LocalService.php | 59 ++ app/Services/CommonService.php | 320 +++++++ app/Services/Customer/AccountService.php | 101 +++ app/Services/MylogService.php | 105 +++ app/Services/UserService.php | 111 +++ app/Steps/CommonStep.php | 13 + app/Steps/TrafficRegistration.php | 18 + app/ThirdParty/.gitkeep | 0 app/Traits/FileTrait.php | 62 ++ app/Traits/ImageTrait.php | 114 +++ app/Traits/LogTrait.php | 46 + app/Traits/UtilTrait.php | 170 ++++ app/Views/.htaccess | 6 + app/Views/Common.php | 15 + app/Views/Pagers/bootstrap_full.php | 35 + app/Views/Pagers/bootstrap_simple.php | 17 + app/Views/admin/api/index.php | 148 +++ app/Views/admin/create_form.php | 22 + app/Views/admin/download.php | 17 + app/Views/admin/index.php | 58 ++ app/Views/admin/modify_form.php | 22 + app/Views/admin/traffic/dashboard.php | 287 ++++++ app/Views/admin/view.php | 17 + app/Views/admin/welcome.php | 12 + app/Views/auth/login_form.php | 24 + app/Views/errors/cli/error_404.php | 7 + app/Views/errors/cli/error_exception.php | 65 ++ app/Views/errors/cli/production.php | 5 + app/Views/errors/html/debug.css | 190 ++++ app/Views/errors/html/debug.js | 116 +++ app/Views/errors/html/error_404.php | 84 ++ app/Views/errors/html/error_exception.php | 430 +++++++++ app/Views/errors/html/production.php | 25 + app/Views/index.html | 11 + app/Views/layouts/admin.php | 30 + app/Views/layouts/admin/bottom.php | 4 + app/Views/layouts/admin/left_menu.php | 13 + app/Views/layouts/admin/left_menu/base.php | 12 + app/Views/layouts/admin/top.php | 36 + app/Views/layouts/empty.php | 30 + app/Views/layouts/front.php | 30 + app/Views/layouts/front/bottom.php | 5 + app/Views/layouts/front/left_menu.php | 2 + app/Views/layouts/front/top.php | 41 + .../templates/admin/form_content_bottom.php | 0 .../templates/admin/form_content_top.php | 2 + .../templates/admin/index_content_bottom.php | 57 ++ .../templates/admin/index_content_filter.php | 13 + .../templates/admin/index_content_top.php | 12 + app/Views/templates/admin/index_footer.php | 3 + app/Views/templates/admin/index_header.php | 7 + app/Views/templates/common/modal_fetch_v1.php | 120 +++ app/Views/templates/common/modal_fetch_v2.php | 163 ++++ app/Views/templates/common/modal_iframe.php | 79 ++ app/Views/templates/front/index_footer.php | 0 app/Views/templates/front/index_header.php | 87 ++ app/Views/welcome_message.php | 331 +++++++ builds | 125 +++ composer.json | 48 + env | 69 ++ phpunit.xml.dist | 63 ++ preload.php | 110 +++ public/.htaccess | 49 + public/css/admin.css | 81 ++ public/css/admin/form.css | 40 + public/css/admin/index.css | 161 ++++ public/css/admin/left_menu.css | 56 ++ public/css/admin/member_link.css | 17 + public/css/admin/resizeTable.css | 67 ++ public/css/admin/server_partinfo.css | 56 ++ public/css/common/style.css | 55 ++ public/css/empty.css | 11 + public/css/front.css | 81 ++ public/css/front/copyright.css | 29 + public/css/front/form.css | 34 + public/css/front/index.css | 157 ++++ public/css/front/left_menu.css | 56 ++ public/css/front/login.css | 80 ++ public/css/front/member_link.css | 17 + public/favicon.ico | Bin 0 -> 5430 bytes public/images/common/com_icon3.png | Bin 0 -> 5005 bytes public/images/common/discord.png | Bin 0 -> 663 bytes public/images/common/excel.png | Bin 0 -> 881 bytes public/images/common/kakaotalk.png | Bin 0 -> 1399 bytes public/images/common/news.png | Bin 0 -> 4746 bytes public/images/common/pdf.png | Bin 0 -> 1392 bytes public/images/common/telegram.png | Bin 0 -> 1763 bytes public/images/common/top.png | Bin 0 -> 2565 bytes public/images/common/top_skype.png | Bin 0 -> 2166 bytes public/index.php | 59 ++ public/js/admin.js | 73 ++ public/js/admin/clipboard.js | 30 + public/js/admin/form.js | 55 ++ public/js/admin/index.js | 33 + public/js/admin/left_menu.js | 13 + public/js/admin/resizeTable.js | 843 ++++++++++++++++++ public/js/admin/server/ipAutoComplete.js | 172 ++++ public/js/admin/server/switchAutoComplete.js | 147 +++ public/js/admin/server_partinfo.js | 43 + public/js/admin/serverpart.js | 39 + public/js/admin/service.js | 35 + public/js/common/product.js | 30 + public/js/empty.js | 6 + public/js/front.js | 93 ++ public/js/front/index.js | 33 + public/js/front/left_menu.js | 13 + public/robots.txt | 2 + spark | 84 ++ tests/.htaccess | 6 + tests/README.md | 118 +++ .../2020-02-22-222222_example_migration.php | 37 + .../_support/Database/Seeds/ExampleSeeder.php | 41 + tests/_support/Libraries/ConfigReader.php | 19 + tests/_support/Models/ExampleModel.php | 24 + tests/database/ExampleDatabaseTest.php | 46 + tests/index.html | 11 + tests/session/ExampleSessionTest.php | 17 + tests/unit/HealthTest.php | 49 + writable/.htaccess | 6 + writable/cache/index.html | 11 + writable/debugbar/index.html | 11 + writable/download/index.html | 11 + writable/index.html | 11 + writable/logs/index.html | 11 + writable/session/index.html | 11 + writable/uploads/index.html | 11 + 300 files changed, 19212 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 app/Config/App.php create mode 100644 app/Config/Autoload.php create mode 100644 app/Config/Boot/development.php create mode 100644 app/Config/Boot/production.php create mode 100644 app/Config/Boot/testing.php create mode 100644 app/Config/CURLRequest.php create mode 100644 app/Config/Cache.php create mode 100644 app/Config/Constants.php create mode 100644 app/Config/ContentSecurityPolicy.php create mode 100644 app/Config/Cookie.php create mode 100644 app/Config/Cors.php create mode 100644 app/Config/Database.php create mode 100644 app/Config/DocTypes.php create mode 100644 app/Config/Email.php create mode 100644 app/Config/Encryption.php create mode 100644 app/Config/Events.php create mode 100644 app/Config/Exceptions.php create mode 100644 app/Config/Feature.php create mode 100644 app/Config/Filters.php create mode 100644 app/Config/ForeignCharacters.php create mode 100644 app/Config/Format.php create mode 100644 app/Config/Generators.php create mode 100644 app/Config/Honeypot.php create mode 100644 app/Config/Images.php create mode 100644 app/Config/Kint.php create mode 100644 app/Config/Logger.php create mode 100644 app/Config/Migrations.php create mode 100644 app/Config/Mimes.php create mode 100644 app/Config/Modules.php create mode 100644 app/Config/Optimize.php create mode 100644 app/Config/Pager.php create mode 100644 app/Config/Paths.php create mode 100644 app/Config/Publisher.php create mode 100644 app/Config/Routes.php create mode 100644 app/Config/Routing.php create mode 100644 app/Config/Security.php create mode 100644 app/Config/Services.php create mode 100644 app/Config/Session.php create mode 100644 app/Config/Toolbar.php create mode 100644 app/Config/UserAgents.php create mode 100644 app/Config/Validation.php create mode 100644 app/Config/View.php create mode 100644 app/Controllers/AbstractCRUDController.php create mode 100644 app/Controllers/AbstractWebController.php create mode 100644 app/Controllers/Admin/AdminController.php create mode 100644 app/Controllers/Admin/Customer/AccountController.php create mode 100644 app/Controllers/Admin/Customer/ClientController.php create mode 100644 app/Controllers/Admin/Customer/CustomerController.php create mode 100644 app/Controllers/Admin/Home.php create mode 100644 app/Controllers/Admin/MylogController.php create mode 100644 app/Controllers/Admin/UserController.php create mode 100644 app/Controllers/Auth/AuthController.php create mode 100644 app/Controllers/Auth/GoogleController.php create mode 100644 app/Controllers/Auth/LocalController.php create mode 100644 app/Controllers/BaseController.php create mode 100644 app/Controllers/CLI/Collector.php create mode 100644 app/Controllers/CommonController.php create mode 100644 app/Controllers/Home.php create mode 100644 app/DTOs/Auth/AuthDTO.php create mode 100644 app/DTOs/Auth/GoogleDTO.php create mode 100644 app/DTOs/Auth/LocalDTO.php create mode 100644 app/DTOs/CommonDTO.php create mode 100644 app/DTOs/Customer/AccountDTO.php create mode 100644 app/DTOs/MylogDTO.php create mode 100644 app/DTOs/UserDTO.php create mode 100644 app/Database/Migrations/.gitkeep create mode 100644 app/Database/Seeds/.gitkeep create mode 100644 app/Database/traffic_test1.sql create mode 100644 app/Database/user.sql create mode 100644 app/Entities/BoardEntity.php create mode 100644 app/Entities/CommonEntity.php create mode 100644 app/Entities/Customer/AccountEntity.php create mode 100644 app/Entities/Customer/ClientEntity.php create mode 100644 app/Entities/Customer/CouponEntity.php create mode 100644 app/Entities/Customer/CustomerEntity.php create mode 100644 app/Entities/Customer/PointEntity.php create mode 100644 app/Entities/Customer/ServiceEntity.php create mode 100644 app/Entities/Equipment/EquipmentEntity.php create mode 100644 app/Entities/Equipment/LineEntity.php create mode 100644 app/Entities/Equipment/ServerEntity.php create mode 100644 app/Entities/Equipment/ServerPartEntity.php create mode 100644 app/Entities/MylogEntity.php create mode 100644 app/Entities/Part/CPUEntity.php create mode 100644 app/Entities/Part/CSEntity.php create mode 100644 app/Entities/Part/DISKEntity.php create mode 100644 app/Entities/Part/IPEntity.php create mode 100644 app/Entities/Part/PartEntity.php create mode 100644 app/Entities/Part/RAMEntity.php create mode 100644 app/Entities/Part/SOFTWAREEntity.php create mode 100644 app/Entities/Part/SWITCHEntity.php create mode 100644 app/Entities/PaymentEntity.php create mode 100644 app/Entities/UserEntity.php create mode 100644 app/Entities/UserSNSEntity.php create mode 100644 app/Filters/.gitkeep create mode 100644 app/Filters/AuthFilter.php create mode 100644 app/Forms/Auth/GoogleForm.php create mode 100644 app/Forms/Auth/LocalForm.php create mode 100644 app/Forms/CollectorForm.php create mode 100644 app/Forms/CommonForm.php create mode 100644 app/Forms/Customer/AccountForm.php create mode 100644 app/Forms/MylogForm.php create mode 100644 app/Forms/UserForm.php create mode 100644 app/Helpers/.gitkeep create mode 100644 app/Helpers/AuthHelper.php create mode 100644 app/Helpers/CollectorHelper.php create mode 100644 app/Helpers/CommonHelper.php create mode 100644 app/Helpers/Customer/AccountHelper.php create mode 100644 app/Helpers/MylogHelper.php create mode 100644 app/Helpers/UserHelper.php create mode 100644 app/Language/.gitkeep create mode 100644 app/Language/en/Auth/Local.php create mode 100644 app/Language/en/Board.php create mode 100644 app/Language/en/Customer/Account.php create mode 100644 app/Language/en/Customer/Client.php create mode 100644 app/Language/en/Customer/Coupon.php create mode 100644 app/Language/en/Customer/Point.php create mode 100644 app/Language/en/Customer/Service.php create mode 100644 app/Language/en/Equipment/Line.php create mode 100644 app/Language/en/Equipment/Server.php create mode 100644 app/Language/en/Equipment/ServerPart.php create mode 100644 app/Language/en/Mylog.php create mode 100644 app/Language/en/Part/CPU.php create mode 100644 app/Language/en/Part/CS.php create mode 100644 app/Language/en/Part/DISK.php create mode 100644 app/Language/en/Part/IP.php create mode 100644 app/Language/en/Part/RAM.php create mode 100644 app/Language/en/Part/SOFTWARE.php create mode 100644 app/Language/en/Part/SWITCH.php create mode 100644 app/Language/en/Payment.php create mode 100644 app/Language/en/User.php create mode 100644 app/Language/en/Validation.php create mode 100644 app/Libraries/.gitkeep create mode 100644 app/Libraries/AuthContext.php create mode 100644 app/Libraries/CommonLibrary.php create mode 100644 app/Libraries/MySocket/GoogleSocket/API.php create mode 100644 app/Libraries/MySocket/GoogleSocket/CURL.php create mode 100644 app/Libraries/MySocket/GoogleSocket/GoogleSocket.php create mode 100644 app/Libraries/MySocket/MySocket.php create mode 100644 app/Libraries/MySocket/WebSocket.php create mode 100644 app/Libraries/MyStorage/FileStorage.php create mode 100644 app/Libraries/OperationContext.php create mode 100644 app/Libraries/PipelineStep.php create mode 100644 app/Libraries/PipelineStepInterface.php create mode 100644 app/Libraries/SNMPLibrary.php create mode 100644 app/Models/.gitkeep create mode 100644 app/Models/BoardModel.php create mode 100644 app/Models/CommonModel.php create mode 100644 app/Models/Customer/AccountModel.php create mode 100644 app/Models/Customer/ClientModel.php create mode 100644 app/Models/Customer/CouponModel.php create mode 100644 app/Models/Customer/CustomerModel.php create mode 100644 app/Models/Customer/PointModel.php create mode 100644 app/Models/Customer/ServiceModel.php create mode 100644 app/Models/Equipment/EquipmentModel.php create mode 100644 app/Models/Equipment/LineModel.php create mode 100644 app/Models/Equipment/ServerModel.php create mode 100644 app/Models/Equipment/ServerPartModel.php create mode 100644 app/Models/MylogModel.php create mode 100644 app/Models/Part/CPUModel.php create mode 100644 app/Models/Part/CSModel.php create mode 100644 app/Models/Part/DISKModel.php create mode 100644 app/Models/Part/IPModel.php create mode 100644 app/Models/Part/PartModel.php create mode 100644 app/Models/Part/RAMModel.php create mode 100644 app/Models/Part/SOFTWAREModel.php create mode 100644 app/Models/Part/SWITCHModel.php create mode 100644 app/Models/PaymentModel.php create mode 100644 app/Models/UserModel.php create mode 100644 app/Models/UserSNSModel.php create mode 100644 app/Services/Auth/AuthService.php create mode 100644 app/Services/Auth/GoogleService.php create mode 100644 app/Services/Auth/LocalService.php create mode 100644 app/Services/CommonService.php create mode 100644 app/Services/Customer/AccountService.php create mode 100644 app/Services/MylogService.php create mode 100644 app/Services/UserService.php create mode 100644 app/Steps/CommonStep.php create mode 100644 app/Steps/TrafficRegistration.php create mode 100644 app/ThirdParty/.gitkeep create mode 100644 app/Traits/FileTrait.php create mode 100644 app/Traits/ImageTrait.php create mode 100644 app/Traits/LogTrait.php create mode 100644 app/Traits/UtilTrait.php create mode 100644 app/Views/.htaccess create mode 100644 app/Views/Common.php create mode 100644 app/Views/Pagers/bootstrap_full.php create mode 100644 app/Views/Pagers/bootstrap_simple.php create mode 100644 app/Views/admin/api/index.php create mode 100644 app/Views/admin/create_form.php create mode 100644 app/Views/admin/download.php create mode 100644 app/Views/admin/index.php create mode 100644 app/Views/admin/modify_form.php create mode 100644 app/Views/admin/traffic/dashboard.php create mode 100644 app/Views/admin/view.php create mode 100644 app/Views/admin/welcome.php create mode 100644 app/Views/auth/login_form.php create mode 100644 app/Views/errors/cli/error_404.php create mode 100644 app/Views/errors/cli/error_exception.php create mode 100644 app/Views/errors/cli/production.php create mode 100644 app/Views/errors/html/debug.css create mode 100644 app/Views/errors/html/debug.js create mode 100644 app/Views/errors/html/error_404.php create mode 100644 app/Views/errors/html/error_exception.php create mode 100644 app/Views/errors/html/production.php create mode 100644 app/Views/index.html create mode 100644 app/Views/layouts/admin.php create mode 100644 app/Views/layouts/admin/bottom.php create mode 100644 app/Views/layouts/admin/left_menu.php create mode 100644 app/Views/layouts/admin/left_menu/base.php create mode 100644 app/Views/layouts/admin/top.php create mode 100644 app/Views/layouts/empty.php create mode 100644 app/Views/layouts/front.php create mode 100644 app/Views/layouts/front/bottom.php create mode 100644 app/Views/layouts/front/left_menu.php create mode 100644 app/Views/layouts/front/top.php create mode 100644 app/Views/templates/admin/form_content_bottom.php create mode 100644 app/Views/templates/admin/form_content_top.php create mode 100644 app/Views/templates/admin/index_content_bottom.php create mode 100644 app/Views/templates/admin/index_content_filter.php create mode 100644 app/Views/templates/admin/index_content_top.php create mode 100644 app/Views/templates/admin/index_footer.php create mode 100644 app/Views/templates/admin/index_header.php create mode 100644 app/Views/templates/common/modal_fetch_v1.php create mode 100644 app/Views/templates/common/modal_fetch_v2.php create mode 100644 app/Views/templates/common/modal_iframe.php create mode 100644 app/Views/templates/front/index_footer.php create mode 100644 app/Views/templates/front/index_header.php create mode 100644 app/Views/welcome_message.php create mode 100644 builds create mode 100644 composer.json create mode 100644 env create mode 100644 phpunit.xml.dist create mode 100644 preload.php create mode 100644 public/.htaccess create mode 100644 public/css/admin.css create mode 100644 public/css/admin/form.css create mode 100644 public/css/admin/index.css create mode 100644 public/css/admin/left_menu.css create mode 100644 public/css/admin/member_link.css create mode 100644 public/css/admin/resizeTable.css create mode 100644 public/css/admin/server_partinfo.css create mode 100644 public/css/common/style.css create mode 100644 public/css/empty.css create mode 100644 public/css/front.css create mode 100644 public/css/front/copyright.css create mode 100644 public/css/front/form.css create mode 100644 public/css/front/index.css create mode 100644 public/css/front/left_menu.css create mode 100644 public/css/front/login.css create mode 100644 public/css/front/member_link.css create mode 100644 public/favicon.ico create mode 100644 public/images/common/com_icon3.png create mode 100644 public/images/common/discord.png create mode 100644 public/images/common/excel.png create mode 100644 public/images/common/kakaotalk.png create mode 100644 public/images/common/news.png create mode 100644 public/images/common/pdf.png create mode 100644 public/images/common/telegram.png create mode 100644 public/images/common/top.png create mode 100644 public/images/common/top_skype.png create mode 100644 public/index.php create mode 100644 public/js/admin.js create mode 100644 public/js/admin/clipboard.js create mode 100644 public/js/admin/form.js create mode 100644 public/js/admin/index.js create mode 100644 public/js/admin/left_menu.js create mode 100644 public/js/admin/resizeTable.js create mode 100644 public/js/admin/server/ipAutoComplete.js create mode 100644 public/js/admin/server/switchAutoComplete.js create mode 100644 public/js/admin/server_partinfo.js create mode 100644 public/js/admin/serverpart.js create mode 100644 public/js/admin/service.js create mode 100644 public/js/common/product.js create mode 100644 public/js/empty.js create mode 100644 public/js/front.js create mode 100644 public/js/front/index.js create mode 100644 public/js/front/left_menu.js create mode 100644 public/robots.txt create mode 100644 spark create mode 100644 tests/.htaccess create mode 100644 tests/README.md create mode 100644 tests/_support/Database/Migrations/2020-02-22-222222_example_migration.php create mode 100644 tests/_support/Database/Seeds/ExampleSeeder.php create mode 100644 tests/_support/Libraries/ConfigReader.php create mode 100644 tests/_support/Models/ExampleModel.php create mode 100644 tests/database/ExampleDatabaseTest.php create mode 100644 tests/index.html create mode 100644 tests/session/ExampleSessionTest.php create mode 100644 tests/unit/HealthTest.php create mode 100644 writable/.htaccess create mode 100644 writable/cache/index.html create mode 100644 writable/debugbar/index.html create mode 100644 writable/download/index.html create mode 100644 writable/index.html create mode 100644 writable/logs/index.html create mode 100644 writable/session/index.html create mode 100644 writable/uploads/index.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..289a5bc --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +#codeigniter4 +.env +composer.lock +vendor/ +public/vendor/ +writable/caceh/* +!writable/caceh/index.html +writable/logs/* +!writable/logs/index.html +writable/session/* +!writable/session/index.html +writable/uploads/* +!writable/uploads/index.html +writable/debugbar/* +!writable/debugbar/index.html +writable/download/* +!writable/download/index.html \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..24728f6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014-2019 British Columbia Institute of Technology +Copyright (c) 2019-present CodeIgniter Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d14b4c9 --- /dev/null +++ b/README.md @@ -0,0 +1,68 @@ +# CodeIgniter 4 Application Starter + +## What is CodeIgniter? + +CodeIgniter is a PHP full-stack web framework that is light, fast, flexible and secure. +More information can be found at the [official site](https://codeigniter.com). + +This repository holds a composer-installable app starter. +It has been built from the +[development repository](https://github.com/codeigniter4/CodeIgniter4). + +More information about the plans for version 4 can be found in [CodeIgniter 4](https://forum.codeigniter.com/forumdisplay.php?fid=28) on the forums. + +You can read the [user guide](https://codeigniter.com/user_guide/) +corresponding to the latest version of the framework. + +## Installation & updates + +`composer create-project codeigniter4/appstarter` then `composer update` whenever +there is a new release of the framework. + +When updating, check the release notes to see if there are any changes you might need to apply +to your `app` folder. The affected files can be copied or merged from +`vendor/codeigniter4/framework/app`. + +## Setup + +Copy `env` to `.env` and tailor for your app, specifically the baseURL +and any database settings. + +## Important Change with index.php + +`index.php` is no longer in the root of the project! It has been moved inside the *public* folder, +for better security and separation of components. + +This means that you should configure your web server to "point" to your project's *public* folder, and +not to the project root. A better practice would be to configure a virtual host to point there. A poor practice would be to point your web server to the project root and expect to enter *public/...*, as the rest of your logic and the +framework are exposed. + +**Please** read the user guide for a better explanation of how CI4 works! + +## Repository Management + +We use GitHub issues, in our main repository, to track **BUGS** and to track approved **DEVELOPMENT** work packages. +We use our [forum](http://forum.codeigniter.com) to provide SUPPORT and to discuss +FEATURE REQUESTS. + +This repository is a "distribution" one, built by our release preparation script. +Problems with it can be raised on our forum, or as issues in the main repository. + +## Server Requirements + +PHP version 8.1 or higher is required, with the following extensions installed: + +- [intl](http://php.net/manual/en/intl.requirements.php) +- [mbstring](http://php.net/manual/en/mbstring.installation.php) + +> [!WARNING] +> - The end of life date for PHP 7.4 was November 28, 2022. +> - The end of life date for PHP 8.0 was November 26, 2023. +> - If you are still using PHP 7.4 or 8.0, you should upgrade immediately. +> - The end of life date for PHP 8.1 will be December 31, 2025. + +Additionally, make sure that the following extensions are enabled in your PHP: + +- json (enabled by default - don't turn it off) +- [mysqlnd](http://php.net/manual/en/mysqlnd.install.php) if you plan to use MySQL +- [libcurl](http://php.net/manual/en/curl.requirements.php) if you plan to use the HTTP\CURLRequest library diff --git a/app/Config/App.php b/app/Config/App.php new file mode 100644 index 0000000..b761da7 --- /dev/null +++ b/app/Config/App.php @@ -0,0 +1,202 @@ + + */ + public array $allowedHostnames = []; + + /** + * -------------------------------------------------------------------------- + * Index File + * -------------------------------------------------------------------------- + * + * Typically, this will be your `index.php` file, unless you've renamed it to + * something else. If you have configured your web server to remove this file + * from your site URIs, set this variable to an empty string. + */ + public string $indexPage = 'index.php'; + + /** + * -------------------------------------------------------------------------- + * URI PROTOCOL + * -------------------------------------------------------------------------- + * + * This item determines which server global should be used to retrieve the + * URI string. The default setting of 'REQUEST_URI' works for most servers. + * If your links do not seem to work, try one of the other delicious flavors: + * + * 'REQUEST_URI': Uses $_SERVER['REQUEST_URI'] + * 'QUERY_STRING': Uses $_SERVER['QUERY_STRING'] + * 'PATH_INFO': Uses $_SERVER['PATH_INFO'] + * + * WARNING: If you set this to 'PATH_INFO', URIs will always be URL-decoded! + */ + public string $uriProtocol = 'REQUEST_URI'; + + /* + |-------------------------------------------------------------------------- + | Allowed URL Characters + |-------------------------------------------------------------------------- + | + | This lets you specify which characters are permitted within your URLs. + | When someone tries to submit a URL with disallowed characters they will + | get a warning message. + | + | As a security measure you are STRONGLY encouraged to restrict URLs to + | as few characters as possible. + | + | By default, only these are allowed: `a-z 0-9~%.:_-` + | + | Set an empty string to allow all characters -- but only if you are insane. + | + | The configured value is actually a regular expression character group + | and it will be used as: '/\A[]+\z/iu' + | + | DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!! + | + */ + public string $permittedURIChars = 'a-z 0-9~%.:_\-'; + + /** + * -------------------------------------------------------------------------- + * Default Locale + * -------------------------------------------------------------------------- + * + * The Locale roughly represents the language and location that your visitor + * is viewing the site from. It affects the language strings and other + * strings (like currency markers, numbers, etc), that your program + * should run under for this request. + */ + public string $defaultLocale = 'en'; + + /** + * -------------------------------------------------------------------------- + * Negotiate Locale + * -------------------------------------------------------------------------- + * + * If true, the current Request object will automatically determine the + * language to use based on the value of the Accept-Language header. + * + * If false, no automatic detection will be performed. + */ + public bool $negotiateLocale = false; + + /** + * -------------------------------------------------------------------------- + * Supported Locales + * -------------------------------------------------------------------------- + * + * If $negotiateLocale is true, this array lists the locales supported + * by the application in descending order of priority. If no match is + * found, the first locale will be used. + * + * IncomingRequest::setLocale() also uses this list. + * + * @var list + */ + public array $supportedLocales = ['en']; + + /** + * -------------------------------------------------------------------------- + * Application Timezone + * -------------------------------------------------------------------------- + * + * The default timezone that will be used in your application to display + * dates with the date helper, and can be retrieved through app_timezone() + * + * @see https://www.php.net/manual/en/timezones.php for list of timezones + * supported by PHP. + */ + public string $appTimezone = 'UTC'; + + /** + * -------------------------------------------------------------------------- + * Default Character Set + * -------------------------------------------------------------------------- + * + * This determines which character set is used by default in various methods + * that require a character set to be provided. + * + * @see http://php.net/htmlspecialchars for a list of supported charsets. + */ + public string $charset = 'UTF-8'; + + /** + * -------------------------------------------------------------------------- + * Force Global Secure Requests + * -------------------------------------------------------------------------- + * + * If true, this will force every request made to this application to be + * made via a secure connection (HTTPS). If the incoming request is not + * secure, the user will be redirected to a secure version of the page + * and the HTTP Strict Transport Security (HSTS) header will be set. + */ + public bool $forceGlobalSecureRequests = false; + + /** + * -------------------------------------------------------------------------- + * Reverse Proxy IPs + * -------------------------------------------------------------------------- + * + * If your server is behind a reverse proxy, you must whitelist the proxy + * IP addresses from which CodeIgniter should trust headers such as + * X-Forwarded-For or Client-IP in order to properly identify + * the visitor's IP address. + * + * You need to set a proxy IP address or IP address with subnets and + * the HTTP header for the client IP address. + * + * Here are some examples: + * [ + * '10.0.1.200' => 'X-Forwarded-For', + * '192.168.5.0/24' => 'X-Real-IP', + * ] + * + * @var array + */ + public array $proxyIPs = []; + + /** + * -------------------------------------------------------------------------- + * Content Security Policy + * -------------------------------------------------------------------------- + * + * Enables the Response's Content Secure Policy to restrict the sources that + * can be used for images, scripts, CSS files, audio, video, etc. If enabled, + * the Response object will populate default values for the policy from the + * `ContentSecurityPolicy.php` file. Controllers can always add to those + * restrictions at run time. + * + * For a better understanding of CSP, see these documents: + * + * @see http://www.html5rocks.com/en/tutorials/security/content-security-policy/ + * @see http://www.w3.org/TR/CSP/ + */ + public bool $CSPEnabled = false; +} diff --git a/app/Config/Autoload.php b/app/Config/Autoload.php new file mode 100644 index 0000000..9a92824 --- /dev/null +++ b/app/Config/Autoload.php @@ -0,0 +1,92 @@ +|string> + */ + public $psr4 = [ + APP_NAMESPACE => APPPATH, + ]; + + /** + * ------------------------------------------------------------------- + * Class Map + * ------------------------------------------------------------------- + * The class map provides a map of class names and their exact + * location on the drive. Classes loaded in this manner will have + * slightly faster performance because they will not have to be + * searched for within one or more directories as they would if they + * were being autoloaded through a namespace. + * + * Prototype: + * $classmap = [ + * 'MyClass' => '/path/to/class/file.php' + * ]; + * + * @var array + */ + public $classmap = []; + + /** + * ------------------------------------------------------------------- + * Files + * ------------------------------------------------------------------- + * The files array provides a list of paths to __non-class__ files + * that will be autoloaded. This can be useful for bootstrap operations + * or for loading functions. + * + * Prototype: + * $files = [ + * '/path/to/my/file.php', + * ]; + * + * @var list + */ + public $files = []; + + /** + * ------------------------------------------------------------------- + * Helpers + * ------------------------------------------------------------------- + * Prototype: + * $helpers = [ + * 'form', + * ]; + * + * @var list + */ + public $helpers = []; +} diff --git a/app/Config/Boot/development.php b/app/Config/Boot/development.php new file mode 100644 index 0000000..a868447 --- /dev/null +++ b/app/Config/Boot/development.php @@ -0,0 +1,34 @@ + WRITEPATH . 'cache/', + 'mode' => 0640, + ]; + + /** + * ------------------------------------------------------------------------- + * Memcached settings + * ------------------------------------------------------------------------- + * + * Your Memcached servers can be specified below, if you are using + * the Memcached drivers. + * + * @see https://codeigniter.com/user_guide/libraries/caching.html#memcached + * + * @var array{host?: string, port?: int, weight?: int, raw?: bool} + */ + public array $memcached = [ + 'host' => '127.0.0.1', + 'port' => 11211, + 'weight' => 1, + 'raw' => false, + ]; + + /** + * ------------------------------------------------------------------------- + * Redis settings + * ------------------------------------------------------------------------- + * + * Your Redis server can be specified below, if you are using + * the Redis or Predis drivers. + * + * @var array{host?: string, password?: string|null, port?: int, timeout?: int, database?: int} + */ + public array $redis = [ + 'host' => '127.0.0.1', + 'password' => null, + 'port' => 6379, + 'timeout' => 0, + 'database' => 0, + ]; + + /** + * -------------------------------------------------------------------------- + * Available Cache Handlers + * -------------------------------------------------------------------------- + * + * This is an array of cache engine alias' and class names. Only engines + * that are listed here are allowed to be used. + * + * @var array> + */ + public array $validHandlers = [ + 'dummy' => DummyHandler::class, + 'file' => FileHandler::class, + 'memcached' => MemcachedHandler::class, + 'predis' => PredisHandler::class, + 'redis' => RedisHandler::class, + 'wincache' => WincacheHandler::class, + ]; + + /** + * -------------------------------------------------------------------------- + * Web Page Caching: Cache Include Query String + * -------------------------------------------------------------------------- + * + * Whether to take the URL query string into consideration when generating + * output cache files. Valid options are: + * + * false = Disabled + * true = Enabled, take all query parameters into account. + * Please be aware that this may result in numerous cache + * files generated for the same page over and over again. + * ['q'] = Enabled, but only take into account the specified list + * of query parameters. + * + * @var bool|list + */ + public $cacheQueryString = false; +} diff --git a/app/Config/Constants.php b/app/Config/Constants.php new file mode 100644 index 0000000..728cc18 --- /dev/null +++ b/app/Config/Constants.php @@ -0,0 +1,535 @@ + '생성되었습니다.', + 'UPDATED' => '수정되였습니다.', + 'DELETED' => '삭제되였습니다.', + 'SUCCESS' => '작업이 성공적으로 완료되었습니다.', + 'FAILED' => '작업이 실패하였습니다.', + 'NOT_FOUND' => '데이터가 존재하지 않습니다.', + 'NOT_AUTH' => '권한이 없습니다.', + 'NOT_LOGIN' => '로그인이 필요합니다.', + 'NOT_MATCH' => '데이터가 일치하지 않습니다.', + 'NOT_EMPTY' => '데이터가 비어있습니다.', + 'NOT_UNIQUE' => '중복된 데이터가 존재합니다.', + 'NOT_DELETE' => '삭제할 수 없는 데이터가 존재합니다.', + 'NOT_UPDATE' => '수정할 수 없는 데이터가 존재합니다.', + 'NOT_CREATE' => '생성할 수 없는 데이터가 존재합니다.', + 'NOT_SYNC' => '동기화할 수 없는 데이터가 존재합니다.', + 'NOT_SYNC_RESULT' => '동기화 결과가 실패하였습니다.', + 'NOT_SYNC_SUCCESS' => '동기화 결과가 성공하였습니다.', + 'NOT_SYNC_ERROR' => '동기화 결과가 실패하였습니다.', + 'NOT_SYNC_NOTHING' => '동기화할 데이터가 없습니다.', + 'NOT_SYNC_NOTHING_RESULT' => '동기화 결과가 없습니다.', + 'NOT_SYNC_NOTHING_ERROR' => '동기화 결과가 없습니다.', + 'LOGIN' => '로그인 하셨습니다.', + 'LOGOUT' => '로그아웃 하셨습니다.' +]); +//URL +define('URLS', [ + 'LOGIN' => '/auth/login', + 'GOOGLE_LOGIN' => '/auth/google_login', + 'SIGNUP' => '/auth/signup', + 'LOGOUT' => '/auth/logout', +]); +//SESSION 관련 +define('SESSION_NAMES', [ + 'RETURN_URL' => "return_url", + 'RETURN_MSG' => "return_message", + 'ISLOGIN' => "islogined", + 'AUTH' => 'auth', +]); +//메신저 관련 +define("MESSENGERS", [ + "skype" => [ + "url" => "//join.skype.com/invite/uKUgXfZThSQC", + "icon" => '스카이프', + "id" => '', + ], + "discord" => [ + "url" => "//discord.gg/k6nQg84N", + "icon" => '디스코드', + "id" => '', + ], + "telegram" => [ + "url" => "//t.me/daemonidc", + "icon" => '텔레그램', + "id" => '@daemonidc', + ], + "kakaotalk" => [ + "url" => "//t.me/daemonidc", + "icon" => '카카오톡', + "id" => '', + ], +]); +//아이콘 및 Sound관련 +define('ICONS', [ + 'ADD' => '', + 'LOGO' => '', + 'EXCEL' => '', + 'PDF' => '', + 'GOOGLE' => 'Google', + 'MEMBER' => '', + 'LOGIN' => '', + 'LOGOUT' => '', + 'HOME' => '', + 'MENU' => '', + 'NEW' => '', + 'REPLY' => '', + 'DATABASE' => '', + 'DISLIKE' => '', + 'LIKE' => '', + 'DOWNLOAD' => '', + 'UPLOAD' => '', + 'COPY' => '', + 'PASTE' => '', + 'EDIT' => '', + 'VIEW' => '', + 'VIEW_OFF' => '', + 'PRINT' => '', + 'SAVE' => '', + 'CANCEL' => '', + 'CLOSE' => '', + 'CLIENT' => '', + 'CHART' => '', + 'CHECK' => '', + 'CHECK_OFF' => '', + 'CHECK_ON' => '', + 'CHECK_ALL' => '', + 'CHECK_NONE' => '', + 'CHECK_SOME' => '', + 'COUPON' => '', + 'HISTORY' => '', + 'MODIFY' => '', + 'MODIFY_ALL' => '', + 'BATCHJOB' => '', + 'DELETE' => '', + 'REBOOT' => '🔄', + 'RELOAD' => '', + 'SETUP' => '', + 'FLAG' => '', + 'SEARCH' => '', + 'PLAY' => '', + 'CART' => '', + 'CARD' => '', + 'DEPOSIT' => '', + 'DESKTOP' => '', + 'DEVICE' => '', + 'UP' => '', + 'DOWN' => '', + 'LEFT' => '', + 'RIGHT' => '', + 'IMAGE_FILE' => '', + 'CLOUD' => '', + 'SIGNPOST' => '', + 'LOCK' => '', + 'UNLOCK' => '', + 'BOX' => '', + 'BOXS' => '', + 'ONETIME' => '', + 'MONTH' => '', + 'EMAIL' => '', + 'MAIL' => '', + 'PHONE' => '', + 'POINT' => '', + 'ALRAM' => '', + 'PAYMENT' => '', + 'LINK' => '', + 'SALE_UP' => '', + 'SALE_DOWN' => '', + 'SERVICE' => '', + 'SERVICE_ITEM' => '', + 'SERVICE_ITEM_LINE' => '', + 'SERVICE_ITEM_IP' => '', + 'SERVICE_ITEM_SERVER' => '', + 'SERVICE_ITEM_CPU' => '', + 'SERVICE_ITEM_RAM' => '', + 'SERVICE_ITEM_STORAGE' => '', + 'SERVICE_ITEM_SOFTWARE' => '', + 'SERVICE_ITEM_DEFENCE' => '', + 'SERVICE_ITEM_DOMAIN' => '', + 'SERVICE_ITEM_OTHER' => '', + 'SERVER_ITEM_CPU' => '', + 'SERVER_ITEM_RAM' => '', + 'SERVER_ITEM_DISK' => '', + 'SERVER_ITEM_SWITCH' => '', + 'SERVER_ITEM_OS' => '', + 'SERVER_ITEM_DB' => '', + 'SERVER_ITEM_SOFTWARE' => '', + 'SERVER_ITEM_IP' => '', + 'SERVER_ITEM_CS' => '', + 'SERVER_ITEM_ETC' => '', +]); +//메신저 아이콘 +define('MESSENGER_ICONS', [ + 'WHATSAPP' => '', + 'VIBER' => '', + 'LINE' => '', + 'KAKAO' => '', + 'DISCORD' => '', + 'TELEGRAM' => '', + 'SKYPE' => '', + 'YOUTUBE' => '', + 'FACEBOOK' => '', + 'TWITTER' => '', + 'INSTAGRAM' => '', + 'LINKEDIN' => '', + 'GITHUB' => '', + 'GITLAB' => '', + 'BITBUCKET' => '', + 'REDDIT' => '', + 'TIKTOK' => '', + 'PINTEREST' => '', + 'TUMBLR' => '', + 'SNAPCHAT' => '', +]); +//배너관련 +define('TOP_BANNER', [ + 'default' => '', + 'aboutus' => '', + 'member' => '', + 'hosting' => '', + 'serverdevice' => '', + 'service' => '', + 'support' => '', +]); +//소리관련 +define('AUDIOS', [ + 'Alram_GetEmail' => '', +]); +//Layout관련 +define('KEYWORD', '일본IDC 일본서버 일본 서버 일본호스팅 서버호스팅 디도스 공격 해외 호스팅 DDOS 방어 ddos 의뢰 디도스 보안 일본 단독서버 가상서버'); +define('LAYOUTS', [ + 'empty' => [ + 'title' => KEYWORD, + 'path' => 'layouts' . DIRECTORY_SEPARATOR . 'empty', + 'metas' => [ + '', + '', + '', + '', + '', + '', + '', + '', + '', + ], + 'stylesheets' => [ + '', + '', + '', + ], + 'javascripts' => [ + '', + ], + ], + 'front' => [ + 'title' => KEYWORD, + 'path' => 'layouts' . DIRECTORY_SEPARATOR . 'front', + 'topmenus' => ['aboutus', 'hosting', 'service', 'support'], + 'metas' => [ + '', + '', + '', + '', + '', + '', + '', + '', + '', + ], + 'stylesheets' => [ + '', + '', + '', + '', + '', + ], + 'javascripts' => [ + '', + '', + '', + '', + ], + ], + 'admin' => [ + 'title' => '관리자화면', + 'path' => 'layouts' . DIRECTORY_SEPARATOR . 'admin', + 'metas' => [ + '', + '', + '', + '', + '', + '', + '', + '', + '', + ], + 'stylesheets' => [ + '', + '', + '', + '', + '', + '', + '', + '', + ], + 'javascripts' => [ + '', + '', + '', + '', + '', + '' + ], + ], +]); + +//STATUS +define("STATUS", [ + 'AVAILABLE' => "available", + 'FORBIDDEN' => "forbidden", + 'OCCUPIED' => "occupied", + 'SUCCESS' => "success", + 'FAILED' => "fail", + 'PAUSE' => "pause", + 'TERMINATED' => "terminated", + 'WITHDRAWAL' => "withdrawal", + 'DEPOSIT' => "deposit", + 'PAID' => 'paid', + 'UNPAID' => 'unpaid', +]); + +//ROLE +define("ROLE", [ + 'USER' => [ + 'MANAGER' => "manager", + 'CLOUDFLARE' => "cloudflare", + 'FIREWALL' => "firewall", + 'SECURITY' => "security", + 'DIRECTOR' => "director", + 'MASTER' => "master", + ], + 'CLIENT' => [], +]); + +//Default값 정의 +define('DEFAULTS', [ + 'DELIMITER_FILE' => "||", + 'DELIMITER_ROLE' => ",", + 'INDEX_PERPAGE' => 20, + 'STATUS' => STATUS['AVAILABLE'] +]); +######################### +//서비스 관련 +define("SERVICE", [ + "NEW_INTERVAL" => $_ENV['SERVICE_NEW_INTERVAL'] ?? $_SERVER['SERVICE_NEW_INTERVAL'] ?? 7, +]); +//서버 관련 +define("SERVER", [ + "TYPES" => [ + "NORMAL" => 'normal', + "DEFENCE" => 'defence', + "DEDICATED" => 'dedicated', + "VPN" => 'vpn', + "EVENT" => 'event', + "TEST" => 'test', + "ALTERNATIVE" => 'alternative', + "OURS" => 'ours', + "COLOCATION" => 'colocation' + ], + "CHASSISES" => [ + "HP DL360 GEN6B" => "HP DL360 Gen6 B", + "HP DL360 GEN7C" => "HP DL360 Gen7 C", + "HP DL360 GEN7D" => "HP DL360 Gen7 D", + "HP DL360 GEN8D" => "HP DL360 Gen8 D", + "HP DL360 GEN8E" => "HP DL360 Gen8 E", + "HP DL360 GEN9E" => "HP DL360 Gen9 E", + "HP DL360 GEN10" => "HP DL360 Gen10", + "Hitach HA3000" => "Hitach HA3000", + "DESKTOP I5-9" => "데탑 I5 9세대", + "DESKTOP I5-10" => "데탑 I5 10세대", + "DESKTOP I5-12" => "데탑 I5 12세대", + "DESKTOP I7-9" => "데탑 I5 9세대", + "DESKTOP I7-10" => "데탑 I5 10세대", + "DESKTOP I7-12" => "데탑 I5 12세대", + "MINI I5-12" => "Mini I5 12세대", + "VPC" => "아마존-VPN", + "KCS" => "KT-VPN", + ], + "STOCKS" => [ + "HP DL360 GEN6B" => 100, + "HP DL360 GEN7C" => 100, + "HP DL360 GEN7D" => 100, + "HP DL360 GEN8D" => 100, + "HP DL360 GEN8E" => 100, + "HP DL360 GEN9E" => 100, + "HP DL360 GEN10" => 100, + "Hitach HA3000" => 100, + "DESKTOP I5-9" => 100, + "DESKTOP I5-10" => 100, + "DESKTOP I5-12" => 100, + "DESKTOP I7-9" => 100, + "DESKTOP I7-10" => 100, + "DESKTOP I7-12" => 100, + "MINI I5-12" => 100, + "VPC" => 100, + "KCS" => 100, + ] +]); +//서버파트 관련 +define("SERVERPART", [ + "CNT_RANGE" => array_combine(range(1, 10), range(1, 10)), + "SERVER_PARTTYPES" => ['CPU', 'RAM', 'DISK'], + "SERVICE_PARTTYPES" => ['SOFTWARE', 'CS', 'IP'], + "ALL_PARTTYPES" => ['CPU', 'RAM', 'DISK', 'SOFTWARE', 'IP', 'CS'], + "CPU" => [ + "HP DL360 GEN6B" => [["UID" => 1, "CNT" => 2, "EXTRA" => ""]], + "HP DL360 GEN7C" => [["UID" => 2, "CNT" => 2, "EXTRA" => ""]], + "HP DL360 GEN7D" => [["UID" => 3, "CNT" => 2, "EXTRA" => ""]], + "HP DL360 GEN8D" => [["UID" => 3, "CNT" => 2, "EXTRA" => ""]], + "HP DL360 GEN8E" => [["UID" => 4, "CNT" => 2, "EXTRA" => ""]], + "HP DL360 GEN9E" => [["UID" => 4, "CNT" => 2, "EXTRA" => ""]], + "HP DL360 GEN10" => [["UID" => 5, "CNT" => 2, "EXTRA" => ""]], + "Hitach HA3000" => [["UID" => 5, "CNT" => 2, "EXTRA" => ""]], + "DESKTOP I5-9" => [["UID" => 7, "CNT" => 1, "EXTRA" => ""]], + "DESKTOP I5-10" => [["UID" => 8, "CNT" => 1, "EXTRA" => ""]], + "DESKTOP I5-12" => [["UID" => 9, "CNT" => 1, "EXTRA" => ""]], + "DESKTOP I7-9" => [["UID" => 10, "CNT" => 1, "EXTRA" => ""]], + "DESKTOP I7-10" => [["UID" => 11, "CNT" => 1, "EXTRA" => ""]], + "DESKTOP I7-12" => [["UID" => 12, "CNT" => 1, "EXTRA" => ""]], + ], + "RAM" => [ + "HP DL360 GEN6B" => [["UID" => 2, "CNT" => 1, "EXTRA" => ""]], + "HP DL360 GEN7C" => [["UID" => 2, "CNT" => 2, "EXTRA" => ""]], + "HP DL360 GEN7D" => [["UID" => 2, "CNT" => 2, "EXTRA" => ""]], + "HP DL360 GEN8D" => [["UID" => 3, "CNT" => 2, "EXTRA" => ""]], + "HP DL360 GEN8E" => [["UID" => 3, "CNT" => 4, "EXTRA" => ""]], + "HP DL360 GEN9E" => [["UID" => 4, "CNT" => 4, "EXTRA" => ""]], + "HP DL360 GEN10" => [["UID" => 5, "CNT" => 2, "EXTRA" => ""]], + "Hitach HA3000" => [["UID" => 5, "CNT" => 2, "EXTRA" => ""]], + "DESKTOP I5-9" => [["UID" => 9, "CNT" => 1, "EXTRA" => ""]], + "DESKTOP I5-10" => [["UID" => 9, "CNT" => 1, "EXTRA" => ""]], + "DESKTOP I5-12" => [["UID" => 10, "CNT" => 1, "EXTRA" => ""]], + "DESKTOP I7-9" => [["UID" => 9, "CNT" => 1, "EXTRA" => ""]], + "DESKTOP I7-10" => [["UID" => 9, "CNT" => 1, "EXTRA" => ""]], + "DESKTOP I7-12" => [["UID" => 10, "CNT" => 1, "EXTRA" => ""]], + ], + "DISK" => [ + "HP DL360 GEN6B" => [["UID" => 8, "CNT" => 2, "EXTRA" => "RAID1"], ["UID" => 9, "CNT" => 2, "EXTRA" => "RAID1"],], + "HP DL360 GEN7C" => [["UID" => 8, "CNT" => 2, "EXTRA" => "RAID1"], ["UID" => 9, "CNT" => 2, "EXTRA" => "RAID1"],], + "HP DL360 GEN7D" => [["UID" => 8, "CNT" => 2, "EXTRA" => "RAID1"], ["UID" => 9, "CNT" => 2, "EXTRA" => "RAID1"],], + "HP DL360 GEN8C" => [["UID" => 8, "CNT" => 2, "EXTRA" => "RAID1"], ["UID" => 9, "CNT" => 2, "EXTRA" => "RAID1"],], + "HP DL360 GEN8D" => [["UID" => 8, "CNT" => 2, "EXTRA" => "RAID1"], ["UID" => 9, "CNT" => 2, "EXTRA" => "RAID1"],], + "HP DL360 GEN8E" => [["UID" => 8, "CNT" => 2, "EXTRA" => "RAID1"], ["UID" => 9, "CNT" => 2, "EXTRA" => "RAID1"],], + "HP DL360 GEN9E" => [["UID" => 8, "CNT" => 2, "EXTRA" => "RAID1"], ["UID" => 9, "CNT" => 2, "EXTRA" => "RAID1"],], + "HP DL360 GEN10" => [["UID" => 8, "CNT" => 2, "EXTRA" => "RAID1"], ["UID" => 9, "CNT" => 2, "EXTRA" => "RAID1"],], + "Hitach HA3000" => [["UID" => 8, "CNT" => 2, "EXTRA" => "RAID1"], ["UID" => 9, "CNT" => 2, "EXTRA" => "RAID1"],], + "DESKTOP I5-9" => [["UID" => 8, "CNT" => 1, "EXTRA" => ""]], + "DESKTOP I5-10" => [["UID" => 8, "CNT" => 1, "EXTRA" => ""]], + "DESKTOP I5-12" => [["UID" => 9, "CNT" => 1, "EXTRA" => ""]], + "DESKTOP I7-9" => [["UID" => 8, "CNT" => 1, "EXTRA" => ""]], + "DESKTOP I7-10" => [["UID" => 8, "CNT" => 1, "EXTRA" => ""]], + "DESKTOP I7-12" => [["UID" => 9, "CNT" => 1, "EXTRA" => ""]], + ] +]); +//결제 관련 +define("PAYMENT", [ + 'BILLING' => [ + 'BASE' => 'base', + 'MONTH' => 'month', + 'ONETIME' => 'onetime' + ], + 'PAY' => [ + 'ACCOUNT' => 'account', + 'COUPON' => 'coupon', + 'POINT' => 'point' + ] +]); +//게시판 관련 +define("BOARD", [ + 'CATEGORY' => [ + 'NOTICE' => 'notice', + 'REQUESTTASK' => 'requesttask' + ], +]); diff --git a/app/Config/ContentSecurityPolicy.php b/app/Config/ContentSecurityPolicy.php new file mode 100644 index 0000000..2ac41a7 --- /dev/null +++ b/app/Config/ContentSecurityPolicy.php @@ -0,0 +1,176 @@ +|string|null + */ + public $defaultSrc; + + /** + * Lists allowed scripts' URLs. + * + * @var list|string + */ + public $scriptSrc = 'self'; + + /** + * Lists allowed stylesheets' URLs. + * + * @var list|string + */ + public $styleSrc = 'self'; + + /** + * Defines the origins from which images can be loaded. + * + * @var list|string + */ + public $imageSrc = 'self'; + + /** + * Restricts the URLs that can appear in a page's `` element. + * + * Will default to self if not overridden + * + * @var list|string|null + */ + public $baseURI; + + /** + * Lists the URLs for workers and embedded frame contents + * + * @var list|string + */ + public $childSrc = 'self'; + + /** + * Limits the origins that you can connect to (via XHR, + * WebSockets, and EventSource). + * + * @var list|string + */ + public $connectSrc = 'self'; + + /** + * Specifies the origins that can serve web fonts. + * + * @var list|string + */ + public $fontSrc; + + /** + * Lists valid endpoints for submission from `
` tags. + * + * @var list|string + */ + public $formAction = 'self'; + + /** + * Specifies the sources that can embed the current page. + * This directive applies to ``, ` + + + + + + \ No newline at end of file diff --git a/app/Views/templates/front/index_footer.php b/app/Views/templates/front/index_footer.php new file mode 100644 index 0000000..e69de29 diff --git a/app/Views/templates/front/index_header.php b/app/Views/templates/front/index_header.php new file mode 100644 index 0000000..f0c64c4 --- /dev/null +++ b/app/Views/templates/front/index_header.php @@ -0,0 +1,87 @@ + + \ No newline at end of file diff --git a/app/Views/welcome_message.php b/app/Views/welcome_message.php new file mode 100644 index 0000000..c18eca3 --- /dev/null +++ b/app/Views/welcome_message.php @@ -0,0 +1,331 @@ + + + + + Welcome to CodeIgniter 4! + + + + + + + + + + + +
+ + + +
+ +

Welcome to CodeIgniter

+ +

The small framework with powerful features

+ +
+ +
+ + + +
+ +

About this page

+ +

The page you are looking at is being generated dynamically by CodeIgniter.

+ +

If you would like to edit this page you will find it located at:

+ +
app/Views/welcome_message.php
+ +

The corresponding controller for this page can be found at:

+ +
app/Controllers/Home.php
+ +
+ +
+ +
+ +

Go further

+ +

+ + Learn +

+ +

The User Guide contains an introduction, tutorial, a number of "how to" + guides, and then reference documentation for the components that make up + the framework. Check the User Guide !

+ +

+ + Discuss +

+ +

CodeIgniter is a community-developed open source project, with several + venues for the community members to gather and exchange ideas. View all + the threads on CodeIgniter's forum, or chat on Slack !

+ +

+ + Contribute +

+ +

CodeIgniter is a community driven project and accepts contributions + of code and documentation from the community. Why not + + join us ?

+ +
+ +
+ + + +
+
+ +

Page rendered in {elapsed_time} seconds using {memory_usage} MB of memory.

+ +

Environment:

+ +
+ +
+ +

© CodeIgniter Foundation. CodeIgniter is open source project released under the MIT + open source licence.

+ +
+ +
+ + + + + + + + + diff --git a/builds b/builds new file mode 100644 index 0000000..cc2ca08 --- /dev/null +++ b/builds @@ -0,0 +1,125 @@ +#!/usr/bin/env php + 'vcs', + 'url' => GITHUB_URL, + ]; + } + + $array['require']['codeigniter4/codeigniter4'] = 'dev-develop'; + unset($array['require']['codeigniter4/framework']); + } else { + unset($array['minimum-stability']); + + if (isset($array['repositories'])) { + foreach ($array['repositories'] as $i => $repository) { + if ($repository['url'] === GITHUB_URL) { + unset($array['repositories'][$i]); + break; + } + } + + if (empty($array['repositories'])) { + unset($array['repositories']); + } + } + + $array['require']['codeigniter4/framework'] = LATEST_RELEASE; + unset($array['require']['codeigniter4/codeigniter4']); + } + + file_put_contents($file, json_encode($array, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL); + + $modified[] = $file; + } else { + echo 'Warning: Unable to decode composer.json! Skipping...' . PHP_EOL; + } + } else { + echo 'Warning: Unable to read composer.json! Skipping...' . PHP_EOL; + } +} + +$files = [ + __DIR__ . DIRECTORY_SEPARATOR . 'app/Config/Paths.php', + __DIR__ . DIRECTORY_SEPARATOR . 'phpunit.xml.dist', + __DIR__ . DIRECTORY_SEPARATOR . 'phpunit.xml', +]; + +foreach ($files as $file) { + if (is_file($file)) { + $contents = file_get_contents($file); + + if ($dev) { + $contents = str_replace('vendor/codeigniter4/framework', 'vendor/codeigniter4/codeigniter4', $contents); + } else { + $contents = str_replace('vendor/codeigniter4/codeigniter4', 'vendor/codeigniter4/framework', $contents); + } + + file_put_contents($file, $contents); + + $modified[] = $file; + } +} + +if ($modified === []) { + echo 'No files modified.' . PHP_EOL; +} else { + echo 'The following files were modified:' . PHP_EOL; + + foreach ($modified as $file) { + echo " * {$file}" . PHP_EOL; + } + + echo 'Run `composer update` to sync changes with your vendor folder.' . PHP_EOL; +} diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..0c322e2 --- /dev/null +++ b/composer.json @@ -0,0 +1,48 @@ +{ + "name": "codeigniter4/appstarter", + "description": "CodeIgniter4 starter app", + "license": "MIT", + "type": "project", + "homepage": "https://codeigniter.com", + "support": { + "forum": "https://forum.codeigniter.com/", + "source": "https://github.com/codeigniter4/CodeIgniter4", + "slack": "https://codeigniterchat.slack.com" + }, + "require": { +"php": "^8.2", + "codeigniter4/framework": "^4.5", + "guzzlehttp/guzzle": "^7.9", + "io-developer/php-whois": "^4.1", + "phpoffice/phpspreadsheet": "^1.27", + "symfony/css-selector": "^7.1", + "twbs/bootstrap": "5.3.3" + }, + "require-dev": { + "fakerphp/faker": "^1.9", + "mikey179/vfsstream": "^1.6", + "phpunit/phpunit": "^10.5.16" + }, + "autoload": { + "psr-4": { + "App\\": "app/", + "Config\\": "app/Config/" + }, + "exclude-from-classmap": [ + "**/Database/Migrations/**" + ] + }, + "autoload-dev": { + "psr-4": { + "Tests\\Support\\": "tests/_support" + } + }, + "config": { + "optimize-autoloader": true, + "preferred-install": "dist", + "sort-packages": true + }, + "scripts": { + "test": "phpunit" + } +} diff --git a/env b/env new file mode 100644 index 0000000..f359ec2 --- /dev/null +++ b/env @@ -0,0 +1,69 @@ +#-------------------------------------------------------------------- +# Example Environment Configuration file +# +# This file can be used as a starting point for your own +# custom .env files, and contains most of the possible settings +# available in a default install. +# +# By default, all of the settings are commented out. If you want +# to override the setting, you must un-comment it by removing the '#' +# at the beginning of the line. +#-------------------------------------------------------------------- + +#-------------------------------------------------------------------- +# ENVIRONMENT +#-------------------------------------------------------------------- + +# CI_ENVIRONMENT = production + +#-------------------------------------------------------------------- +# APP +#-------------------------------------------------------------------- + +# app.baseURL = '' +# If you have trouble with `.`, you could also use `_`. +# app_baseURL = '' +# app.forceGlobalSecureRequests = false +# app.CSPEnabled = false + +#-------------------------------------------------------------------- +# DATABASE +#-------------------------------------------------------------------- + +# database.default.hostname = localhost +# database.default.database = ci4 +# database.default.username = root +# database.default.password = root +# database.default.DBDriver = MySQLi +# database.default.DBPrefix = +# database.default.port = 3306 + +# If you use MySQLi as tests, first update the values of Config\Database::$tests. +# database.tests.hostname = localhost +# database.tests.database = ci4_test +# database.tests.username = root +# database.tests.password = root +# database.tests.DBDriver = MySQLi +# database.tests.DBPrefix = +# database.tests.charset = utf8mb4 +# database.tests.DBCollat = utf8mb4_general_ci +# database.tests.port = 3306 + +#-------------------------------------------------------------------- +# ENCRYPTION +#-------------------------------------------------------------------- + +# encryption.key = + +#-------------------------------------------------------------------- +# SESSION +#-------------------------------------------------------------------- + +# session.driver = 'CodeIgniter\Session\Handlers\FileHandler' +# session.savePath = null + +#-------------------------------------------------------------------- +# LOGGER +#-------------------------------------------------------------------- + +# logger.threshold = 4 diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..b408a99 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,63 @@ + + + + + + + + + + + + + ./tests + + + + + + + + + + ./app + + + ./app/Views + ./app/Config/Routes.php + + + + + + + + + + + + + + + diff --git a/preload.php b/preload.php new file mode 100644 index 0000000..9d16bb3 --- /dev/null +++ b/preload.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +use CodeIgniter\Boot; +use Config\Paths; + +/* + *--------------------------------------------------------------- + * Sample file for Preloading + *--------------------------------------------------------------- + * See https://www.php.net/manual/en/opcache.preloading.php + * + * How to Use: + * 0. Copy this file to your project root folder. + * 1. Set the $paths property of the preload class below. + * 2. Set opcache.preload in php.ini. + * php.ini: + * opcache.preload=/path/to/preload.php + */ + +// Load the paths config file +require __DIR__ . '/app/Config/Paths.php'; + +// Path to the front controller +define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR); + +class preload +{ + /** + * @var array Paths to preload. + */ + private array $paths = [ + [ + 'include' => __DIR__ . '/vendor/codeigniter4/framework/system', // Change this path if using manual installation + 'exclude' => [ + // Not needed if you don't use them. + '/system/Database/OCI8/', + '/system/Database/Postgre/', + '/system/Database/SQLite3/', + '/system/Database/SQLSRV/', + // Not needed for web apps. + '/system/Database/Seeder.php', + '/system/Test/', + '/system/CLI/', + '/system/Commands/', + '/system/Publisher/', + '/system/ComposerScripts.php', + // Not Class/Function files. + '/system/Config/Routes.php', + '/system/Language/', + '/system/bootstrap.php', + '/system/util_bootstrap.php', + '/system/rewrite.php', + '/Views/', + // Errors occur. + '/system/ThirdParty/', + ], + ], + ]; + + public function __construct() + { + $this->loadAutoloader(); + } + + private function loadAutoloader(): void + { + $paths = new Paths(); + require rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'Boot.php'; + + Boot::preload($paths); + } + + /** + * Load PHP files. + */ + public function load(): void + { + foreach ($this->paths as $path) { + $directory = new RecursiveDirectoryIterator($path['include']); + $fullTree = new RecursiveIteratorIterator($directory); + $phpFiles = new RegexIterator( + $fullTree, + '/.+((? $file) { + foreach ($path['exclude'] as $exclude) { + if (str_contains($file[0], $exclude)) { + continue 2; + } + } + + require_once $file[0]; + echo 'Loaded: ' . $file[0] . "\n"; + } + } + } +} + +(new preload())->load(); diff --git a/public/.htaccess b/public/.htaccess new file mode 100644 index 0000000..abac3cb --- /dev/null +++ b/public/.htaccess @@ -0,0 +1,49 @@ +# Disable directory browsing +Options -Indexes + +# ---------------------------------------------------------------------- +# Rewrite engine +# ---------------------------------------------------------------------- + +# Turning on the rewrite engine is necessary for the following rules and features. +# FollowSymLinks must be enabled for this to work. + + Options +FollowSymlinks + RewriteEngine On + + # If you installed CodeIgniter in a subfolder, you will need to + # change the following line to match the subfolder you need. + # http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritebase + # RewriteBase / + + # Redirect Trailing Slashes... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} (.+)/$ + RewriteRule ^ %1 [L,R=301] + + # Rewrite "www.example.com -> example.com" + RewriteCond %{HTTPS} !=on + RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] + RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L] + + # Checks to see if the user is attempting to access a valid file, + # such as an image or css document, if this isn't true it sends the + # request to the front controller, index.php + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteRule ^([\s\S]*)$ index.php/$1 [L,NC,QSA] + + # Ensure Authorization header is passed along + RewriteCond %{HTTP:Authorization} . + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + + + + # If we don't have mod_rewrite installed, all 404's + # can be sent to index.php, and everything works as normal. + ErrorDocument 404 index.php + + +# Disable server signature start +ServerSignature Off +# Disable server signature end diff --git a/public/css/admin.css b/public/css/admin.css new file mode 100644 index 0000000..4576f3b --- /dev/null +++ b/public/css/admin.css @@ -0,0 +1,81 @@ +/* ------------------------------------------------------------ + * Name : admin.css + * Desc : Admin StyleSheet + * Created : 2016/9/11 Tri-aBility by Junheum,Choi + * Updated : + ------------------------------------------------------------ */ +* { + margin: 0px; + padding: 0px; + border: 0px; +} + +html, +body { + height: 100%; +} + +div.layout_top { + height: 51px; + margin-bottom: 10px; + border-top: 1px solid gray; + border-bottom: 1px solid gray; + background-color: #e8e9ea; +} + +div.layout_bottom { + height: 51px; + margin-top: 10px; + border-top: 1px solid gray; + border-bottom: 1px solid gray; + background-color: #efefef; + background-color: #e8e9ea; +} + +table.layout_middle { + width: 100%; + /* border: 1px solid blue; */ +} + +table.layout_middle td.layout_left { + vertical-align: top; + /* border: 1px solid red; */ +} + +table.layout_middle td.layout_right { + padding-top: 5px; + padding-left: 23px; + padding-right: 5px; + padding-bottom: 5px; + /* overflow: auto; */ + /* border: 1px solid blue; */ +} + +table.layout_middle td.layout_right div.layout_header { + /*content 헤더라인*/ + height: 55px; + padding-top: 15px; + background-color: #e7e7e7; + border-top: 1px solid gray; + border-left: 1px solid gray; + border-right: 1px solid gray; + border-radius: 15px 15px 0px 0px; +} + +table.layout_middle td.layout_right div.layout_header li.nav-item {} + +table.layout_middle td.layout_right div.layout_footer { + /*content 하단라인*/ + height: 20px; + border-left: 1px solid gray; + border-right: 1px solid gray; + border-bottom: 1px solid gray; + border-radius: 0px 0px 15px 15px; +} + +table.layout_middle td.layout_right div.layout_content { + /*content 부분*/ + padding: 5px; + border-left: 1px solid gray; + border-right: 1px solid gray; +} \ No newline at end of file diff --git a/public/css/admin/form.css b/public/css/admin/form.css new file mode 100644 index 0000000..6f14a64 --- /dev/null +++ b/public/css/admin/form.css @@ -0,0 +1,40 @@ +.form-label { + font-size: 12px; + margin: 0 !important; + padding: 0 !important; +} + +/* create,modify,view 페이지용 */ +div.action_form { + /* 블록 요소로 변경 */ + margin-left: auto; + /* 자동 여백을 이용한 가로 가운데 정렬 */ + margin-right: auto; + /* 자동 여백을 이용한 가로 가운데 정렬 */ + /* border: 1px solid blue; */ + /* table-layout: fixed; 고정 레이아웃 */ + border-collapse: collapse; + /* 테두리 결합 */ +} + +div.action_form table {} + +div.action_form table th { + background-color: #f0f0f0; +} + +div.action_form table td { + text-align: center; + word-wrap: break-word; + /* 긴 단어 강제 줄바꿈 */ + white-space: normal; + /* 자동 줄바꿈 */ +} + +/* create,modify,view 페이지용 */ + +/*Form 안에서 datepicker 사용시*/ +/* datepicker의 z-index를 높여서 다른 요소 위에 표시되도록 설정 tinyMCE와 겹치는 문제 처리용용*/ +.ui-datepicker { + z-index: 9999 !important; +} \ No newline at end of file diff --git a/public/css/admin/index.css b/public/css/admin/index.css new file mode 100644 index 0000000..c9b79ff --- /dev/null +++ b/public/css/admin/index.css @@ -0,0 +1,161 @@ +.form-label { + font-size: 12px; + margin: 0 !important; + padding: 0 !important; +} + +/* create,modify,view 페이지용 */ +table.action_form { + /* 블록 요소로 변경 */ + margin-left: auto; + /* 자동 여백을 이용한 가로 가운데 정렬 */ + margin-right: auto; + /* 자동 여백을 이용한 가로 가운데 정렬 */ + /* border: 1px solid blue; */ + /* table-layout: fixed; 고정 레이아웃 */ + border-collapse: collapse; + /* 테두리 결합 */ +} + +table.action_form th { + text-align: center; + background-color: #f5f5f5; + +} + +table.action_form td { + text-align: center; + word-wrap: break-word; + /* 긴 단어 강제 줄바꿈 */ + white-space: normal; + /* 자동 줄바꿈 */ +} + +/* create,modify,view 페이지용 */ + +/*조건검색*/ +nav.index_top nav.condition { + border-color: 1px solid red; +} + +/*검색*/ +nav.index_top nav.search { + position: relative; + border-color: 1px solid red; +} + +nav.index_top nav.search input[type="text"] { + width: 150px; +} + +/*검색submit*/ +nav.index_top nav.search input[type="submit"] { + font-weight: bold; + width: 70px; + color: white; + background-color: #555555; +} + +/*검색submit*/ +nav.index_top nav.search a.excel { + position: absolute; + top: -5px; + right: -45px; + /* border-color: 1px solid red; */ +} + +/*페이지정보*/ +nav.index_top nav.pageinfo { + font-weight: bold; + /* border-color: 1px solid red; */ +} + +/* Table 부분 */ +table.index_table { + width: 100%; + /* table-layout: fixed; */ + border-collapse: collapse; +} + +table.index_table thead tr th { + white-space: nowrap; + padding-top: 15px; + padding-bottom: 15px; + font-weight: bold; + border-top: 2px solid black; + border-bottom: 1px solid silver; + background-color: #f5f5f5; + text-align: center; + /* border:1px solid silver; */ +} + +table.index_table thead th.index_head_short_column { + width: 80px; +} + +table.index_table thead th:active { + cursor: grabbing; +} + +table.index_table tbody th { + text-align: center; + /* border:1px solid silver; */ +} + +div.index_batchjob { + padding-top: 15px; + text-align: center; + /* border: 1px solid red; */ +} + +div.index_batchjob ul.nav li.nav-item { + margin-left: 10px; + /* border: 1px solid red; */ +} + +div.index_pagination { + margin-top: 20px; + /* border: 1px solid red; */ +} + +div.index_pagination ul.pagination { + /* border: 1px solid green; */ + width: fit-content; + /* UL의 너비를 내용에 맞춤 */ + margin: 0 auto; + /* 좌우 마진을 자동으로 설정하여 중앙 배치 */ + padding: 0; + list-style: none; + /* 기본 점 스타일 제거 (옵션) */ +} + +/* pager의 template가 default_full일경우 사용 */ +/* div.index_pagination ul.pagination li { + margin-left: 5px; +} + +div.index_pagination ul.pagination li a { + padding: 5px 10px 5px 10px; + font-size: 1.5rem; + color: white; + background-color: #808080; +} + +div.index_pagination ul.pagination li a:hover { + border: 1px solid black; +} + +div.index_pagination ul.pagination li.active a { + color: black; + border: 1px solid #808080; +} */ + +div.index_bottom { + padding-top: 15px; + text-align: center; + word-wrap: break-word; + /* 긴 단어 강제 줄바꿈 */ + white-space: normal; + /* 자동 줄바꿈 */ + /* border: 1px solid red; */ +} \ No newline at end of file diff --git a/public/css/admin/left_menu.css b/public/css/admin/left_menu.css new file mode 100644 index 0000000..80ca2aa --- /dev/null +++ b/public/css/admin/left_menu.css @@ -0,0 +1,56 @@ +div#left_menu { + position: fixed; + margin-top: 70px; + z-index: 100; + border: 1px solid silver; +} + +div#left_menu div#menu_button { + position: absolute; + top: -1px; + right: -20px; + width: 20px; + height: 160px; + cursor: pointer; + writing-mode: vertical-rl; + /* 세로로 글자를 출력 */ + text-orientation: upright; + /* 글자가 직립되도록 설정 */ + border-top: 1px solid silver; + border-right: 1px solid silver; + border-bottom: 1px solid silver; + border-radius: 0px 5px 5px 0px; + background-color: #e8e9ea; +} + +div#left_menu div.accordion { + display: none; + width: 20px; +} + +div#left_menu div.accordion div.main { + height: 50px; + padding-top: 15px; + padding-left: 10px; + background-color: white; + border-bottom: 1px solid silver; +} + +div#left_menu div.accordion div.accordion-item { + height: 50px; + padding-top: 15px; + background-color: #eeeeee; + border-bottom: 1px solid silver; +} + +div#left_menu div.accordion div.accordion-item:hover { + background-color: silver; +} + +div#left_menu div.accordion div.accordion-item a { + padding-left: 20px; +} + +div#left_menu div.accordion div.accordion-collapse a { + padding-left: 30px; +} \ No newline at end of file diff --git a/public/css/admin/member_link.css b/public/css/admin/member_link.css new file mode 100644 index 0000000..38ed839 --- /dev/null +++ b/public/css/admin/member_link.css @@ -0,0 +1,17 @@ +nav.top_menu ul.member-link{ + /* border:1px solid red; */ + color:#3a37f3; + padding-right:20px; +} + +nav.top_menu ul.member-link a{ + color:#3a37f3; +} + +nav.top_menu ul.member-link ul.dropdown-menu li:hover{ + background-color: #eaeaea; +} + +nav.top_menu ul.member-link ul.dropdown-menu li a{ + padding-left:10px; +} \ No newline at end of file diff --git a/public/css/admin/resizeTable.css b/public/css/admin/resizeTable.css new file mode 100644 index 0000000..8c4e075 --- /dev/null +++ b/public/css/admin/resizeTable.css @@ -0,0 +1,67 @@ +.rtc-wrapper table.rtc-table { + border-collapse: collapse; + white-space: nowrap; + margin: 0; +} + +.rtc-wrapper table.rtc-table thead, +.rtc-wrapper table.rtc-table tbody, +.rtc-wrapper table.rtc-table tfoot { + margin: 0; +} + +.rtc-wrapper table.rtc-table thead tr, +.rtc-wrapper table.rtc-table tbody tr, +.rtc-wrapper table.rtc-table tfoot tr { + margin: 0; +} + +.rtc-wrapper table.rtc-table thead tr th, +.rtc-wrapper table.rtc-table thead tr td, +.rtc-wrapper table.rtc-table tbody tr th, +.rtc-wrapper table.rtc-table tbody tr td, +.rtc-wrapper table.rtc-table tfoot tr th, +.rtc-wrapper table.rtc-table tfoot tr td { + margin: 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.rtc-wrapper table.rtc-table.rtc-table-resizing { + cursor: col-resize; +} + +.rtc-wrapper table.rtc-table.rtc-table-resizing thead, +.rtc-wrapper table.rtc-table.rtc-table-resizing thead > th, +.rtc-wrapper table.rtc-table.rtc-table-resizing thead > th > a { + cursor: col-resize; +} + +.rtc-wrapper table.rtc-table thead tr.invisible, +.rtc-wrapper table.rtc-table thead tr.invisible th { + border: none; + margin: 0; + padding: 0; + height: 0 !important; +} + +.rtc-wrapper .rtc-handle-container { + position: relative; + padding: 0; + margin: 0; + border: 0; +} + +.rtc-wrapper .rtc-handle-container .rtc-handle { + position: absolute; + width: 6.5px; + margin-left: -3.575px; + z-index: 2; + cursor: col-resize; +} + +.rtc-wrapper .rtc-handle-container .rtc-handle:last-of-type { + width: 4.5px; + margin-left: -4.95px; +} \ No newline at end of file diff --git a/public/css/admin/server_partinfo.css b/public/css/admin/server_partinfo.css new file mode 100644 index 0000000..5e069fb --- /dev/null +++ b/public/css/admin/server_partinfo.css @@ -0,0 +1,56 @@ +.server_partinfo_layer_btn { + background-color: #0d6efd; /* Bootstrap 5 primary color */ + color: #fff; /* 흰색 텍스트 */ + border: 1px solid #0d6efd; + padding: 0.375rem 0.75rem; /* 기본 패딩 */ + font-size: 1rem; + line-height: 1.5; + border-radius: 0.375rem; /* 기본 border-radius */ + cursor: pointer; + text-align: center; + display: inline-block; + text-decoration: none; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out; +} + +.server_partinfo_layer_btn:hover { + background-color: #0b5ed7; + border-color: #0a58ca; +} +.server_partinfo_layer { + position: fixed; + top: 20%; + left: 50%; + transform: translateX(-50%); + background: #fff; + border: 1px solid #ccc; + padding: 20px; + z-index: 1000; + box-shadow: 0 0 10px rgba(0,0,0,0.2); +} + +.server_partinfo_layer_inner { + text-align:center; +} + +.server_partinfo_item_list li { + margin: 5px 0; +} + +.server_partinfo_item_list label { + cursor: pointer; + color: #007bff; + text-decoration: underline; +} + +.server_partinfo_items { + margin-top: 20px; +} + +.server_partinfo_item { + padding: 5px 10px; + background: #f0f0f0; + margin: 5px 0; + display: flex; + align-items: left; +} diff --git a/public/css/common/style.css b/public/css/common/style.css new file mode 100644 index 0000000..54b28ae --- /dev/null +++ b/public/css/common/style.css @@ -0,0 +1,55 @@ +/* ------------------------------------------------------------ + * Name : admin.css + * Desc : Admin StyleSheet + * Created : 2016/9/11 Tri-aBility by Junheum,Choi + * Updated : + ------------------------------------------------------------ */ +@charset "utf-8"; + +/* user class */ +h1, +h2, +h3, +h4, +h5, +h6, +strong, +th, +.bold { + font-weight: 500; +} + +input[type=text], +input[type=password] { + display: inline-block; + border: 1px solid #ccc; + border-radius: 4px; + box-sizing: border-box; + white-space: nowrap; +} + +select, +textarea, +button { + display: inline-block; + border: 1px solid #ccc; + border-radius: 4px; + box-sizing: border-box; + white-space: nowrap; +} + +a:link { + text-decoration: none; +} + +a:visited { + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +a:active { + text-decoration: underline; +} \ No newline at end of file diff --git a/public/css/empty.css b/public/css/empty.css new file mode 100644 index 0000000..1e4df2e --- /dev/null +++ b/public/css/empty.css @@ -0,0 +1,11 @@ +/* ------------------------------------------------------------ + * Name : admin.css + * Desc : Admin StyleSheet + * Created : 2016/9/11 Tri-aBility by Junheum,Choi + * Updated : + ------------------------------------------------------------ */ +* { + margin: 0px; + padding: 0px; + border: 0px; +} \ No newline at end of file diff --git a/public/css/front.css b/public/css/front.css new file mode 100644 index 0000000..e2255e4 --- /dev/null +++ b/public/css/front.css @@ -0,0 +1,81 @@ +/* ------------------------------------------------------------ + * Name : front.css + * Desc : Admin StyleSheet + * Created : 2016/9/11 Tri-aBility by Junheum,Choi + * Updated : + ------------------------------------------------------------ */ +* { + margin: 0px; + padding: 0px; + border: 0px; +} + +html, +body { + height: 100%; +} + +div.layout_top { + height: 51px; + margin-bottom: 10px; + border-top: 1px solid gray; + border-bottom: 1px solid gray; + background-color: #e8e9ea; +} + +div.layout_bottom { + height: 51px; + margin-top: 10px; + border-top: 1px solid gray; + border-bottom: 1px solid gray; + background-color: #efefef; + background-color: #e8e9ea; +} + +table.layout_middle { + width: 100%; + /* border: 1px solid blue; */ +} + +table.layout_middle td.layout_left { + vertical-align: top; + /* border: 1px solid red; */ +} + +table.layout_middle td.layout_right { + padding-top: 5px; + padding-left: 23px; + padding-right: 5px; + padding-bottom: 5px; + /* overflow: auto; */ + /* border: 1px solid blue; */ +} + +table.layout_middle td.layout_right div.layout_header { + /*content 헤더라인*/ + height: 55px; + padding-top: 15px; + background-color: #e7e7e7; + border-top: 1px solid gray; + border-left: 1px solid gray; + border-right: 1px solid gray; + border-radius: 15px 15px 0px 0px; +} + +table.layout_middle td.layout_right div.layout_header li.nav-item {} + +table.layout_middle td.layout_right div.layout_footer { + /*content 하단라인*/ + height: 20px; + border-left: 1px solid gray; + border-right: 1px solid gray; + border-bottom: 1px solid gray; + border-radius: 0px 0px 15px 15px; +} + +table.layout_middle td.layout_right div.layout_content { + /*content 부분*/ + padding: 5px; + border-left: 1px solid gray; + border-right: 1px solid gray; +} \ No newline at end of file diff --git a/public/css/front/copyright.css b/public/css/front/copyright.css new file mode 100644 index 0000000..45a4a77 --- /dev/null +++ b/public/css/front/copyright.css @@ -0,0 +1,29 @@ +div#copyright{ + width:100%; + height:300px; + padding-top:30px; + padding-bottom:30px; + background-color:#2d2e2e; + color:white; +} + +div#copyright div#content_bottom{ + color:white; + text-align:left; + /* border-left:1px solid silver; + border-right:1px solid silver; */ +} + +div#copyright div#content_bottom .item{ + padding-top:5px; + padding-left:5px; + padding-right:5px; + border-top:1px solid silver; + border-left:1px solid silver; + border-right:1px solid silver; +} + +div#copyright div#content_bottom div.company_info{ + padding:10px; + border:1px solid silver; +} diff --git a/public/css/front/form.css b/public/css/front/form.css new file mode 100644 index 0000000..8276f4f --- /dev/null +++ b/public/css/front/form.css @@ -0,0 +1,34 @@ +/* create,modify,view 페이지용 */ +div.action_form { + /* 블록 요소로 변경 */ + margin-left: auto; + /* 자동 여백을 이용한 가로 가운데 정렬 */ + margin-right: auto; + /* 자동 여백을 이용한 가로 가운데 정렬 */ + /* border: 1px solid blue; */ + /* table-layout: fixed; 고정 레이아웃 */ + border-collapse: collapse; + /* 테두리 결합 */ +} + +div.action_form table {} + +div.action_form table th { + background-color: #f0f0f0; +} + +div.action_form table td { + text-align: center; + word-wrap: break-word; + /* 긴 단어 강제 줄바꿈 */ + white-space: normal; + /* 자동 줄바꿈 */ +} + +/* create,modify,view 페이지용 */ + +/*Form 안에서 datepicker 사용시*/ +/* datepicker의 z-index를 높여서 다른 요소 위에 표시되도록 설정 tinyMCE와 겹치는 문제 처리용용*/ +.ui-datepicker { + z-index: 9999 !important; +} \ No newline at end of file diff --git a/public/css/front/index.css b/public/css/front/index.css new file mode 100644 index 0000000..94c68a2 --- /dev/null +++ b/public/css/front/index.css @@ -0,0 +1,157 @@ +/* create,modify,view 페이지용 */ +table.action_form { + /* 블록 요소로 변경 */ + margin-left: auto; + /* 자동 여백을 이용한 가로 가운데 정렬 */ + margin-right: auto; + /* 자동 여백을 이용한 가로 가운데 정렬 */ + /* border: 1px solid blue; */ + /* table-layout: fixed; 고정 레이아웃 */ + border-collapse: collapse; + /* 테두리 결합 */ +} + +table.action_form th { + text-align: center; + background-color: #f5f5f5; +} + +table.action_form td { + text-align: center; + word-wrap: break-word; + /* 긴 단어 강제 줄바꿈 */ + white-space: normal; + /* 자동 줄바꿈 */ +} + +/* create,modify,view 페이지용 */ + +/*조건검색*/ +nav.index_top nav.condition { + border-color: 1px solid red; +} + +/*검색*/ +nav.index_top nav.search { + position: relative; + height: 30px; + border-color: 1px solid red; +} + +nav.index_top nav.search input[type="text"] { + width: 200px; + height: 30px; +} + +/*검색submit*/ +nav.index_top nav.search input[type="submit"] { + font-weight: bold; + width: 80px; + height: 30px; + color: white; + background-color: #555555; +} + +/*검색submit*/ +nav.index_top nav.search a.excel { + position: absolute; + top: -9px; + right: -45px; + /* border-color: 1px solid red; */ +} + +/*페이지정보*/ +nav.index_top nav.pageinfo { + font-weight: bold; + /* border-color: 1px solid red; */ +} + +/* Table 부분 */ +table.index_table { + width: 100%; + /* table-layout: fixed; */ + border-collapse: collapse; +} + +table.index_table thead th { + white-space: nowrap; + padding-top: 15px; + padding-bottom: 15px; + font-weight: bold; + border-top: 2px solid black; + border-bottom: 1px solid silver; + background-color: #f5f5f5; + text-align: center; + /* border:1px solid silver; */ +} + +table.index_table thead th.index_head_short_column { + width: 80px; +} + +table.index_table thead th:active { + cursor: grabbing; +} + +table.index_table tbody th { + text-align: center; + /* border:1px solid silver; */ +} + +div.index_batchjob { + padding-top: 15px; + text-align: center; + /* border: 1px solid red; */ +} + +div.index_batchjob ul.nav li.nav-item { + margin-left: 10px; + /* border: 1px solid red; */ +} + +div.index_pagination { + margin-top: 20px; + /* border: 1px solid red; */ +} + +div.index_pagination ul.pagination { + /* border: 1px solid green; */ + width: fit-content; + /* UL의 너비를 내용에 맞춤 */ + margin: 0 auto; + /* 좌우 마진을 자동으로 설정하여 중앙 배치 */ + padding: 0; + list-style: none; + /* 기본 점 스타일 제거 (옵션) */ +} + +/* pager의 template가 default_full일경우 사용 */ +/* div.index_pagination ul.pagination li { + margin-left: 5px; +} + +div.index_pagination ul.pagination li a { + padding: 5px 10px 5px 10px; + font-size: 1.5rem; + color: white; + background-color: #808080; +} + +div.index_pagination ul.pagination li a:hover { + border: 1px solid black; +} + +div.index_pagination ul.pagination li.active a { + color: black; + border: 1px solid #808080; +} */ + +div.index_bottom { + padding-top: 15px; + text-align: center; + word-wrap: break-word; + /* 긴 단어 강제 줄바꿈 */ + white-space: normal; + /* 자동 줄바꿈 */ + /* border: 1px solid red; */ +} \ No newline at end of file diff --git a/public/css/front/left_menu.css b/public/css/front/left_menu.css new file mode 100644 index 0000000..cc89e40 --- /dev/null +++ b/public/css/front/left_menu.css @@ -0,0 +1,56 @@ +div#left_menu { + position: fixed; + margin-top: 60px; + z-index: 100; + border: 1px solid silver; +} + +div#left_menu div#menu_button { + position: absolute; + top: -1px; + right: -21px; + width: 20px; + height: 160px; + cursor: pointer; + writing-mode: vertical-rl; + /* 세로로 글자를 출력 */ + text-orientation: upright; + /* 글자가 직립되도록 설정 */ + border-top: 1px solid silver; + border-right: 1px solid silver; + border-bottom: 1px solid silver; + border-radius: 0px 5px 5px 0px; + background-color: #e8e9ea; +} + +div#left_menu div.accordion { + display: none; + width: 20px; +} + +div#left_menu div.accordion div.main { + height: 50px; + padding-top: 15px; + padding-left: 10px; + background-color: white; + border-bottom: 1px solid silver; +} + +div#left_menu div.accordion div.accordion-item { + height: 50px; + padding-top: 15px; + background-color: #eeeeee; + border-bottom: 1px solid silver; +} + +div#left_menu div.accordion div.accordion-item:hover { + background-color: silver; +} + +div#left_menu div.accordion div.accordion-item a { + padding-left: 20px; +} + +div#left_menu div.accordion div.accordion-collapse a { + padding-left: 30px; +} \ No newline at end of file diff --git a/public/css/front/login.css b/public/css/front/login.css new file mode 100644 index 0000000..3f80970 --- /dev/null +++ b/public/css/front/login.css @@ -0,0 +1,80 @@ +.login-page { + background-image: url('/images/login-background.jpg'); + background-size: cover; + background-position: center; + height: 100vh; + display: flex; + align-items: center; + justify-content: center; +} + +.login-content { + background-color: rgba(255, 255, 255, 0.9); + border-radius: 10px; + padding: 40px; + box-shadow: 0 0 20px rgba(0, 0, 0, 0.1); + width: 400px; +} + +.login-title { + text-align: center; + margin-bottom: 30px; + color: #333; +} + +.input-group { + margin-bottom: 20px; +} + +.input-group label { + display: block; + margin-bottom: 5px; + color: #555; +} + +.input-group input { + width: 100%; + padding: 10px; + border: 1px solid #ddd; + border-radius: 5px; +} + +.btn-login { + width: 100%; + padding: 12px; + background-color: #007bff; + color: white; + border: none; + border-radius: 5px; + cursor: pointer; + font-size: 16px; + margin-bottom: 15px; +} + +.login-options { + display: flex; + justify-content: space-between; +} + +.btn-google, +.btn-facebook { + flex: 1; + padding: 10px; + border: none; + border-radius: 5px; + cursor: pointer; + font-size: 14px; + text-align: center; + text-decoration: none; +} + +.btn-google { + background-color: #db4437; + color: white; + margin-right: 10px; +} + +.btn-facebook { + background-color: #28a745; + color: white; +} \ No newline at end of file diff --git a/public/css/front/member_link.css b/public/css/front/member_link.css new file mode 100644 index 0000000..38ed839 --- /dev/null +++ b/public/css/front/member_link.css @@ -0,0 +1,17 @@ +nav.top_menu ul.member-link{ + /* border:1px solid red; */ + color:#3a37f3; + padding-right:20px; +} + +nav.top_menu ul.member-link a{ + color:#3a37f3; +} + +nav.top_menu ul.member-link ul.dropdown-menu li:hover{ + background-color: #eaeaea; +} + +nav.top_menu ul.member-link ul.dropdown-menu li a{ + padding-left:10px; +} \ No newline at end of file diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..7ecfce214cbdbedc15d8348babeff5cd7e720488 GIT binary patch literal 5430 zcmeHL&npB`9Dn5Kuy>cuLGmAPauLohTgugsgTofC9NbV!aa0tgTofgxl%f=?Y?Sh& zWMxI9hibZ5LZ@~9&$;7J-7ai$2=7ByD3A3P1*hfQz|8$LL= zUz~w$;90HjJ=)Ss!V^NuI2Za%(z#lli~7u{+nbyOi;~<-#pGX{K<~tb_C6Lj^YSY9 zuHBEb(bRJ+>$(mjNuamQtlmY!MgdXJjDiJ*`fSvC!*oskp+}sjm(MWyz%r29BW!f*m(x|(w?cOiYFaD0y8pq z9eCfscMhGYa>i@!YdSYJ(-6XZ(W@wc#d9lm1l3S%FF!rC_waiB@V}AM)ez?!Gp$os wgQ-p&yk8A*^lZ5Jw#)Gj@LI_qy{H^P{^jt7C;ag)RHAYMwkN>;6;PJx7hHm1jsO4v literal 0 HcmV?d00001 diff --git a/public/images/common/com_icon3.png b/public/images/common/com_icon3.png new file mode 100644 index 0000000000000000000000000000000000000000..eb662cdeaee19e73456ca27f170837968794acbf GIT binary patch literal 5005 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 literal 0 HcmV?d00001 diff --git a/public/images/common/discord.png b/public/images/common/discord.png new file mode 100644 index 0000000000000000000000000000000000000000..4a2233c03abeed0bf7d3491c9b2d908efc9f96db GIT binary patch literal 663 zcmV;I0%-k-P)s;2ZE2sPe>BNwb)jz%At_<{0o4_zeWRTDvE{-4nM1 zi~vW=Eq)$YmB}Aq40r&1P~Q@;2yCh?sxMHC#f~dCkk`4m#Tzw^mN*IA1?D|Z7uDvK zJE`A!c}H?n32%X{W4Ho51A2k8Kn6IVmQi1?Vpg2Ith@qwM>4D6Zv7qtdVspPQwSW? zU@RAT1@aE175EGM0uHfvGyog&J{}f$Mq$ia4!+&m{&pvTK_?iK)4Kk>2JLuS>LTk;K~(1IUI9z^AzkNFNS+0Xz3`2`)>Y@`;}$o+y!=(hIh!vmq5zb2+6NAARDg z#1^No8fYRpP4XykL^W*5irDdN!H2*y&{yVPalLYuuRHZ z3|s-u0L?(HTC?s0*ML#rr;|4&uSR_jRLi?QYt9;7Q2!-hF2Qj;r(EMAu%LdcakA9Z zwW)Z)WJXij<6JCqI$rI3-&V`3FXy~VmUBZMfpb~02aP!lvI6;>1s;*b3=DjSL74G){)!X^24*%-7srqc=eILsJ%SS@8m{|Jk1fA{H|g}> z&cGlS$HXL7w!2^19TTqj*5~!D2vBYlVVSDT^!gBozR{&_k27@&Ou8Lg91{=D@!Fxf z^7Pxczt7$C-mOlis$9elTFzi84(fjXZo6``)}f&XM8lV`m-*~ z{lMQNFUwsE-`qbWw`F}9%iTP|iinmt;q}c*R_}OrD2C4ovRl=BHQOa+?dF?TRpJgS zeOr6^ecXa1&5tHa56XR6E4t8nF5~$~!CP;6b|@(+&6N)Asd#nCfptb{`T2SKH?3Qq z$g%lH0At$HM>~?l`;?cem5m4Ii=(-k9#U{9(Y4jC(Pf zqQ^u*j=Hp5exBsQNfSSoAKT}Cc<&DOp0{@_y@1Z>5RGi8+5Y_F-Dz{)*|D!IId#MD zjA}ykZ@!{=A9u7YroOM3KHshCJZ#08B zd*0;Z+NB{8ieV{??AHAf{azO~y!6(ZLP*HG5MP(|@z94K9M2eC($zlAv-or` z-beS5V8WmLCH>wY_f5-XJiWAUYlFQb>x@u-tuP!hs@0>N_HiN88L!sDHLo)(`XXzz z{+*8P>iShR*W2~)fk2k2pM@v40s&{vw);7Eo$jrEZ$Ax~O&B~~{an^LB{Ts5L7AAy literal 0 HcmV?d00001 diff --git a/public/images/common/kakaotalk.png b/public/images/common/kakaotalk.png new file mode 100644 index 0000000000000000000000000000000000000000..cf7a87c83a2d7dfce219afc7b6d409bda2036980 GIT binary patch literal 1399 zcmaKqdo+}J7{`C_`_AQ^dFQ>%o3OGX5lRio8coM-#Fz*}218^jQ>!#hS{m=sJ$rV~d7kHcp65BA^Zny_GX4F$ zaIO&-0Dw!p#eq6C`H(20tGpMH**YpLsp$aB=tilJ0oWw~;As>9&V>LN z#A|BLJLGy2^qJ^hfLeL~NU(NjZo$0hPe4z^Q;hOA}zcrZ0v z(6U^t^D_B*kbk%kDDa|Q-;VVRUwRmPjV&u_m-%GR(@HpD?8xj*Yp19{;G z+;Rb8V~NzC!mm^j^NnG1Q~1U?;z=j9(vjh|lKHHgpOemIAi!iEywD7xNQlVfubzz)d1f`$XIHP-2RmuX{Scos7D=CW->Q6lHGlkT z&k~3CaYF-G#zyc!6Lsxpf`>u5Mz({+WMxW^ywwIFJ6n!N1he0c($&Xs3p2#p0znX9ZHZV} zAd43vrXR!e3}K3ZOikdL3VeEqj*CIpdb7f1tSC9V@JnpLe0Z4+qWv119ONs4SSH4> zpBJ;_E9~)YYKaw+xQ%l(54+b)p(y0EoKahWr>Hp^75e@WJv%!)v*+7J-8XPFfqpWt z)|s1b?alB0u&!SpuNy)eq+a5d^lH|JhOLqKda@s*FhrQ=X!qUHt-B>+w;-$5n5Zaa z1E(<5P%eB499aoT9md`rihhNtu1@62l@%Xa@9OU@7Y7B2*C_TD93g{?rGY+StJe`c z<;YyU{0rITHF?27BiX6NwJZboVyR3@;IU)zmyb{HdOa*iy$HF8i(A{g2~6Pl0Fk~b zX)Y=Xm&@g0p?7ce_BA#2hBpg)nuX3U(~eJTBZd_N{i{Uvb;(I1Z{I#2f#I~h9_}Ma z`BSMKis&x&gARU9K)YRCm3qfZjyhA)RBEkOSEv-Os`nGT?|d7ILVJZZPr?$XIclaT z!_&2Fh)&7Ys6NV$C|ws28XO@D57}-V($?0~xnxnn9XNM%OB~{Jesh8*L82L(n3#OM zw$MtXI-~8^+nqh2m7RdfPqb2;mQtZKeo|ZWYIK?WLTuIP{@ilvkZpDT;c7+Xxeevo zKAT_eZ0)L)=7(Q$yOm<@vQX~mdtHA?$q9EP|D;q;mXKv;Ao3aAw!$M{(=*zXp;w0A z-EAsqe$jun1QQC!cf5eIket4I$!`W~ru+l3!7tL(>gA+u>{H>Xoys{b24P_jyM;Ep zpE)i1gc>&wT;M(#py~ARGz*!(jF8B8Q2N1VisoIqI-vDoF pd|C%s{q3Mp#ckZFiH?i^H?w@jUnX{fKAw&N5>G#IrF+!gKLJ(D3{U_7 literal 0 HcmV?d00001 diff --git a/public/images/common/news.png b/public/images/common/news.png new file mode 100644 index 0000000000000000000000000000000000000000..fa77ce2e3fb172694b38dd59da0def06a78def28 GIT binary patch literal 4746 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 literal 0 HcmV?d00001 diff --git a/public/images/common/pdf.png b/public/images/common/pdf.png new file mode 100644 index 0000000000000000000000000000000000000000..bb18a19e9ddaae7307995160ad1c3a74ca74cd44 GIT binary patch literal 1392 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 I&?3|S1F{PgKmY&$ literal 0 HcmV?d00001 diff --git a/public/images/common/top_skype.png b/public/images/common/top_skype.png new file mode 100644 index 0000000000000000000000000000000000000000..90355c0b4791cc6b3ab0d62de8a0479558e17dc3 GIT binary patch literal 2166 zcmbVOX;f2Z8ji9!Age60h=zd5SRuJd$VQ@Mxj@8V*o3l~m|P%`;-AvJnG6eW=}Fp~}6W6%;Y z0~6%R!|@bsC|cr`tc3iNeF8+uu_CG%vvUWUuAw0YWRO~j*2tuC6-~pyEZLEikX+5> zFfho8i&!G20aP}TOmPKCBq9h>0Dwxt<3J+QgTMv}IM5YXvGFl3l|TTg96Z5;#KHjp zNTE_WY|w)VvH>!Q$tDn1xLmnPEtHF(6xIvSWH8^5(}vw)qTyZ0hWbot39~scBCf>>ZwJ$IN0!+sBF>Ur&_a<4%m8Ua%rN155J%up!wbzN5 zb^u#->^U8T?RX;lX#vCi7xZz;mD!p~ntLf@oP1f#t@g}E%_2Phs zq1SC6XghgKOU)EUPGPjMlG~aDuCP~-$1|Y$46h#@fx^hXh-7F|n78~EM-`hGK8#SGkdoo?1m1k5`Sq!|nQIWyu zkDZiKx-UM+s`oY2CH3fbP<5?7ojQ&08QBGdozD%+X|i=19CS1%Htq{wuz2gMF&C6) ztlcz)I-1rzNX9_*H;aag@|j^)RBkk{VWS)aJ$pDjPO*N&0BZzgJtP8puPQ&<)o@lL|7|K^Qx$kw>D zimONGeU0o}(p#T=-u^Hn(mrf@gs{-IB{11MfBlbXB_6?RE5Q}4%^b{_ z+1ivXF{+S39y%3e!ZIA0HF2+q(2aI>pDd&rP^%2@4OwUZ-AyZd`{h4=IVt3y?y_{# z{BZWG%rt|()t2tv=6TZDSIw!#qq?uwY|D~br8Mz>tNRzZzBfI!#k8uX8Qee~p1q>& z&`{d?^>>pg*Q@Vu#E!W=Es|590$x@cYldm+eV1cv2R+Z+K`EAUA2n>HDI+%RVddIB znKSkGZ`ECMQ%-CfY|fcE;Ki%5dBN;msystemDirectory . '/Boot.php'; + +exit(Boot::bootWeb($paths)); diff --git a/public/js/admin.js b/public/js/admin.js new file mode 100644 index 0000000..a485a38 --- /dev/null +++ b/public/js/admin.js @@ -0,0 +1,73 @@ +/* ------------------------------------------------------------ + * Name : admin.js + * Desc : Admin Javascrip + * Created : 2016/9/11 Tri-aBility by Junheum,Choi + * Updated : + ------------------------------------------------------------ */ + +function is_NumericKey(evt,obj){ + var charCode = (evt.which) ? evt.which : event.keyCode; + switch(charCode){ + case 48://0 + case 49://1 + case 50://2 + case 51://3 + case 52://4 + case 53://5 + case 54://6 + case 55://7 + case 56://8 + case 57://9 + case 96://KeyPad:0 + case 97://KeyPad:1 + case 98://KeyPad:2 + case 99://KeyPad:3 + case 100://KeyPad:4 + case 101://KeyPad:5 + case 102://KeyPad:6 + case 103://KeyPad:7 + case 104://KeyPad:8 + case 105://KeyPad:9 + break; + default: + alert('숫자만 가능합니다['+charCode+']'); + obj.value = obj.value.substring(0,obj.value.length-1); + break; + } +} +function is_NumericType(data){ + if(!data.match(/^[0-9]+$/)){ + throw (new Error('숫자가 아닌값['+data+']이 있습니다')); + } + return true; +}// +function change_CurrencyFormat(obj,currencies){ + //var currencies = document.getElementsByClassName("currency"); + var total_currency = 0; + for(i=0; i { alert("복사가 완료되었습니다."); }) + .catch(err => { console.log('복사가 오류', err); }) +} \ No newline at end of file diff --git a/public/js/admin/clipboard.js b/public/js/admin/clipboard.js new file mode 100644 index 0000000..4c53982 --- /dev/null +++ b/public/js/admin/clipboard.js @@ -0,0 +1,30 @@ +function copyServerPartToClipboard(text) { + try { + if (navigator.clipboard && navigator.clipboard.writeText) { + // HTTPS 환경 + navigator.clipboard.writeText(text) + .then(() => alert(text + "\n 복사되었습니다.")) + .catch(err => alert("실패: " + err)); + } else { + // HTTP 환경 fallback + const temp = document.createElement("textarea"); + temp.value = text; + document.body.appendChild(temp); + temp.select(); + // document.execCommand("copy"); --- DEPRECATED --- + document.body.removeChild(temp); + alert(text + "\n 복사되었습니다."); + } + } catch (err) { + alert("복사 실패: " + err); + } +} + +function copyServerPartsToClipboard() { + // 모든 .serverparts div에서 text-data 속성값 수집 + const elements = document.querySelectorAll(".serverparts"); + const texts = Array.from(elements).map(el => el.getAttribute("text-data") || ""); + // console.log(texts); + const combined = texts.join("\n"); + copyServerPartToClipboard(combined); +} \ No newline at end of file diff --git a/public/js/admin/form.js b/public/js/admin/form.js new file mode 100644 index 0000000..1977628 --- /dev/null +++ b/public/js/admin/form.js @@ -0,0 +1,55 @@ +// /public/js/admin/form.js +window.initFormModal = function (context) { + const $context = context ? $(context) : $(document); + + // ✅ 캘린더 + $context.find(".calender").datepicker({ + changeYear: true, + changeMonth: true, + yearRange: "-10:+0", + dateFormat: "yy-mm-dd" + }); + + // ✅ TinyMCE + if ($context.find(".tinymce").length) { + if (typeof tinymce !== "undefined") { + tinymce.remove(); // 기존 인스턴스 제거 + tinymce.init({ + selector: ".tinymce", + license_key: "gpl", + height: 250, + plugins: "advlist autolink lists link image charmap preview anchor", + toolbar: "undo redo | bold italic underline | align | link image | code fullscreen preview", + menubar: "file edit view insert format tools table help" + }); + } + } + + // ✅ Select2 (입력 허용) + if ($context.find(".select-field").length) { + $context.find(".select-field").select2({ + theme: "bootstrap-5", + tags: true, + allowClear: true, + width: '100%', + dropdownAutoWidth: true, + language: { + noResults: function () { + return "직접 입력 후 Enter"; // 사용자 안내 + } + } + }); + } + + console.log("✅ Form initialized inside modal:", context); +}; + +// ✅ DOM 전체 로드 후 (페이지 최초 로드시 실행) +document.addEventListener("DOMContentLoaded", function () { + window.initFormModal(document); +}); + +// ✅ Modal 로드 시점에 재초기화 +$(document).on("shown.bs.modal", ".modal", function (e) { + window.initFormModal(this); +}); \ No newline at end of file diff --git a/public/js/admin/index.js b/public/js/admin/index.js new file mode 100644 index 0000000..a41c934 --- /dev/null +++ b/public/js/admin/index.js @@ -0,0 +1,33 @@ +document.addEventListener('DOMContentLoaded', function() { + //class가 calender인 inputbox용,날짜field용 + if (document.querySelector(".calender")) { + $(".calender").datepicker({ + changeYear: true, + changeMonth: true, + yearRange: "-10:+0", + dateFormat: "yy-mm-dd" + }); + } + if (document.querySelector(".batchjobuids_checkboxs")) { + //id가 batchjobuids_checkbox인 버튼을 클릭시 class가 batchjobuids_checkboxs인 checkbox용 + $('#batchjobuids_checkbox').click(function (event) { + if (this.checked) { + $('.batchjobuids_checkboxs').each(function () { //loop checkbox + $(this).prop('checked', true); //check + }); + } else { + $('.batchjobuids_checkboxs').each(function () { //loop checkbox + $(this).prop('checked', false); //uncheck + }); + } + }); + } + if (document.querySelector(".select-field")) { + //class가 select-field인 SelectBox용 + $(".select-field").select2({ + theme: "classic", + width: 'style', + dropdownAutoWidth: true + }); + } +}); \ No newline at end of file diff --git a/public/js/admin/left_menu.js b/public/js/admin/left_menu.js new file mode 100644 index 0000000..1cfc98e --- /dev/null +++ b/public/js/admin/left_menu.js @@ -0,0 +1,13 @@ +function sideMenuToggle(left_menu) { + $accordion = $("#accordion")[0]; + if (accordion.clientWidth == 0){ + accordion.style.display = "block"; + $("#accordion").css({ "width": '217px' }) + $("#menu_button").html("메뉴닫기"); + } + else { + accordion.style.display = "none"; + $("#accordion").css({"width":'20px'}) + $("#menu_button").html("메뉴열기"); + } +}//toggleMenu \ No newline at end of file diff --git a/public/js/admin/resizeTable.js b/public/js/admin/resizeTable.js new file mode 100644 index 0000000..58a8c6b --- /dev/null +++ b/public/js/admin/resizeTable.js @@ -0,0 +1,843 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.validide_resizableTableColumns = {})); +})(this, (function (exports) { + 'use strict'; + + var ResizableConstants = /** @class */ (function () { + function ResizableConstants() { + } + ResizableConstants.dataPropertyName = 'validide_rtc_data_object'; + ResizableConstants.classes = { + table: 'rtc-table', + wrapper: 'rtc-wrapper', + handleContainer: 'rtc-handle-container', + handle: 'rtc-handle', + tableResizing: 'rtc-table-resizing', + columnResizing: 'rtc-column-resizing', + }; + ResizableConstants.attributes = { + dataResizable: 'data-rtc-resizable', + dataResizableTable: 'data-rtc-resizable-table' + }; + ResizableConstants.data = { + resizable: 'rtcResizable', + resizableTable: 'rtcResizableTable' + }; + ResizableConstants.events = { + pointerDown: ['mousedown', 'touchstart'], + pointerMove: ['mousemove', 'touchmove'], + pointerUp: ['mouseup', 'touchend'], + windowResize: ['resize'], + eventResizeStart: 'eventResizeStart.rtc', + eventResize: 'eventResize.rtc', + eventResizeStop: 'eventResizeStop.rtc' + }; + return ResizableConstants; + }()); + + var WidthsData = /** @class */ (function () { + function WidthsData() { + this.column = 0; + this.table = 0; + } + return WidthsData; + }()); + var PointerData = /** @class */ (function () { + function PointerData() { + this.x = null; + this.isDoubleClick = false; + } + return PointerData; + }()); + var ResizableEventData = /** @class */ (function () { + function ResizableEventData(column, dragHandler) { + this.pointer = new PointerData(); + this.originalWidths = new WidthsData(); + this.newWidths = new WidthsData(); + this.column = column; + this.dragHandler = dragHandler; + } + return ResizableEventData; + }()); + + var Utilities = /** @class */ (function () { + function Utilities() { + } + Utilities.kebabCaseToCamelCase = function (str) { + return str.replace(Utilities.kebabCaseRegex, function (m) { return m[1].toUpperCase(); }); + }; + Utilities.parseStringToType = function (str) { + if (str.length == 0 || Utilities.onlyWhiteSpace.test(str)) + return str; + if (Utilities.trueRegex.test(str)) + return true; + if (Utilities.falseRegex.test(str)) + return false; + if (Utilities.notEmptyOrWhiteSpace.test(str)) { + var temp = +str; + if (!isNaN(temp)) + return temp; + } + return str; + }; + Utilities.regexEscapeRegex = /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g; + Utilities.kebabCaseRegex = /(\-\w)/g; + Utilities.trueRegex = /^true$/i; + Utilities.falseRegex = /^false$/i; + Utilities.onlyWhiteSpace = /^\s$/; + Utilities.notEmptyOrWhiteSpace = /\S/; + return Utilities; + }()); + + var UtilitiesDOM = /** @class */ (function () { + function UtilitiesDOM() { + } + UtilitiesDOM.getDataAttributesValues = function (el) { + if (!el) + return null; + var returnValue = {}; + if (el.dataset) { + for (var prop in el.dataset) { + if (el.dataset.hasOwnProperty(prop)) { + returnValue[prop] = Utilities.parseStringToType(el.dataset[prop] || ''); + } + } + } + else { + for (var i = 0; i < el.attributes.length; i++) { + if (!/^data\-/.test(el.attributes[i].name)) + continue; + var name_1 = Utilities.kebabCaseToCamelCase(el.attributes[i].name.replace('data-', '')); + returnValue[name_1] = Utilities.parseStringToType(el.attributes[i].value); + } + } + return returnValue; + }; + return UtilitiesDOM; + }()); + + var ResizableOptions = /** @class */ (function () { + function ResizableOptions(options, element) { + if (options === void 0) { options = null; } + if (element === void 0) { element = null; } + this.resizeFromBody = true; + this.minWidth = 40; + this.maxWidth = null; + this.doubleClickDelay = 500; + this.maxInitialWidthHint = null; + this.store = null; + this.overrideValues(options); + this.overrideValuesFromElement(element); + } + ResizableOptions.prototype.overrideValues = function (options) { + if (options === void 0) { options = null; } + if (!options) + return; + for (var prop in options) { + if (this.hasOwnProperty(prop)) { + this[prop] = options[prop]; + } + } + }; + ResizableOptions.prototype.overrideValuesFromElement = function (element) { + if (element === void 0) { element = null; } + if (!element) + return; + var elementOptions = UtilitiesDOM.getDataAttributesValues(element); + this.overrideValues(elementOptions); + }; + return ResizableOptions; + }()); + + var ResizableTableColumns = /** @class */ (function () { + function ResizableTableColumns(table, options) { + if (typeof table !== 'object' || table === null || table.toString() !== '[object HTMLTableElement]') + throw 'Invalid argument: "table".\nResizableTableColumns requires that the table element is a not null HTMLTableElement object!'; + if (typeof table[ResizableConstants.dataPropertyName] !== 'undefined') + throw "Existing \"".concat(ResizableConstants.dataPropertyName, "\" property.\nTable element already has a '").concat(ResizableConstants.dataPropertyName, "' attached object!"); + this.id = ResizableTableColumns.getInstanceId(); + this.table = table; + this.options = new ResizableOptions(options, table); + this.wrapper = null; + this.ownerDocument = table.ownerDocument; + this.tableHeaders = []; + this.dragHandlesContainer = null; + this.originalWidths = []; + this.eventData = null; + this.lastPointerDown = 0; + this.init(); + this.table[ResizableConstants.dataPropertyName] = this; + } + ResizableTableColumns.prototype.init = function () { + this.validateMarkup(); + this.createHandlerReferences(); + this.wrapTable(); + this.assignTableHeaders(); + this.storeOriginalWidths(); + this.setHeaderWidths(); + this.createDragHandles(); + this.restoreColumnWidths(); + this.checkTableWidth(); + this.syncHandleWidths(); + this.registerWindowResizeHandler(); + }; + ResizableTableColumns.prototype.dispose = function () { + this.destroyDragHandles(); + this.restoreOriginalWidths(); + this.unwrapTable(); + this.onPointerDownRef = null; + this.onPointerMoveRef = null; + this.onPointerUpRef = null; + this.table[ResizableConstants.dataPropertyName] = void (0); + }; + ResizableTableColumns.prototype.validateMarkup = function () { + var theadCount = 0; + var tbodyCount = 0; + var thead = null; + for (var index = 0; index < this.table.childNodes.length; index++) { + var element = this.table.childNodes[index]; + if (element.nodeName === 'THEAD') { + theadCount++; + thead = element; + } + else if (element.nodeName === 'TBODY') { + tbodyCount++; + } + } + if (thead === null || theadCount !== 1) + throw "Markup validation: thead count.\nResizableTableColumns requires that the table element has one(1) table head element. Current count: ".concat(theadCount); + if (tbodyCount !== 1) + throw "Markup validation: tbody count.\nResizableTableColumns requires that the table element has one(1) table body element. Current count: ".concat(tbodyCount); + var theadRowCount = 0; + var firstRow = null; + for (var index = 0; index < thead.childNodes.length; index++) { + var element = thead.childNodes[index]; + if (element.nodeName === 'TR') { + theadRowCount++; + if (firstRow === null) { + firstRow = element; + } + } + } + if (firstRow === null || theadRowCount < 1) + throw "Markup validation: thead row count.\nResizableTableColumns requires that the table head element has at least one(1) table row element. Current count: ".concat(theadRowCount); + var headerCellsCount = 0; + var invalidHeaderCellsCount = 0; + for (var index = 0; index < firstRow.childNodes.length; index++) { + var element = firstRow.childNodes[index]; + if (element.nodeName === 'TH') { + headerCellsCount++; + } + else if (element.nodeName === 'TD') { + invalidHeaderCellsCount++; + } + } + if (headerCellsCount < 1) + throw "Markup validation: thead first row cells count.\nResizableTableColumns requires that the table head's first row element has at least one(1) table header cell element. Current count: ".concat(headerCellsCount); + if (invalidHeaderCellsCount !== 0) + throw "Markup validation: thead first row invalid.\nResizableTableColumns requires that the table head's first row element has no(0) table cell(TD) elements. Current count: ".concat(invalidHeaderCellsCount); + }; + ResizableTableColumns.prototype.wrapTable = function () { + if (this.wrapper) + return; + this.wrapper = this.ownerDocument.createElement('div'); + this.wrapper.classList.add(ResizableConstants.classes.wrapper); + var tableOriginalParent = this.table.parentNode; + tableOriginalParent.insertBefore(this.wrapper, this.table); + tableOriginalParent.removeChild(this.table); + this.wrapper.appendChild(this.table); + this.table.classList.add(ResizableConstants.classes.table); + }; + ResizableTableColumns.prototype.unwrapTable = function () { + this.table.classList.remove(ResizableConstants.classes.table); + if (!this.wrapper) + return; + var tableOriginalParent = this.wrapper.parentNode; + tableOriginalParent.insertBefore(this.table, this.wrapper); + tableOriginalParent.removeChild(this.wrapper); + this.wrapper = null; + }; + ResizableTableColumns.prototype.assignTableHeaders = function () { + var tableHeader; + var firstTableRow; + for (var index = 0; index < this.table.childNodes.length; index++) { + var element = this.table.childNodes[index]; + if (element.nodeName === 'THEAD') { + tableHeader = element; + break; + } + } + if (!tableHeader) + return; + for (var index = 0; index < tableHeader.childNodes.length; index++) { + var element = tableHeader.childNodes[index]; + if (element.nodeName === 'TR') { + firstTableRow = element; + break; + } + } + if (!firstTableRow) + return; + for (var index = 0; index < firstTableRow.childNodes.length; index++) { + var element = firstTableRow.childNodes[index]; + if (element.nodeName === 'TH') { + this.tableHeaders.push(element); + } + } + }; + ResizableTableColumns.prototype.storeOriginalWidths = function () { + var _this = this; + this.tableHeaders + .forEach(function (el) { + _this.originalWidths.push({ + el: el, + detail: el.style.width + }); + }); + this.originalWidths.push({ + el: this.table, + detail: this.table.style.width + }); + }; + ResizableTableColumns.prototype.restoreOriginalWidths = function () { + this.originalWidths + .forEach(function (itm) { + itm.el.style.width = itm.detail; + }); + }; + ResizableTableColumns.prototype.setHeaderWidths = function () { + var _this = this; + this.tableHeaders + .forEach(function (el) { + var width = el.offsetWidth; + var constrainedWidth = _this.constrainWidth(el, width); + if (typeof _this.options.maxInitialWidthHint === 'number') { + constrainedWidth = Math.min(constrainedWidth, _this.options.maxInitialWidthHint); + } + _this.updateWidth(el, constrainedWidth, true, false); + }); + }; + ResizableTableColumns.prototype.constrainWidth = function (el, width) { + var result = width; + result = Math.max(result, this.options.minWidth || -Infinity); + result = Math.min(result, this.options.maxWidth || +Infinity); + return result; + }; + ResizableTableColumns.prototype.createDragHandles = function () { + var _this = this; + var _a; + if (this.dragHandlesContainer != null) + throw 'Drag handlers already created. Call if you wish to recreate them'; + this.dragHandlesContainer = this.ownerDocument.createElement('div'); + (_a = this.wrapper) === null || _a === void 0 ? void 0 : _a.insertBefore(this.dragHandlesContainer, this.table); + this.dragHandlesContainer.classList.add(ResizableConstants.classes.handleContainer); + this.getResizableHeaders() + .forEach(function () { + var _a; + var handler = _this.ownerDocument.createElement('div'); + handler.classList.add(ResizableConstants.classes.handle); + (_a = _this.dragHandlesContainer) === null || _a === void 0 ? void 0 : _a.appendChild(handler); + }); + ResizableConstants.events.pointerDown + .forEach(function (evt, evtIdx) { + var _a; + (_a = _this.dragHandlesContainer) === null || _a === void 0 ? void 0 : _a.addEventListener(evt, _this.onPointerDownRef, false); + }); + }; + ResizableTableColumns.prototype.destroyDragHandles = function () { + var _this = this; + var _a, _b; + if (this.dragHandlesContainer !== null) { + ResizableConstants.events.pointerDown + .forEach(function (evt, evtIdx) { + var _a; + (_a = _this.dragHandlesContainer) === null || _a === void 0 ? void 0 : _a.removeEventListener(evt, _this.onPointerDownRef, false); + }); + (_b = (_a = this.dragHandlesContainer) === null || _a === void 0 ? void 0 : _a.parentElement) === null || _b === void 0 ? void 0 : _b.removeChild(this.dragHandlesContainer); + } + }; + ResizableTableColumns.prototype.getDragHandlers = function () { + var nodes = this.dragHandlesContainer == null + ? null + : this.dragHandlesContainer.querySelectorAll(".".concat(ResizableConstants.classes.handle)); + return nodes + ? Array.prototype.slice.call(nodes).filter(function (el) { return el.nodeName === 'DIV'; }) + : new Array(); + }; + ResizableTableColumns.prototype.restoreColumnWidths = function () { + if (!this.options.store) + return; + var tableId = ResizableTableColumns.generateTableId(this.table); + if (tableId.length === 0) + return; + var data = this.options.store.get(tableId); + if (!data) + return; + this.getResizableHeaders() + .forEach(function (el) { + var width = data.columns[ResizableTableColumns.generateColumnId(el)]; + if (typeof width !== 'undefined') { + ResizableTableColumns.setWidth(el, width); + } + }); + if (typeof data.table !== 'undefined') { + ResizableTableColumns.setWidth(this.table, data.table); + } + }; + ResizableTableColumns.prototype.checkTableWidth = function () { + var _a; + var wrapperWidth = this.wrapper.clientWidth; + var tableWidth = this.table.offsetWidth; + var difference = wrapperWidth - tableWidth; + if (difference <= 0) + return; + var resizableWidth = 0; + var addedWidth = 0; + var headersDetails = []; + this.tableHeaders + .forEach(function (el, idx) { + if (el.hasAttribute(ResizableConstants.attributes.dataResizable)) { + var detail = { + el: el, + detail: el.offsetWidth + }; + headersDetails.push(detail); + resizableWidth += detail.detail; + } + }); + var leftToAdd = 0; + var lastResizableCell = null; + var currentDetail; + while ((currentDetail = headersDetails.shift())) { + leftToAdd = difference - addedWidth; + lastResizableCell = currentDetail.el; + var extraWidth = Math.floor((currentDetail.detail / resizableWidth) * difference); + extraWidth = Math.min(extraWidth, leftToAdd); + var newWidth = this.updateWidth(currentDetail.el, currentDetail.detail + extraWidth, false, true); + addedWidth += (newWidth - currentDetail.detail); + if (addedWidth >= difference) + break; + } + leftToAdd = difference - addedWidth; + if (leftToAdd > 0) { + var lastCell = ((_a = headersDetails[0]) === null || _a === void 0 ? void 0 : _a.el) || lastResizableCell || this.tableHeaders[this.tableHeaders.length - 1]; + var lastCellWidth = lastCell.offsetWidth; + this.updateWidth(lastCell, lastCellWidth, true, true); + } + ResizableTableColumns.setWidth(this.table, wrapperWidth); + }; + ResizableTableColumns.prototype.syncHandleWidths = function () { + var _this = this; + var tableWidth = this.table.clientWidth; + ResizableTableColumns.setWidth(this.dragHandlesContainer, tableWidth); + this.dragHandlesContainer.style.minWidth = "".concat(tableWidth, "px"); + var headers = this.getResizableHeaders(); + this.getDragHandlers() + .forEach(function (el, idx) { + var height = (_this.options.resizeFromBody ? _this.table : _this.table.tHead).clientHeight; + if (idx < headers.length) { + var th = headers[idx]; + var left = th.offsetWidth; + left += ResizableTableColumns.getOffset(th).left; + left -= ResizableTableColumns.getOffset(_this.dragHandlesContainer).left; + el.style.left = "".concat(left, "px"); + el.style.height = "".concat(height, "px"); + } + }); + }; + ResizableTableColumns.prototype.getResizableHeaders = function () { + return this.tableHeaders + .filter(function (el, idx) { + return el.hasAttribute(ResizableConstants.attributes.dataResizable); + }); + }; + ResizableTableColumns.prototype.handlePointerDown = function (event) { + this.handlePointerUp(); + var target = event ? event.target : null; + if (target == null) + return; + if (target.nodeName !== 'DIV' || !target.classList.contains(ResizableConstants.classes.handle)) + return; + if (typeof event.button === 'number' && event.button !== 0) + return; // this is not a left click + var dragHandler = target; + var gripIndex = this.getDragHandlers().indexOf(dragHandler); + var resizableHeaders = this.getResizableHeaders(); + if (gripIndex >= resizableHeaders.length) + return; + var millisecondsNow = (new Date()).getTime(); + var isDoubleClick = (millisecondsNow - this.lastPointerDown) < this.options.doubleClickDelay; + var column = resizableHeaders[gripIndex]; + var columnWidth = column.offsetWidth; + var widths = { + column: columnWidth, + table: this.table.offsetWidth + }; + var eventData = new ResizableEventData(column, dragHandler); + eventData.pointer = { + x: ResizableTableColumns.getPointerX(event), + isDoubleClick: isDoubleClick + }; + eventData.originalWidths = widths; + eventData.newWidths = widths; + this.detachHandlers(); //make sure we do not have extra handlers + this.attachHandlers(); + this.table.classList.add(ResizableConstants.classes.tableResizing); + this.wrapper.classList.add(ResizableConstants.classes.tableResizing); + dragHandler.classList.add(ResizableConstants.classes.columnResizing); + column.classList.add(ResizableConstants.classes.columnResizing); + this.lastPointerDown = millisecondsNow; + this.eventData = eventData; + var eventToDispatch = new CustomEvent(ResizableConstants.events.eventResizeStart, { + detail: { + column: column, + columnWidth: columnWidth, + table: this.table, + tableWidth: this.table.clientWidth + } + }); + this.table.dispatchEvent(eventToDispatch); + event.preventDefault(); + }; + ResizableTableColumns.prototype.handlePointerMove = function (event) { + if (!this.eventData || !event) + return; + var difference = (ResizableTableColumns.getPointerX(event) || 0) - (this.eventData.pointer.x || 0); + if (difference === 0) { + return; + } + var tableWidth = this.eventData.originalWidths.table + difference; + var columnWidth = this.constrainWidth(this.eventData.column, this.eventData.originalWidths.column + difference); + ResizableTableColumns.setWidth(this.table, tableWidth); + ResizableTableColumns.setWidth(this.eventData.column, columnWidth); + this.eventData.newWidths = { + column: columnWidth, + table: tableWidth + }; + var eventToDispatch = new CustomEvent(ResizableConstants.events.eventResize, { + detail: { + column: this.eventData.column, + columnWidth: columnWidth, + table: this.table, + tableWidth: tableWidth + } + }); + this.table.dispatchEvent(eventToDispatch); + }; + ResizableTableColumns.prototype.handlePointerUp = function () { + this.detachHandlers(); + if (!this.eventData) + return; + if (this.eventData.pointer.isDoubleClick) { + this.handleDoubleClick(); + } + this.table.classList.remove(ResizableConstants.classes.tableResizing); + this.wrapper.classList.remove(ResizableConstants.classes.tableResizing); + this.eventData.dragHandler.classList.remove(ResizableConstants.classes.columnResizing); + this.eventData.column.classList.remove(ResizableConstants.classes.columnResizing); + this.checkTableWidth(); + this.syncHandleWidths(); + this.refreshWrapperStyle(); + this.saveColumnWidths(); + var widths = this.eventData.newWidths || this.eventData.originalWidths; + var eventToDispatch = new CustomEvent(ResizableConstants.events.eventResizeStop, { + detail: { + column: this.eventData.column, + columnWidth: widths.column, + table: this.table, + tableWidth: widths.table + } + }); + this.table.dispatchEvent(eventToDispatch); + this.eventData = null; + }; + ResizableTableColumns.prototype.handleDoubleClick = function () { + if (!this.eventData || !this.eventData.column) + return; + var column = this.eventData.column; + var colIndex = this.tableHeaders.indexOf(column); + var maxWidth = 0; + var indicesToSkip = []; + this.tableHeaders + .forEach(function (el, idx) { + if (!el.hasAttribute(ResizableConstants.attributes.dataResizable)) { + indicesToSkip.push(idx); + } + }); + var span = this.ownerDocument.createElement('span'); + span.style.position = 'absolute'; + span.style.left = '-99999px'; + span.style.top = '-99999px'; + span.style.visibility = 'hidden'; + this.ownerDocument.body.appendChild(span); + var rows = this.table.querySelectorAll('tr'); + for (var rowIndex = 0; rowIndex < rows.length; rowIndex++) { + var element = rows[rowIndex]; + var cells = element.querySelectorAll('td, th'); + var currentIndex = 0; + for (var cellIndex = 0; cellIndex < cells.length; cellIndex++) { + var cell = cells[cellIndex]; + var colSpan = 1; + if (cell.hasAttribute('colspan')) { + var colSpanString = cell.getAttribute('colspan') || '1'; + var parsed = parseInt(colSpanString); + if (!isNaN(parsed)) { + colSpan = parsed; + } + else { + colSpan = 1; + } + } + if (indicesToSkip.indexOf(cellIndex) === -1 + && colSpan === 1 + && currentIndex === colIndex) { + maxWidth = Math.max(maxWidth, ResizableTableColumns.getTextWidth(cell, span)); + break; + } + currentIndex += colSpan; + } + } + this.ownerDocument.body.removeChild(span); + var difference = maxWidth - column.offsetWidth; + if (difference === 0) { + return; + } + var tableWidth = this.eventData.originalWidths.table + difference; + var columnWidth = this.constrainWidth(this.eventData.column, this.eventData.originalWidths.column + difference); + ResizableTableColumns.setWidth(this.table, tableWidth); + ResizableTableColumns.setWidth(this.eventData.column, columnWidth); + this.eventData.newWidths = { + column: columnWidth, + table: tableWidth, + }; + var eventToDispatch = new CustomEvent(ResizableConstants.events.eventResize, { + detail: { + column: this.eventData.column, + columnWidth: columnWidth, + table: this.table, + tableWidth: tableWidth + } + }); + this.table.dispatchEvent(eventToDispatch); + this.checkTableWidth(); + this.syncHandleWidths(); + this.saveColumnWidths(); + }; + ResizableTableColumns.prototype.attachHandlers = function () { + var _this = this; + ResizableConstants.events.pointerMove + .forEach(function (evt, evtIdx) { + _this.ownerDocument.addEventListener(evt, _this.onPointerMoveRef, false); + }); + ResizableConstants.events.pointerUp + .forEach(function (evt, evtIdx) { + _this.ownerDocument.addEventListener(evt, _this.onPointerUpRef, false); + }); + }; + ResizableTableColumns.prototype.detachHandlers = function () { + var _this = this; + ResizableConstants.events.pointerMove + .forEach(function (evt, evtIdx) { + _this.ownerDocument.removeEventListener(evt, _this.onPointerMoveRef, false); + }); + ResizableConstants.events.pointerUp + .forEach(function (evt, evtIdx) { + _this.ownerDocument.removeEventListener(evt, _this.onPointerUpRef, false); + }); + }; + ResizableTableColumns.prototype.refreshWrapperStyle = function () { + if (this.wrapper == null) + return; + var original = this.wrapper.style.overflowX; + this.wrapper.style.overflowX = 'hidden'; + this.wrapper.style.overflowX = original; + }; + ResizableTableColumns.prototype.saveColumnWidths = function () { + if (!this.options.store) + return; + var tableId = ResizableTableColumns.generateTableId(this.table); + if (tableId.length === 0) + return; + var data = { + table: this.table.offsetWidth, + columns: {} + }; + this.getResizableHeaders() + .forEach(function (el) { + data.columns[ResizableTableColumns.generateColumnId(el)] = el.offsetWidth; + }); + this.options.store.set(tableId, data); + }; + ResizableTableColumns.prototype.createHandlerReferences = function () { + var _this = this; + if (!this.onPointerDownRef) { + this.onPointerDownRef = ResizableTableColumns.debounce(function (evt) { + _this.handlePointerDown(evt); + }, 100, true); + } + if (!this.onPointerMoveRef) { + this.onPointerMoveRef = ResizableTableColumns.debounce(function (evt) { + _this.handlePointerMove(evt); + }, 5, false); + } + if (!this.onPointerUpRef) { + this.onPointerUpRef = ResizableTableColumns.debounce(function (evt) { + _this.handlePointerUp(); + }, 100, true); + } + }; + ResizableTableColumns.prototype.registerWindowResizeHandler = function () { + var win = this.ownerDocument.defaultView; + if (ResizableTableColumns.windowResizeHandlerRef) + return; + ResizableTableColumns.windowResizeHandlerRef = ResizableTableColumns.debounce(ResizableTableColumns.onWindowResize, 50, false); + ResizableConstants.events.windowResize + .forEach(function (evt, idx) { + win === null || win === void 0 ? void 0 : win.addEventListener(evt, ResizableTableColumns.windowResizeHandlerRef, false); + }); + }; + ResizableTableColumns.prototype.handleWindowResize = function () { + this.checkTableWidth(); + this.syncHandleWidths(); + this.saveColumnWidths(); + }; + ResizableTableColumns.prototype.updateWidth = function (cell, suggestedWidth, skipConstrainCheck, skipTableResize) { + var originalCellWidth = cell.offsetWidth; + var columnWidth = skipConstrainCheck + ? suggestedWidth + : this.constrainWidth(cell, suggestedWidth); + ResizableTableColumns.setWidth(cell, columnWidth); + if (!skipTableResize) { + var difference = columnWidth - originalCellWidth; + var tableWidth = this.table.offsetWidth + difference; + ResizableTableColumns.setWidth(this.table, tableWidth); + } + return columnWidth; + }; + ResizableTableColumns.onWindowResize = function (event) { + var win = event ? event.target : null; + if (win == null) + return; + var tables = win.document.querySelectorAll(".".concat(ResizableConstants.classes.table)); + for (var index = 0; index < tables.length; index++) { + var table = tables[index]; + if (typeof table[ResizableConstants.dataPropertyName] !== 'object') + continue; + table[ResizableConstants.dataPropertyName].handleWindowResize(); + } + }; + ResizableTableColumns.generateColumnId = function (el) { + var columnId = (el.getAttribute(ResizableConstants.attributes.dataResizable) || '') + .trim() + .replace(/\./g, '_'); + return columnId; + }; + ResizableTableColumns.generateTableId = function (table) { + var tableId = (table.getAttribute(ResizableConstants.attributes.dataResizableTable) || '') + .trim() + .replace(/\./g, '_'); + return tableId.length + ? "rtc/".concat(tableId) + : tableId; + }; + ResizableTableColumns.setWidth = function (element, width) { + var strWidth = width.toFixed(2); + strWidth = width > 0 ? strWidth : '0'; + element.style.width = "".concat(strWidth, "px"); + }; + ResizableTableColumns.getInstanceId = function () { + return ResizableTableColumns.instancesCount++; + }; + ResizableTableColumns.getPointerX = function (event) { + if (event.type.indexOf('touch') === 0) { + var tEvent = event; + if (tEvent.touches && tEvent.touches.length) { + return tEvent.touches[0].pageX; + } + if (tEvent.changedTouches && tEvent.changedTouches.length) { + return tEvent.changedTouches[0].pageX; + } + } + return event.pageX; + }; + ResizableTableColumns.getTextWidth = function (contentElement, measurementElement) { + var _a, _b; + if (!contentElement || !measurementElement) + return 0; + var text = ((_a = contentElement.textContent) === null || _a === void 0 ? void 0 : _a.trim().replace(/\s/g, ' ')) + ' '; //add extra space to ensure we are not add the `...` + var styles = (_b = contentElement.ownerDocument.defaultView) === null || _b === void 0 ? void 0 : _b.getComputedStyle(contentElement); + ['fontFamily', 'fontSize', 'fontWeight', 'padding', 'border', 'boxSizing'] + .forEach(function (prop) { + measurementElement.style[prop] = styles[prop]; + }); + measurementElement.innerHTML = text; + return measurementElement.offsetWidth; + }; + ResizableTableColumns.getOffset = function (el) { + if (!el) + return { top: 0, left: 0 }; + var rect = el.getBoundingClientRect(); + return { + top: rect.top + el.ownerDocument.body.scrollTop, + left: rect.left + el.ownerDocument.body.scrollLeft + }; + }; + ResizableTableColumns.instancesCount = 0; + ResizableTableColumns.windowResizeHandlerRef = null; + ResizableTableColumns.debounce = function (func, wait, immediate) { + var timeout = null; + var debounced = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + var later = function () { + timeout = null; + if (!immediate) { + func.apply(void 0, args); + } + }; + var callNow = immediate && !timeout; + if (timeout) { + clearTimeout(timeout); + } + timeout = setTimeout(later, wait); + if (callNow) { + func.apply(void 0, args); + } + }; + return debounced; + }; + return ResizableTableColumns; + }()); + + exports.PointerData = PointerData; + exports.ResizableConstants = ResizableConstants; + exports.ResizableEventData = ResizableEventData; + exports.ResizableOptions = ResizableOptions; + exports.ResizableTableColumns = ResizableTableColumns; + exports.Utilities = Utilities; + exports.UtilitiesDOM = UtilitiesDOM; + exports.WidthsData = WidthsData; + +})); +(function (window, ResizableTableColumns, undefined) { + var store = window.store && window.store.enabled ? window.store : null; + var els = document.querySelectorAll('table.data'); + for (var index = 0; index < els.length; index++) { + var table = els[index]; + if (table['rtc_data_object']) { + continue; + } + var options = { + store: store + }; + if (table.querySelectorAll('thead > tr').length > 1) { + options.resizeFromBody = false; + } + new ResizableTableColumns(els[index], options); + } +})(window, window.validide_resizableTableColumns.ResizableTableColumns, void (0)); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/public/js/admin/server/ipAutoComplete.js b/public/js/admin/server/ipAutoComplete.js new file mode 100644 index 0000000..6389d17 --- /dev/null +++ b/public/js/admin/server/ipAutoComplete.js @@ -0,0 +1,172 @@ + +// 기본 실행 (페이지 로드시 전체 document) +class IpAutoComplete { + /** + * @param {HTMLElement|string} input + * @param {HTMLElement|string} panel + * @param {string[]} ipArray + * @param {object} opts + */ + constructor(input, panel, ipArray = [], opts = {}) { + this.inputEl = typeof input === 'string' ? document.querySelector(input) : input; + this.panelEl = typeof panel === 'string' ? document.querySelector(panel) : panel; + if (!this.inputEl || !this.panelEl) throw new Error('Invalid input/panel element'); + + this.opts = Object.assign({ + validateIPv4: true, + enforceListOnly: false, + previewOnFocus: true, // 포커스 시 상위 N개 미리보기 + previewCount: 30, // 미리보기 개수 + resultLimit: 1000 // 너무 많을 때 렌더 최대치(성능 안전장치) + }, opts); + + this.errorEl = document.getElementById('ipError'); + this.ipv4Re = /^(25[0-5]|2[0-4]\d|[01]?\d\d?)(\.(25[0-5]|2[0-4]\d|[01]?\d\d?)){3}$/; + this.setArray(ipArray); + + // 상태 + this.activeIndex = -1; + + // 이벤트 + this.onInput = this._handleInput.bind(this); + this.onChange = this._handleChange.bind(this); + this.onFocus = this._handleFocus.bind(this); + this.onKeydown = this._handleKeydown.bind(this); + this.onClickOutside = this._handleClickOutside.bind(this); + + this.inputEl.addEventListener('input', this.onInput); + this.inputEl.addEventListener('change', this.onChange); + this.inputEl.addEventListener('focus', this.onFocus); + this.inputEl.addEventListener('keydown', this.onKeydown); + document.addEventListener('mousedown', this.onClickOutside); + } + + destroy(){ + this.inputEl.removeEventListener('input', this.onInput); + this.inputEl.removeEventListener('change', this.onChange); + this.inputEl.removeEventListener('focus', this.onFocus); + this.inputEl.removeEventListener('keydown', this.onKeydown); + document.removeEventListener('mousedown', this.onClickOutside); + this.hidePanel(); + } + + setArray(arr){ this.ipArray = Array.from(new Set((arr||[]).filter(Boolean))); } + + _handleInput(e){ + const q = (e.target.value||'').trim(); + this._filterAndRender(q); + this._checkIPv4(q); + } + + _handleChange(){ + const v = (this.inputEl.value||'').trim(); + this._checkIPv4(v); + if (this.opts.enforceListOnly && v && !this.ipArray.includes(v)) { + this._setError('❌ 목록에 없는 IP입니다.'); + } + } + + _handleFocus(){ + if (!this.inputEl.value && this.opts.previewOnFocus) { + this._renderPanel(this.ipArray.slice(0, this.opts.resultLimit)); + this.showPanel(); + } + } + + _handleKeydown(e){ + if (this.panelEl.hidden) return; + const items = this._items(); + if (!items.length) return; + + if (e.key === 'ArrowDown'){ e.preventDefault(); this._move(1); } + else if (e.key === 'ArrowUp'){ e.preventDefault(); this._move(-1); } + else if (e.key === 'Enter'){ + if (this.activeIndex >= 0){ e.preventDefault(); this._pick(items[this.activeIndex].dataset.value); } + } else if (e.key === 'Escape'){ this.hidePanel(); } + } + + _handleClickOutside(e){ + if (!this.inputEl.closest('.ac-wrap')?.contains(e.target)) this.hidePanel(); + } + + _filterAndRender(query){ + if (!query){ + this.hidePanel(); + return; + } + const q = query.toLowerCase(); + let results = this.ipArray.filter(ip => ip.toLowerCase().includes(q)); + if (this.opts.resultLimit > 0) results = results.slice(0, this.opts.resultLimit); + if (results.length){ this._renderPanel(results); this.showPanel(); } + else { this.hidePanel(); } + } + + _renderPanel(list){ + this.panelEl.innerHTML = ''; + this.activeIndex = -1; + + const frag = document.createDocumentFragment(); + list.forEach((ip) => { + const item = document.createElement('div'); + item.className = 'ac-item'; + item.textContent = ip; + item.dataset.value = ip; + item.addEventListener('mousedown', (ev) => { ev.preventDefault(); this._pick(ip); }); + frag.appendChild(item); + }); + this.panelEl.appendChild(frag); + } + + _items(){ return Array.from(this.panelEl.querySelectorAll('.ac-item')); } + + _move(delta){ + const items = this._items(); + if (!items.length) return; + this.activeIndex = (this.activeIndex + delta + items.length) % items.length; + items.forEach(el => el.classList.remove('active')); + const el = items[this.activeIndex]; + el.classList.add('active'); + el.scrollIntoView({ block: 'nearest' }); + } + + _pick(value){ + this.inputEl.value = value; + this.hidePanel(); + this._checkIPv4(value); + } + + showPanel(){ this.panelEl.hidden = false; } + hidePanel(){ this.panelEl.hidden = true; this.activeIndex = -1; } + + _checkIPv4(val){ + if (!this.opts.validateIPv4 || !val){ this._setError(''); return; } + this._setError(this.ipv4Re.test(val) ? '' : '❌ IPv4 형식이 아닙니다.'); + } + + _setError(text){ if (this.errorEl) this.errorEl.textContent = text || ''; } +} + +/* ipData(JSON) 읽기: (이미 페이지에 있다면) */ +function parseEmbeddedJson(id){ + const el=document.getElementById(id); if(!el) return []; + let txt=el.textContent||''; + txt = txt + .replace(/\/\*[\s\S]*?\*\//g,'') + .replace(/(^|[^:])\/\/.*$/mg,'$1') + .replace(/,\s*([}\]])/g,'$1'); + try { const data=JSON.parse(txt); return Array.isArray(data)?data:[]; } + catch(e){ console.error('ipData parse error',e); return []; } +} + +/* 초기화 */ +document.addEventListener('DOMContentLoaded', () => { + // ipData