diff --git a/.gitignore b/.gitignore index 8fb962b..433946d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,18 @@ -# ---> CodeIgniter -*/config/development -*/logs/log-*.php -!*/logs/index.html -*/cache/* -!system/cache/* -!*/cache/index.html -!*/cache/.htaccess - -user_guide_src/build/* -user_guide_src/cilexer/build/* -user_guide_src/cilexer/dist/* -user_guide_src/cilexer/pycilexer.egg-info/* - -#codeigniter 3 -application/logs/* -!application/logs/index.html -!application/logs/.htaccess -/vendor/ - +#codeigniter4 +.env +composer.lock +vendor/ +public/vendors/ +public/tinymce_uploads/ +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/excel/* +!writable/excel/index.html \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..148e7f7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014-2019 British Columbia Institute of Technology +Copyright (c) 2019-2024 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 index fd7338f..f5f8ee1 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ -# dbms +# Automation diff --git a/app/.htaccess b/app/.htaccess new file mode 100644 index 0000000..97c65d2 --- /dev/null +++ b/app/.htaccess @@ -0,0 +1,6 @@ + + Require all denied + + + Deny from all + \ No newline at end of file diff --git a/app/Common.php b/app/Common.php new file mode 100644 index 0000000..95f5544 --- /dev/null +++ b/app/Common.php @@ -0,0 +1,15 @@ + + */ + 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..76cd926 --- /dev/null +++ b/app/Config/Autoload.php @@ -0,0 +1,94 @@ +|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 @@ + + */ + public array $file = [ + 'storePath' => 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 + */ + 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 + */ + 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..17f4871 --- /dev/null +++ b/app/Config/Constants.php @@ -0,0 +1,317 @@ + "guest", + 'STATUS' => "use", + 'EMPTY' => "", + 'DELIMITER_FILE' => "||", + 'DELIMITER_ROLE' => ",", +]); +define('MESSAGES', [ + 'CREATED' => '생성되었습니다.', + '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' => '동기화 결과가 없습니다.', +]); +//URL +define('URLS', [ + 'LOGIN' => '/user/login', + 'GOOGLE_LOGIN' => '/user/google_login', + 'SIGNUP' => '/user/signup', + 'LOGOUT' => '/user/logout', +]); +//회원ROLE +define('ROLES', [ + 'guest', + 'user', + 'vip', + 'manager', + 'cloudflare', + 'director', + 'master', +]); +//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', [ + 'LOGO' => '', + 'EXCEL' => '', + 'PDF' => '', + 'GOOGLE' => 'Google', + 'MEMBER' => '', + 'LOGIN' => '', + 'LOGOUT' => '', + 'HOME' => '', + 'MENU' => '', + 'NEW' => '', + 'REPLY' => '', + 'DATABASE' => '', + 'DELETE' => '', + 'REBOOT' => '', + 'RELOAD' => '', + 'SETUP' => '', + 'FLAG' => '', + 'SEARCH' => '', + 'PLAY' => '', + 'CART' => '', + 'CARD' => '', + 'DEPOSIT' => '', + 'DESKTOP' => '', + 'UP' => '', + 'DOWN' => '', + 'LEFT' => '', + 'RIGHT' => '', + 'IMAGE_FILE' => '', + 'CLOUD' => '', + 'SIGNPOST' => '', + 'LOCK' => '', + 'UNLOCK' => '', + 'BOX' => '', + 'BOXS' => '', +]); +//배너관련 +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' => [ + '', + '', + '', + '', + '', + ], + ], +]); + +//List의 Page당 갯수 +define('DEFAULT_LIST_PERPAGE', $_ENV['LIST_PERPAGE'] ?? $_SERVER['LIST_PERPAGE'] ?? 20); \ No newline at end of file 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/download.php b/app/Views/templates/download.php new file mode 100644 index 0000000..3c52984 --- /dev/null +++ b/app/Views/templates/download.php @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + +
$field ?>
\ 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..e35fef7 --- /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/app/index.html b/app/index.html new file mode 100644 index 0000000..69df4e1 --- /dev/null +++ b/app/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + 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..4d161ea --- /dev/null +++ b/composer.json @@ -0,0 +1,53 @@ +{ + "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", + "cloudflare/sdk": "^1.3", + "codeigniter4/framework": "^4.5", + "google/apiclient": "^2.15.0", + "guzzlehttp/guzzle": "^7.9", + "io-developer/php-whois": "^4.1", + "phpoffice/phpspreadsheet": "^1.27", + "symfony/css-selector": "^7.1", + "symfony/dom-crawler": "^7.1", + "tinymce/tinymce": "^7.3", + "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, + "process-timeout": 600 + }, + "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..75d86f5 --- /dev/null +++ b/preload.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +/* + *--------------------------------------------------------------- + * 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' => [ + '/system/bootstrap.php', + // Not needed if you don't use them. + '/system/Database/OCI8/', + '/system/Database/Postgre/', + '/system/Database/SQLite3/', + '/system/Database/SQLSRV/', + // Not needed. + '/system/Database/Seeder.php', + '/system/Test/', + '/system/Language/', + '/system/CLI/', + '/system/Commands/', + '/system/Publisher/', + '/system/ComposerScripts.php', + '/Views/', + // Errors occur. + '/system/Config/Routes.php', + '/system/ThirdParty/', + ], + ], + ]; + + public function __construct() + { + $this->loadAutoloader(); + } + + private function loadAutoloader(): void + { + $paths = new Config\Paths(); + require rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'Boot.php'; + + CodeIgniter\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..7440ad5 --- /dev/null +++ b/public/css/admin/form.css @@ -0,0 +1,28 @@ +/* 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 페이지용 */ \ 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..9dc021e --- /dev/null +++ b/public/css/admin/index.css @@ -0,0 +1,165 @@ +/* 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 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; */ +} + +div.index_bottom div.index_action_form { + margin-top: 20px; + /* border: 1px solid red; */ +} + +div.index_bottom div.index_action_form iframe { + width: 100%; + border: none; + /* border: 1px solid blue; */ +} \ 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/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..7440ad5 --- /dev/null +++ b/public/css/front/form.css @@ -0,0 +1,28 @@ +/* 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 페이지용 */ \ 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..8a66b59 --- /dev/null +++ b/public/css/front/index.css @@ -0,0 +1,168 @@ +/* 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; */ +} + +div.index_bottom div.index_action_form { + margin-top: 20px; + /* border: 1px solid red; */ +} + +div.index_bottom div.index_action_form iframe { + width: 100%; + border: none; + /* border: 1px solid blue; */ +} \ 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 0000000..7ecfce2 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/images/common/com_icon3.png b/public/images/common/com_icon3.png new file mode 100644 index 0000000..eb662cd Binary files /dev/null and b/public/images/common/com_icon3.png differ diff --git a/public/images/common/discord.png b/public/images/common/discord.png new file mode 100644 index 0000000..4a2233c Binary files /dev/null and b/public/images/common/discord.png differ diff --git a/public/images/common/excel.png b/public/images/common/excel.png new file mode 100644 index 0000000..e67fc00 Binary files /dev/null and b/public/images/common/excel.png differ diff --git a/public/images/common/kakaotalk.png b/public/images/common/kakaotalk.png new file mode 100644 index 0000000..cf7a87c Binary files /dev/null and b/public/images/common/kakaotalk.png differ diff --git a/public/images/common/news.png b/public/images/common/news.png new file mode 100644 index 0000000..fa77ce2 Binary files /dev/null and b/public/images/common/news.png differ diff --git a/public/images/common/pdf.png b/public/images/common/pdf.png new file mode 100644 index 0000000..bb18a19 Binary files /dev/null and b/public/images/common/pdf.png differ diff --git a/public/images/common/telegram.png b/public/images/common/telegram.png new file mode 100644 index 0000000..c88f3fa Binary files /dev/null and b/public/images/common/telegram.png differ diff --git a/public/images/common/top.png b/public/images/common/top.png new file mode 100644 index 0000000..84d194d Binary files /dev/null and b/public/images/common/top.png differ diff --git a/public/images/common/top_skype.png b/public/images/common/top_skype.png new file mode 100644 index 0000000..90355c0 Binary files /dev/null and b/public/images/common/top_skype.png differ diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..5ec58a7 --- /dev/null +++ b/public/index.php @@ -0,0 +1,56 @@ +systemDirectory . '/Boot.php'; + +exit(CodeIgniter\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/form.js b/public/js/admin/form.js new file mode 100644 index 0000000..0c13ad3 --- /dev/null +++ b/public/js/admin/form.js @@ -0,0 +1,119 @@ +(function() { + //console.log('form.js가 로드되었습니다.'); + + function initializeModalComponents(modal) { + //console.log('모달 컴포넌트 초기화 시작'); + + // 약간의 지연을 주어 모달이 완전히 렌더링되도록 함 + setTimeout(() => { + initializeCalendar(modal); + initializeSelectField(modal); + initializeTinyMCE(modal); + }, 100); + } + + function initializeCalendar(container) { + const calendarInputs = container.querySelectorAll('.calender'); + if (calendarInputs.length > 0) { + //console.log('달력 초기화 시작'); + $(calendarInputs).datepicker({ + changeYear: true, + changeMonth: true, + yearRange: "-10:+0", + dateFormat: "yy-mm-dd" + }); + //console.log('달력 초기화 완료'); + } + } + + function initializeSelectField(container) { + const selectFields = container.querySelectorAll('.select-field'); + if (selectFields.length > 0 && typeof $.fn.select2 !== 'undefined') { + //console.log('선택 필드 초기화 시작'); + $(selectFields).select2({ + theme: "classic", + width: 'style', + dropdownAutoWidth: true, + dropdownParent: $('#index_action_form'), + containerCssClass: 'text-start', // 왼쪽 정렬을 위한 클래스 추가 + dropdownCssClass: 'text-start' // 드롭다운 메뉴도 왼쪽 정렬 + }); + //console.log('선택 필드 초기화 완료'); + } + } + + function initializeTinyMCE(container) { + const textareas = container.querySelectorAll('textarea.tinymce'); + if (textareas.length > 0 && typeof tinymce !== 'undefined') { + //console.log('TinyMCE 초기화 시작'); + tinymce.init({ + selector: textareas, + plugins: ['code', 'image', 'preview', 'table', 'emoticons', 'autoresize'], + height: 600, + automatic_uploads: false, + images_upload_url: '/tinymce_upload.php', + images_upload_handler: function (blobInfo, success, failure) { + var xhr, formData; + xhr = new XMLHttpRequest(); + xhr.withCredentials = false; + xhr.open('POST', '/tinymce_upload.php'); + xhr.onload = function () { + var json; + if (xhr.status != 200) { + failure('HTTP Error: ' + xhr.status); + return; + } + json = JSON.parse(xhr.responseText); + if (!json || typeof json.file_path != 'string') { + failure('Invalid JSON: ' + xhr.responseText); + return; + } + success(json.file_path); + }; + formData = new FormData(); + formData.append('file', blobInfo.blob(), blobInfo.filename()); + xhr.send(formData); + }, + setup: function(editor) { + editor.on('init', function() { + //console.log('TinyMCE 에디터 초기화 완료'); + }); + } + }); + } + } + + // MutationObserver 설정 + const observer = new MutationObserver(function(mutations) { + mutations.forEach(function(mutation) { + if (mutation.type === 'childList') { + const addedNodes = mutation.addedNodes; + for (let i = 0; i < addedNodes.length; i++) { + if (addedNodes[i].nodeType === 1 && addedNodes[i].matches('.modal')) { + //console.log('새로운 모달이 추가되었습니다.'); + initializeModalComponents(addedNodes[i]); + } + } + } + }); + }); + + // 전체 문서에 대해 MutationObserver 시작 + observer.observe(document.body, { childList: true, subtree: true }); + + // 모달 표시 이벤트 리스너 + document.body.addEventListener('shown.bs.modal', function(event) { + //console.log('모달이 표시되었습니다.'); + initializeModalComponents(event.target); + }); + + // 페이지 로드 시 전체 문서에 대해 초기화 실행 + //console.log('페이지 로드 시 초기화 시작'); + initializeModalComponents(document.body); + + // 전역 스코프에 함수 노출 + window.initializeForm = function() { + //console.log('initializeForm 함수가 호출되었습니다.'); + initializeModalComponents(document.body); + }; +})(); \ 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/common/product.js b/public/js/common/product.js new file mode 100644 index 0000000..673a2ed --- /dev/null +++ b/public/js/common/product.js @@ -0,0 +1,30 @@ + +function calculator(order_price) { + var parts = Array.from(document.getElementsByClassName("vhost_parts")); + parts.forEach(function(part) { //loop + //console.log(part); + order_price += parseInt((part.getAttribute('cost') - part.getAttribute('sale')) * part.options[part.selectedIndex].value); + document.getElementById('price').value = order_price; + document.getElementById('order_price').textContent = new Intl.NumberFormat().format(order_price); + }); + var current = document.getElementById('paymentday'); + if (!current.selectedIndex) { + alert("결제일을 선택해주세요"); + current.focus(); + return false + } +} +function addDevice(category, key, label) { + var categoryBox = document.getElementById(category + "Box"); + var div = document.createElement("div"); + var checkbox = document.createElement("input"); + checkbox.setAttribute("type", "checkbox"); + checkbox.setAttribute("name", category + '[]'); + checkbox.setAttribute("value", key); + checkbox.setAttribute("checked", true); + checkbox.setAttribute("class", 'device'); + div.appendChild(checkbox); + div.appendChild(document.createTextNode(label)); + // console.log(div); + categoryBox.appendChild(div); +} \ No newline at end of file diff --git a/public/js/empty.js b/public/js/empty.js new file mode 100644 index 0000000..f973e71 --- /dev/null +++ b/public/js/empty.js @@ -0,0 +1,6 @@ +/* ------------------------------------------------------------ + * Name : front.js + * Desc : Front Javascrip + * Created : 2016/9/11 Tri-aBility by Junheum,Choi + * Updated : + ------------------------------------------------------------ */ diff --git a/public/js/front.js b/public/js/front.js new file mode 100644 index 0000000..6bea8a4 --- /dev/null +++ b/public/js/front.js @@ -0,0 +1,93 @@ +/* ------------------------------------------------------------ + * Name : front.js + * Desc : Front Javascrip + * Created : 2016/9/11 Tri-aBility by Junheum,Choi + * Updated : + ------------------------------------------------------------ */ + +function trim(str){ + return this.replace(/(^\s*)|(\s*$)/gi, ""); +}// + +function bookmarksite(title,url) { + if (window.sidebar) // firefox + window.sidebar.addPanel(title, url, ""); + else if(window.opera && window.print){ // opera + var elem = document.createElement('a'); + elem.setAttribute('href',url); + elem.setAttribute('title',title); + elem.setAttribute('rel','sidebar'); + elem.click(); + } + else if(document.all) // ie + window.external.AddFavorite(url, title); +}// + +function captcha_refresh(refresh_url) { + $.ajax({ + type: 'POST', + url: refresh_url, + success: function(data, status, xhr){ + if(data) + $('#captcha_span').html(data); + }, + error: function(jqXHR, textStatus, errorThrown) { + console.log(jqXHR.responseText); + console.log(textStatus+'=>'+errorThrown); + } + });//ajax +}// + +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 $fileName + )); +} diff --git a/spark b/spark new file mode 100644 index 0000000..992d044 --- /dev/null +++ b/spark @@ -0,0 +1,84 @@ +#!/usr/bin/env php + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +/* + * -------------------------------------------------------------------- + * CODEIGNITER COMMAND-LINE TOOLS + * -------------------------------------------------------------------- + * The main entry point into the CLI system and allows you to run + * commands and perform maintenance on your application. + */ + +/* + *--------------------------------------------------------------- + * CHECK SERVER API + *--------------------------------------------------------------- + */ + +// Refuse to run when called from php-cgi +if (str_starts_with(PHP_SAPI, 'cgi')) { + exit("The cli tool is not supported when running php-cgi. It needs php-cli to function!\n\n"); +} + +/* + *--------------------------------------------------------------- + * CHECK PHP VERSION + *--------------------------------------------------------------- + */ + +$minPhpVersion = '8.1'; // If you update this, don't forget to update `public/index.php`. +if (version_compare(PHP_VERSION, $minPhpVersion, '<')) { + $message = sprintf( + 'Your PHP version must be %s or higher to run CodeIgniter. Current version: %s', + $minPhpVersion, + PHP_VERSION + ); + + exit($message); +} + +// We want errors to be shown when using it from the CLI. +error_reporting(E_ALL); +ini_set('display_errors', '1'); + +/* + *--------------------------------------------------------------- + * SET THE CURRENT DIRECTORY + *--------------------------------------------------------------- + */ + +// Path to the front controller +define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR); + +// Ensure the current directory is pointing to the front controller's directory +chdir(FCPATH); + +/* + *--------------------------------------------------------------- + * BOOTSTRAP THE APPLICATION + *--------------------------------------------------------------- + * This process sets up the path constants, loads and registers + * our autoloader, along with Composer's, loads our constants + * and fires up an environment-specific bootstrapping. + */ + +// LOAD OUR PATHS CONFIG FILE +// This is the line that might need to be changed, depending on your folder structure. +require FCPATH . '../app/Config/Paths.php'; +// ^^^ Change this line if you move your application folder + +$paths = new Config\Paths(); + +// LOAD THE FRAMEWORK BOOTSTRAP FILE +require $paths->systemDirectory . '/Boot.php'; + +exit(CodeIgniter\Boot::bootSpark($paths)); diff --git a/tests/.htaccess b/tests/.htaccess new file mode 100644 index 0000000..3462048 --- /dev/null +++ b/tests/.htaccess @@ -0,0 +1,6 @@ + + Require all denied + + + Deny from all + diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..fc40e44 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,118 @@ +# Running Application Tests + +This is the quick-start to CodeIgniter testing. Its intent is to describe what +it takes to set up your application and get it ready to run unit tests. +It is not intended to be a full description of the test features that you can +use to test your application. Those details can be found in the documentation. + +## Resources + +* [CodeIgniter 4 User Guide on Testing](https://codeigniter.com/user_guide/testing/index.html) +* [PHPUnit docs](https://phpunit.de/documentation.html) +* [Any tutorials on Unit testing in CI4?](https://forum.codeigniter.com/showthread.php?tid=81830) + +## Requirements + +It is recommended to use the latest version of PHPUnit. At the time of this +writing, we are running version 9.x. Support for this has been built into the +**composer.json** file that ships with CodeIgniter and can easily be installed +via [Composer](https://getcomposer.org/) if you don't already have it installed globally. + +```console +> composer install +``` + +If running under macOS or Linux, you can create a symbolic link to make running tests a touch nicer. + +```console +> ln -s ./vendor/bin/phpunit ./phpunit +``` + +You also need to install [XDebug](https://xdebug.org/docs/install) in order +for code coverage to be calculated successfully. After installing `XDebug`, you must add `xdebug.mode=coverage` in the **php.ini** file to enable code coverage. + +## Setting Up + +A number of the tests use a running database. +In order to set up the database edit the details for the `tests` group in +**app/Config/Database.php** or **.env**. +Make sure that you provide a database engine that is currently running on your machine. +More details on a test database setup are in the +[Testing Your Database](https://codeigniter.com/user_guide/testing/database.html) section of the documentation. + +## Running the tests + +The entire test suite can be run by simply typing one command-line command from the main directory. + +```console +> ./phpunit +``` + +If you are using Windows, use the following command. + +```console +> vendor\bin\phpunit +``` + +You can limit tests to those within a single test directory by specifying the +directory name after phpunit. + +```console +> ./phpunit app/Models +``` + +## Generating Code Coverage + +To generate coverage information, including HTML reports you can view in your browser, +you can use the following command: + +```console +> ./phpunit --colors --coverage-text=tests/coverage.txt --coverage-html=tests/coverage/ -d memory_limit=1024m +``` + +This runs all of the tests again collecting information about how many lines, +functions, and files are tested. It also reports the percentage of the code that is covered by tests. +It is collected in two formats: a simple text file that provides an overview as well +as a comprehensive collection of HTML files that show the status of every line of code in the project. + +The text file can be found at **tests/coverage.txt**. +The HTML files can be viewed by opening **tests/coverage/index.html** in your favorite browser. + +## PHPUnit XML Configuration + +The repository has a ``phpunit.xml.dist`` file in the project root that's used for +PHPUnit configuration. This is used to provide a default configuration if you +do not have your own configuration file in the project root. + +The normal practice would be to copy ``phpunit.xml.dist`` to ``phpunit.xml`` +(which is git ignored), and to tailor it as you see fit. +For instance, you might wish to exclude database tests, or automatically generate +HTML code coverage reports. + +## Test Cases + +Every test needs a *test case*, or class that your tests extend. CodeIgniter 4 +provides one class that you may use directly: +* `CodeIgniter\Test\CIUnitTestCase` + +Most of the time you will want to write your own test cases that extend `CIUnitTestCase` +to hold functions and services common to your test suites. + +## Creating Tests + +All tests go in the **tests/** directory. Each test file is a class that extends a +**Test Case** (see above) and contains methods for the individual tests. These method +names must start with the word "test" and should have descriptive names for precisely what +they are testing: +`testUserCanModifyFile()` `testOutputColorMatchesInput()` `testIsLoggedInFailsWithInvalidUser()` + +Writing tests is an art, and there are many resources available to help learn how. +Review the links above and always pay attention to your code coverage. + +### Database Tests + +Tests can include migrating, seeding, and testing against a mock or live database. +Be sure to modify the test case (or create your own) to point to your seed and migrations +and include any additional steps to be run before tests in the `setUp()` method. +See [Testing Your Database](https://codeigniter.com/user_guide/testing/database.html) +for details. diff --git a/tests/_support/Database/Migrations/2020-02-22-222222_example_migration.php b/tests/_support/Database/Migrations/2020-02-22-222222_example_migration.php new file mode 100644 index 0000000..a73356d --- /dev/null +++ b/tests/_support/Database/Migrations/2020-02-22-222222_example_migration.php @@ -0,0 +1,37 @@ +forge->addField('id'); + $this->forge->addField([ + 'name' => ['type' => 'varchar', 'constraint' => 31], + 'uid' => ['type' => 'varchar', 'constraint' => 31], + 'class' => ['type' => 'varchar', 'constraint' => 63], + 'icon' => ['type' => 'varchar', 'constraint' => 31], + 'summary' => ['type' => 'varchar', 'constraint' => 255], + 'created_at' => ['type' => 'datetime', 'null' => true], + 'updated_at' => ['type' => 'datetime', 'null' => true], + 'deleted_at' => ['type' => 'datetime', 'null' => true], + ]); + + $this->forge->addKey('name'); + $this->forge->addKey('uid'); + $this->forge->addKey(['deleted_at', 'id']); + $this->forge->addKey('created_at'); + + $this->forge->createTable('factories'); + } + + public function down(): void + { + $this->forge->dropTable('factories'); + } +} diff --git a/tests/_support/Database/Seeds/ExampleSeeder.php b/tests/_support/Database/Seeds/ExampleSeeder.php new file mode 100644 index 0000000..619fc27 --- /dev/null +++ b/tests/_support/Database/Seeds/ExampleSeeder.php @@ -0,0 +1,41 @@ + 'Test Factory', + 'uid' => 'test001', + 'class' => 'Factories\Tests\NewFactory', + 'icon' => 'fas fa-puzzle-piece', + 'summary' => 'Longer sample text for testing', + ], + [ + 'name' => 'Widget Factory', + 'uid' => 'widget', + 'class' => 'Factories\Tests\WidgetPlant', + 'icon' => 'fas fa-puzzle-piece', + 'summary' => 'Create widgets in your factory', + ], + [ + 'name' => 'Evil Factory', + 'uid' => 'evil-maker', + 'class' => 'Factories\Evil\MyFactory', + 'icon' => 'fas fa-book-dead', + 'summary' => 'Abandon all hope, ye who enter here', + ], + ]; + + $builder = $this->db->table('factories'); + + foreach ($factories as $factory) { + $builder->insert($factory); + } + } +} diff --git a/tests/_support/Libraries/ConfigReader.php b/tests/_support/Libraries/ConfigReader.php new file mode 100644 index 0000000..40d057a --- /dev/null +++ b/tests/_support/Libraries/ConfigReader.php @@ -0,0 +1,17 @@ +findAll(); + + // Make sure the count is as expected + $this->assertCount(3, $objects); + } + + public function testSoftDeleteLeavesRow(): void + { + $model = new ExampleModel(); + $this->setPrivateProperty($model, 'useSoftDeletes', true); + $this->setPrivateProperty($model, 'tempUseSoftDeletes', true); + + /** @var stdClass $object */ + $object = $model->first(); + $model->delete($object->id); + + // The model should no longer find it + $this->assertNull($model->find($object->id)); + + // ... but it should still be in the database + $result = $model->builder()->where('id', $object->id)->get()->getResult(); + + $this->assertCount(1, $result); + } +} diff --git a/tests/index.html b/tests/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/tests/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/tests/session/ExampleSessionTest.php b/tests/session/ExampleSessionTest.php new file mode 100644 index 0000000..6ada0c5 --- /dev/null +++ b/tests/session/ExampleSessionTest.php @@ -0,0 +1,18 @@ +set('logged_in', 123); + $this->assertSame(123, $session->get('logged_in')); + } +} diff --git a/tests/unit/HealthTest.php b/tests/unit/HealthTest.php new file mode 100644 index 0000000..25f229b --- /dev/null +++ b/tests/unit/HealthTest.php @@ -0,0 +1,50 @@ +assertTrue(defined('APPPATH')); + } + + public function testBaseUrlHasBeenSet(): void + { + $validation = Services::validation(); + + $env = false; + + // Check the baseURL in .env + if (is_file(HOMEPATH . '.env')) { + $env = preg_grep('/^app\.baseURL = ./', file(HOMEPATH . '.env')) !== false; + } + + if ($env) { + // BaseURL in .env is a valid URL? + // phpunit.xml.dist sets app.baseURL in $_SERVER + // So if you set app.baseURL in .env, it takes precedence + $config = new App(); + $this->assertTrue( + $validation->check($config->baseURL, 'valid_url'), + 'baseURL "' . $config->baseURL . '" in .env is not valid URL' + ); + } + + // Get the baseURL in app/Config/App.php + // You can't use Config\App, because phpunit.xml.dist sets app.baseURL + $reader = new ConfigReader(); + + // BaseURL in app/Config/App.php is a valid URL? + $this->assertTrue( + $validation->check($reader->baseURL, 'valid_url'), + 'baseURL "' . $reader->baseURL . '" in app/Config/App.php is not valid URL' + ); + } +} diff --git a/writable/.htaccess b/writable/.htaccess new file mode 100644 index 0000000..a94c5b0 --- /dev/null +++ b/writable/.htaccess @@ -0,0 +1,12 @@ + + Require all denied + + + Deny from all + + + RewriteEngine On + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteRule ^(.*)$ index.php/$1 [L] + \ No newline at end of file diff --git a/writable/cache/index.html b/writable/cache/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/writable/cache/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/writable/debugbar/index.html b/writable/debugbar/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/writable/debugbar/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/writable/excel/index.html b/writable/excel/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/writable/excel/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/writable/index.html b/writable/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/writable/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/writable/logs/index.html b/writable/logs/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/writable/logs/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/writable/uploads/index.html b/writable/uploads/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/writable/uploads/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + +