From c040d4d7132a9dcdb1c5ecf66179bf4044de7c45 Mon Sep 17 00:00:00 2001 From: zero Date: Tue, 6 Feb 2007 15:11:13 +0000 Subject: [PATCH] git-svn-id: http://xe-core.googlecode.com/svn/trunk@2 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- addons/spam_filter/spam_filter.addon.php | 16 + admin.php | 62 ++ classes/addon/AddOnHandler.class.php | 51 ++ classes/context/Context.class.php | 547 ++++++++++++++ classes/db/DB.class.php | 237 ++++++ classes/db/DBMysql.class.php | 375 ++++++++++ classes/display/DisplayHandler.class.php | 154 ++++ classes/file/FileHandler.class.php | 94 +++ classes/layout/LayoutHandler.class.php | 45 ++ classes/module/Module.class.php | 132 ++++ classes/module/ModuleHandler.class.php | 87 +++ classes/output/Output.class.php | 110 +++ classes/page/PageHandler.class.php | 42 ++ classes/template/TemplateHandler.class.php | 286 +++++++ classes/xml/XmlJsFilter.class.php | 158 ++++ classes/xml/XmlParser.class.php | 111 +++ classes/xml/XmlQueryParser.class.php | 340 +++++++++ common/css/default.css | 42 ++ common/js/common.js | 122 +++ common/js/x.js | 633 ++++++++++++++++ common/js/xml_handler.js | 136 ++++ common/js/xml_js_filter.js | 230 ++++++ common/lang/ko.lang.php | 135 ++++ common/tpl/common_footer.html | 3 + common/tpl/common_header.html | 19 + common/tpl/default_layout.html | 3 + config/config.inc.php | 37 + config/func.inc.php | 84 +++ editor/default/editor.css | 176 +++++ editor/default/editor.html | 59 ++ editor/default/editor.js | 706 ++++++++++++++++++ editor/default/editor_uploader.html | 44 ++ editor/default/flvplayer/flvplayer.swf | Bin 0 -> 3443 bytes editor/default/images/add_image.gif | Bin 0 -> 1019 bytes editor/default/images/add_indent.gif | Bin 0 -> 525 bytes editor/default/images/add_multi.gif | Bin 0 -> 1050 bytes editor/default/images/add_url.gif | Bin 0 -> 1082 bytes editor/default/images/align_center.gif | Bin 0 -> 510 bytes editor/default/images/align_left.gif | Bin 0 -> 307 bytes editor/default/images/align_right.gif | Bin 0 -> 308 bytes editor/default/images/blank.gif | Bin 0 -> 43 bytes editor/default/images/bold.gif | Bin 0 -> 323 bytes editor/default/images/color_block.gif | Bin 0 -> 49 bytes editor/default/images/emoticon.gif | Bin 0 -> 1018 bytes editor/default/images/emoticon/msn001.gif | Bin 0 -> 1056 bytes editor/default/images/emoticon/msn002.gif | Bin 0 -> 1040 bytes editor/default/images/emoticon/msn003.gif | Bin 0 -> 1041 bytes editor/default/images/emoticon/msn004.gif | Bin 0 -> 1027 bytes editor/default/images/emoticon/msn005.gif | Bin 0 -> 1540 bytes editor/default/images/emoticon/msn006.gif | Bin 0 -> 1022 bytes editor/default/images/emoticon/msn007.gif | Bin 0 -> 1054 bytes editor/default/images/emoticon/msn008.gif | Bin 0 -> 1015 bytes editor/default/images/emoticon/msn009.gif | Bin 0 -> 1031 bytes editor/default/images/emoticon/msn010.gif | Bin 0 -> 3531 bytes editor/default/images/emoticon/msn011.gif | Bin 0 -> 1047 bytes editor/default/images/emoticon/msn012.gif | Bin 0 -> 1015 bytes editor/default/images/emoticon/msn013.gif | Bin 0 -> 1078 bytes editor/default/images/emoticon/msn014.gif | Bin 0 -> 1022 bytes editor/default/images/emoticon/msn015.gif | Bin 0 -> 1026 bytes editor/default/images/emoticon/msn016.gif | Bin 0 -> 953 bytes editor/default/images/emoticon/msn017.gif | Bin 0 -> 1031 bytes editor/default/images/emoticon/msn018.gif | Bin 0 -> 944 bytes editor/default/images/emoticon/msn019.gif | Bin 0 -> 1013 bytes editor/default/images/emoticon/msn020.gif | Bin 0 -> 975 bytes editor/default/images/emoticon/msn021.gif | Bin 0 -> 1007 bytes editor/default/images/emoticon/msn022.gif | Bin 0 -> 1016 bytes editor/default/images/emoticon/msn023.gif | Bin 0 -> 977 bytes editor/default/images/emoticon/msn024.gif | Bin 0 -> 989 bytes editor/default/images/emoticon/msn025.gif | Bin 0 -> 980 bytes editor/default/images/emoticon/msn026.gif | Bin 0 -> 1055 bytes editor/default/images/emoticon/msn027.gif | Bin 0 -> 971 bytes editor/default/images/emoticon/msn028.gif | Bin 0 -> 1056 bytes editor/default/images/emoticon/msn029.gif | Bin 0 -> 968 bytes editor/default/images/emoticon/msn030.gif | Bin 0 -> 1040 bytes editor/default/images/emoticon/msn031.gif | Bin 0 -> 1063 bytes editor/default/images/emoticon/msn032.gif | Bin 0 -> 987 bytes editor/default/images/emoticon/msn033.gif | Bin 0 -> 992 bytes editor/default/images/emoticon/msn034.gif | Bin 0 -> 1057 bytes editor/default/images/emoticon/msn035.gif | Bin 0 -> 1056 bytes editor/default/images/emoticon/msn036.gif | Bin 0 -> 1004 bytes editor/default/images/emoticon/msn037.gif | Bin 0 -> 1052 bytes editor/default/images/emoticon/msn038.gif | Bin 0 -> 1032 bytes editor/default/images/emoticon/msn039.gif | Bin 0 -> 953 bytes editor/default/images/emoticon/msn040.gif | Bin 0 -> 1034 bytes editor/default/images/font_bg_color.gif | Bin 0 -> 595 bytes editor/default/images/font_color.gif | Bin 0 -> 549 bytes editor/default/images/html_add.gif | Bin 0 -> 1023 bytes editor/default/images/icon_align_article.gif | Bin 0 -> 379 bytes editor/default/images/icon_align_left.gif | Bin 0 -> 366 bytes editor/default/images/icon_align_middle.gif | Bin 0 -> 382 bytes editor/default/images/icon_align_right.gif | Bin 0 -> 368 bytes editor/default/images/icon_drag_down.gif | Bin 0 -> 53 bytes editor/default/images/italic.gif | Bin 0 -> 282 bytes editor/default/images/list_bullet.gif | Bin 0 -> 302 bytes editor/default/images/list_number.gif | Bin 0 -> 304 bytes editor/default/images/multimedia_icon.gif | Bin 0 -> 2531 bytes editor/default/images/php_highlight.gif | Bin 0 -> 603 bytes editor/default/images/quotation.gif | Bin 0 -> 547 bytes editor/default/images/remove_indent.gif | Bin 0 -> 525 bytes editor/default/images/strike.gif | Bin 0 -> 309 bytes editor/default/images/underline.gif | Bin 0 -> 306 bytes editor/default/lang/ko.lang.php | 60 ++ editor/default/popup/add_emoticon.php | 35 + editor/default/popup/add_html.php | 39 + editor/default/popup/add_image.php | 55 ++ editor/default/popup/add_multi.php | 51 ++ editor/default/popup/add_quotation.php | 216 ++++++ editor/default/popup/add_url.php | 75 ++ editor/default/popup/color_box.php | 39 + index.php | 23 + layouts/test/test.layout.php | 13 + modules/admin/admin.module.php | 148 ++++ modules/admin/lang/ko.lang.php | 9 + modules/admin/module.xml | 11 + modules/admin/skins/default/css/admin.css | 22 + modules/admin/skins/default/error.html | 1 + .../skins/default/filter/filter.login.xml | 10 + .../skins/default/filter/filter.logout.xml | 12 + modules/admin/skins/default/index.html | 1 + modules/admin/skins/default/js/admin.js | 27 + modules/admin/skins/default/layout.html | 21 + modules/admin/skins/default/login_form.html | 30 + modules/admin/skins/default/logout.html | 21 + modules/board/admin/category_list.html | 57 ++ modules/board/admin/category_update_form.html | 21 + modules/board/admin/delete_form.html | 34 + .../admin/filter/filter.delete_module.xml | 15 + modules/board/admin/filter/filter.insert.xml | 16 + .../admin/filter/filter.insert_category.xml | 16 + .../admin/filter/filter.insert_grant.xml | 15 + .../admin/filter/filter.update_category.xml | 13 + modules/board/admin/grant_list.html | 45 ++ modules/board/admin/header.html | 14 + modules/board/admin/info.html | 37 + modules/board/admin/insert_form.html | 99 +++ modules/board/admin/js/admin.js | 95 +++ modules/board/admin/list.html | 58 ++ modules/board/admin/skin_info.html | 119 +++ modules/board/board.admin.php | 403 ++++++++++ modules/board/board.module.php | 667 +++++++++++++++++ modules/board/lang/ko.lang.php | 56 ++ modules/board/module.xml | 11 + modules/board/queries/getBoardList.xml | 20 + modules/board/skins/default/comment.html | 53 ++ modules/board/skins/default/comment_form.html | 77 ++ .../skins/default/delete_comment_form.html | 23 + modules/board/skins/default/delete_form.html | 26 + .../skins/default/delete_trackback_form.html | 23 + .../default/filter/filter.delete_comment.xml | 19 + .../default/filter/filter.delete_document.xml | 17 + .../filter/filter.delete_trackback.xml | 19 + .../default/filter/filter.input_password.xml | 17 + .../skins/default/filter/filter.insert.xml | 18 + .../default/filter/filter.insert_comment.xml | 29 + .../skins/default/filter/filter.login.xml | 16 + .../skins/default/filter/filter.logout.xml | 14 + .../skins/default/filter/filter.search.xml | 15 + .../skins/default/filter/filter.vote.xml | 14 + modules/board/skins/default/header.html | 1 + .../skins/default/input_password_form.html | 26 + modules/board/skins/default/js/admin.js | 39 + modules/board/skins/default/js/board.js | 107 +++ modules/board/skins/default/list.html | 124 +++ modules/board/skins/default/login_form.html | 26 + modules/board/skins/default/logout.html | 22 + modules/board/skins/default/skin.xml | 67 ++ modules/board/skins/default/trackback.html | 50 ++ .../board/skins/default/view_document.html | 108 +++ modules/board/skins/default/write_form.html | 100 +++ modules/comment/comment.module.php | 267 +++++++ modules/comment/module.xml | 11 + modules/comment/queries/deleteComment.xml | 8 + modules/comment/queries/deleteComments.xml | 8 + .../comment/queries/deleteModuleComments.xml | 8 + .../comment/queries/getChildCommentCount.xml | 11 + modules/comment/queries/getComment.xml | 11 + modules/comment/queries/getCommentCount.xml | 11 + modules/comment/queries/getCommentList.xml | 14 + modules/comment/queries/getComments.xml | 11 + modules/comment/queries/insertComment.xml | 21 + modules/comment/queries/updateComment.xml | 20 + modules/comment/schemas/comments.xml | 18 + modules/document/document.module.php | 702 +++++++++++++++++ modules/document/lang/ko.lang.php | 8 + modules/document/module.xml | 11 + modules/document/queries/deleteCategory.xml | 8 + modules/document/queries/deleteDocument.xml | 8 + modules/document/queries/deleteFile.xml | 8 + modules/document/queries/deleteFiles.xml | 8 + .../document/queries/deleteModuleCategory.xml | 8 + .../document/queries/deleteModuleDocument.xml | 8 + .../document/queries/deleteModuleFiles.xml | 8 + modules/document/queries/getCategory.xml | 8 + .../queries/getCategoryDocumentCount.xml | 11 + modules/document/queries/getCategoryList.xml | 11 + modules/document/queries/getDocument.xml | 11 + modules/document/queries/getDocumentCount.xml | 19 + modules/document/queries/getDocumentList.xml | 26 + modules/document/queries/getDocumentPage.xml | 12 + modules/document/queries/getDocuments.xml | 11 + modules/document/queries/getFile.xml | 8 + modules/document/queries/getFiles.xml | 11 + modules/document/queries/getFilesCount.xml | 11 + modules/document/queries/insertCategory.xml | 14 + modules/document/queries/insertDocument.xml | 34 + modules/document/queries/insertFile.xml | 20 + modules/document/queries/updateCategory.xml | 13 + .../document/queries/updateCategoryCount.xml | 12 + .../document/queries/updateCommentCount.xml | 11 + modules/document/queries/updateDocument.xml | 31 + .../queries/updateDocumentCategory.xml | 11 + .../queries/updateFileDownloadCount.xml | 11 + .../document/queries/updateReadedCount.xml | 11 + .../document/queries/updateTrackbackCount.xml | 11 + modules/document/queries/updateVotedCount.xml | 11 + modules/document/schemas/category.xml | 9 + modules/document/schemas/documents.xml | 29 + modules/document/schemas/files.xml | 16 + modules/install/install.module.php | 264 +++++++ modules/install/lang/ko.lang.php | 65 ++ modules/install/module.xml | 11 + modules/install/schemas/sequence.xml | 3 + modules/install/skins/default/css/install.css | 0 .../install/skins/default/db_form.mysql.html | 92 +++ .../install/skins/default/disp_license.html | 48 ++ .../default/filter/filter.mysql_form.xml | 35 + modules/install/skins/default/js/install.js | 6 + modules/log/log.module.php | 60 ++ modules/log/module.xml | 11 + modules/log/schemas/log.xml | 8 + modules/member/admin/delete_form.html | 34 + modules/member/admin/denied_list.html | 67 ++ modules/member/admin/filter/filter.delete.xml | 16 + modules/member/admin/filter/filter.insert.xml | 16 + .../admin/filter/filter.insert_denied_id.xml | 14 + .../admin/filter/filter.insert_group.xml | 14 + .../admin/filter/filter.update_denied_id.xml | 14 + .../admin/filter/filter.update_group.xml | 14 + modules/member/admin/group_list.html | 64 ++ modules/member/admin/group_update_form.html | 30 + modules/member/admin/header.html | 9 + modules/member/admin/insert_member.html | 111 +++ modules/member/admin/js/admin.js | 81 ++ modules/member/admin/list.html | 58 ++ modules/member/admin/member_info.html | 49 ++ modules/member/lang/ko.lang.php | 45 ++ modules/member/member.admin.php | 267 +++++++ modules/member/member.module.php | 477 ++++++++++++ modules/member/module.xml | 11 + modules/member/queries/addMemberToGroup.xml | 10 + modules/member/queries/changeGroup.xml | 11 + modules/member/queries/chkDeniedID.xml | 11 + modules/member/queries/deleteDeniedID.xml | 8 + modules/member/queries/deleteGroup.xml | 8 + modules/member/queries/deleteMember.xml | 8 + .../queries/deleteMemberGroupMember.xml | 9 + modules/member/queries/getDefaultGroup.xml | 11 + modules/member/queries/getDeniedIDList.xml | 14 + modules/member/queries/getGroup.xml | 11 + modules/member/queries/getGroups.xml | 8 + modules/member/queries/getMemberGroups.xml | 14 + modules/member/queries/getMemberInfo.xml | 11 + .../queries/getMemberInfoByMemberSrl.xml | 11 + modules/member/queries/getMemberList.xml | 14 + modules/member/queries/getMemberSrl.xml | 13 + modules/member/queries/insertDeniedID.xml | 11 + modules/member/queries/insertGroup.xml | 12 + modules/member/queries/insertMember.xml | 26 + modules/member/queries/updateGroup.xml | 13 + .../queries/updateGroupDefaultClear.xml | 8 + modules/member/queries/updateLastLogin.xml | 12 + modules/member/queries/updateMember.xml | 24 + modules/member/schemas/member.xml | 23 + .../member/schemas/member_denied_user_id.xml | 6 + modules/member/schemas/member_group.xml | 7 + .../member/schemas/member_group_member.xml | 5 + modules/message/message.module.php | 66 ++ modules/message/module.xml | 11 + modules/message/skins/default/css/message.css | 0 .../message/skins/default/system_message.html | 11 + modules/module_manager/admin/index.html | 21 + modules/module_manager/lang/ko.lang.php | 12 + modules/module_manager/module.xml | 11 + .../module_manager/module_manager.admin.php | 119 +++ .../module_manager/module_manager.module.php | 455 +++++++++++ .../queries/clearDefaultModule.xml | 8 + .../module_manager/queries/deleteModule.xml | 8 + .../queries/getDefaultMidInfo.xml | 11 + modules/module_manager/queries/getMidInfo.xml | 12 + .../queries/getModuleInfoByDocument.xml | 24 + .../module_manager/queries/insertModule.xml | 22 + .../module_manager/queries/updateModule.xml | 23 + .../queries/updateModuleExtraVars.xml | 11 + .../queries/updateModuleGrant.xml | 11 + .../module_manager/schemas/module_addon.xml | 9 + .../module_manager/schemas/module_plugin.xml | 7 + modules/module_manager/schemas/modules.xml | 18 + modules/rss/module.xml | 11 + modules/rss/rss.module.php | 111 +++ modules/tag/module.xml | 11 + modules/tag/queries/deleteModuleTags.xml | 8 + modules/tag/queries/deleteTag.xml | 8 + modules/tag/queries/insertTag.xml | 12 + modules/tag/schemas/tags.xml | 7 + modules/tag/tag.module.php | 110 +++ modules/trackback/module.xml | 19 + .../queries/deleteModuleTrackbacks.xml | 8 + modules/trackback/queries/deleteTrackback.xml | 8 + .../trackback/queries/deleteTrackbacks.xml | 8 + modules/trackback/queries/getTrackback.xml | 8 + .../trackback/queries/getTrackbackCount.xml | 11 + .../trackback/queries/getTrackbackList.xml | 14 + modules/trackback/queries/insertTrackback.xml | 17 + modules/trackback/schemas/trackbacks.xml | 12 + modules/trackback/trackback.module.php | 251 +++++++ rss.php | 22 + trackback.php | 22 + 317 files changed, 14496 insertions(+) create mode 100644 addons/spam_filter/spam_filter.addon.php create mode 100644 admin.php create mode 100644 classes/addon/AddOnHandler.class.php create mode 100644 classes/context/Context.class.php create mode 100644 classes/db/DB.class.php create mode 100644 classes/db/DBMysql.class.php create mode 100644 classes/display/DisplayHandler.class.php create mode 100644 classes/file/FileHandler.class.php create mode 100644 classes/layout/LayoutHandler.class.php create mode 100644 classes/module/Module.class.php create mode 100644 classes/module/ModuleHandler.class.php create mode 100644 classes/output/Output.class.php create mode 100644 classes/page/PageHandler.class.php create mode 100644 classes/template/TemplateHandler.class.php create mode 100644 classes/xml/XmlJsFilter.class.php create mode 100644 classes/xml/XmlParser.class.php create mode 100644 classes/xml/XmlQueryParser.class.php create mode 100644 common/css/default.css create mode 100644 common/js/common.js create mode 100644 common/js/x.js create mode 100644 common/js/xml_handler.js create mode 100644 common/js/xml_js_filter.js create mode 100644 common/lang/ko.lang.php create mode 100644 common/tpl/common_footer.html create mode 100644 common/tpl/common_header.html create mode 100644 common/tpl/default_layout.html create mode 100644 config/config.inc.php create mode 100644 config/func.inc.php create mode 100644 editor/default/editor.css create mode 100644 editor/default/editor.html create mode 100755 editor/default/editor.js create mode 100644 editor/default/editor_uploader.html create mode 100644 editor/default/flvplayer/flvplayer.swf create mode 100644 editor/default/images/add_image.gif create mode 100644 editor/default/images/add_indent.gif create mode 100644 editor/default/images/add_multi.gif create mode 100644 editor/default/images/add_url.gif create mode 100644 editor/default/images/align_center.gif create mode 100644 editor/default/images/align_left.gif create mode 100644 editor/default/images/align_right.gif create mode 100644 editor/default/images/blank.gif create mode 100644 editor/default/images/bold.gif create mode 100644 editor/default/images/color_block.gif create mode 100644 editor/default/images/emoticon.gif create mode 100644 editor/default/images/emoticon/msn001.gif create mode 100644 editor/default/images/emoticon/msn002.gif create mode 100644 editor/default/images/emoticon/msn003.gif create mode 100644 editor/default/images/emoticon/msn004.gif create mode 100644 editor/default/images/emoticon/msn005.gif create mode 100644 editor/default/images/emoticon/msn006.gif create mode 100644 editor/default/images/emoticon/msn007.gif create mode 100644 editor/default/images/emoticon/msn008.gif create mode 100644 editor/default/images/emoticon/msn009.gif create mode 100644 editor/default/images/emoticon/msn010.gif create mode 100644 editor/default/images/emoticon/msn011.gif create mode 100644 editor/default/images/emoticon/msn012.gif create mode 100644 editor/default/images/emoticon/msn013.gif create mode 100644 editor/default/images/emoticon/msn014.gif create mode 100644 editor/default/images/emoticon/msn015.gif create mode 100644 editor/default/images/emoticon/msn016.gif create mode 100644 editor/default/images/emoticon/msn017.gif create mode 100644 editor/default/images/emoticon/msn018.gif create mode 100644 editor/default/images/emoticon/msn019.gif create mode 100644 editor/default/images/emoticon/msn020.gif create mode 100644 editor/default/images/emoticon/msn021.gif create mode 100644 editor/default/images/emoticon/msn022.gif create mode 100644 editor/default/images/emoticon/msn023.gif create mode 100644 editor/default/images/emoticon/msn024.gif create mode 100644 editor/default/images/emoticon/msn025.gif create mode 100644 editor/default/images/emoticon/msn026.gif create mode 100644 editor/default/images/emoticon/msn027.gif create mode 100644 editor/default/images/emoticon/msn028.gif create mode 100644 editor/default/images/emoticon/msn029.gif create mode 100644 editor/default/images/emoticon/msn030.gif create mode 100644 editor/default/images/emoticon/msn031.gif create mode 100644 editor/default/images/emoticon/msn032.gif create mode 100644 editor/default/images/emoticon/msn033.gif create mode 100644 editor/default/images/emoticon/msn034.gif create mode 100644 editor/default/images/emoticon/msn035.gif create mode 100644 editor/default/images/emoticon/msn036.gif create mode 100644 editor/default/images/emoticon/msn037.gif create mode 100644 editor/default/images/emoticon/msn038.gif create mode 100644 editor/default/images/emoticon/msn039.gif create mode 100644 editor/default/images/emoticon/msn040.gif create mode 100644 editor/default/images/font_bg_color.gif create mode 100644 editor/default/images/font_color.gif create mode 100644 editor/default/images/html_add.gif create mode 100644 editor/default/images/icon_align_article.gif create mode 100644 editor/default/images/icon_align_left.gif create mode 100644 editor/default/images/icon_align_middle.gif create mode 100644 editor/default/images/icon_align_right.gif create mode 100644 editor/default/images/icon_drag_down.gif create mode 100644 editor/default/images/italic.gif create mode 100644 editor/default/images/list_bullet.gif create mode 100644 editor/default/images/list_number.gif create mode 100644 editor/default/images/multimedia_icon.gif create mode 100644 editor/default/images/php_highlight.gif create mode 100644 editor/default/images/quotation.gif create mode 100644 editor/default/images/remove_indent.gif create mode 100644 editor/default/images/strike.gif create mode 100644 editor/default/images/underline.gif create mode 100644 editor/default/lang/ko.lang.php create mode 100644 editor/default/popup/add_emoticon.php create mode 100755 editor/default/popup/add_html.php create mode 100644 editor/default/popup/add_image.php create mode 100644 editor/default/popup/add_multi.php create mode 100644 editor/default/popup/add_quotation.php create mode 100644 editor/default/popup/add_url.php create mode 100644 editor/default/popup/color_box.php create mode 100644 index.php create mode 100644 layouts/test/test.layout.php create mode 100644 modules/admin/admin.module.php create mode 100644 modules/admin/lang/ko.lang.php create mode 100644 modules/admin/module.xml create mode 100644 modules/admin/skins/default/css/admin.css create mode 100644 modules/admin/skins/default/error.html create mode 100644 modules/admin/skins/default/filter/filter.login.xml create mode 100644 modules/admin/skins/default/filter/filter.logout.xml create mode 100644 modules/admin/skins/default/index.html create mode 100644 modules/admin/skins/default/js/admin.js create mode 100644 modules/admin/skins/default/layout.html create mode 100644 modules/admin/skins/default/login_form.html create mode 100644 modules/admin/skins/default/logout.html create mode 100644 modules/board/admin/category_list.html create mode 100644 modules/board/admin/category_update_form.html create mode 100644 modules/board/admin/delete_form.html create mode 100644 modules/board/admin/filter/filter.delete_module.xml create mode 100644 modules/board/admin/filter/filter.insert.xml create mode 100644 modules/board/admin/filter/filter.insert_category.xml create mode 100644 modules/board/admin/filter/filter.insert_grant.xml create mode 100644 modules/board/admin/filter/filter.update_category.xml create mode 100644 modules/board/admin/grant_list.html create mode 100644 modules/board/admin/header.html create mode 100644 modules/board/admin/info.html create mode 100644 modules/board/admin/insert_form.html create mode 100644 modules/board/admin/js/admin.js create mode 100644 modules/board/admin/list.html create mode 100644 modules/board/admin/skin_info.html create mode 100644 modules/board/board.admin.php create mode 100644 modules/board/board.module.php create mode 100644 modules/board/lang/ko.lang.php create mode 100644 modules/board/module.xml create mode 100644 modules/board/queries/getBoardList.xml create mode 100644 modules/board/skins/default/comment.html create mode 100644 modules/board/skins/default/comment_form.html create mode 100644 modules/board/skins/default/delete_comment_form.html create mode 100644 modules/board/skins/default/delete_form.html create mode 100644 modules/board/skins/default/delete_trackback_form.html create mode 100644 modules/board/skins/default/filter/filter.delete_comment.xml create mode 100644 modules/board/skins/default/filter/filter.delete_document.xml create mode 100644 modules/board/skins/default/filter/filter.delete_trackback.xml create mode 100644 modules/board/skins/default/filter/filter.input_password.xml create mode 100644 modules/board/skins/default/filter/filter.insert.xml create mode 100644 modules/board/skins/default/filter/filter.insert_comment.xml create mode 100644 modules/board/skins/default/filter/filter.login.xml create mode 100644 modules/board/skins/default/filter/filter.logout.xml create mode 100644 modules/board/skins/default/filter/filter.search.xml create mode 100644 modules/board/skins/default/filter/filter.vote.xml create mode 100644 modules/board/skins/default/header.html create mode 100644 modules/board/skins/default/input_password_form.html create mode 100644 modules/board/skins/default/js/admin.js create mode 100644 modules/board/skins/default/js/board.js create mode 100644 modules/board/skins/default/list.html create mode 100644 modules/board/skins/default/login_form.html create mode 100644 modules/board/skins/default/logout.html create mode 100644 modules/board/skins/default/skin.xml create mode 100644 modules/board/skins/default/trackback.html create mode 100644 modules/board/skins/default/view_document.html create mode 100644 modules/board/skins/default/write_form.html create mode 100644 modules/comment/comment.module.php create mode 100644 modules/comment/module.xml create mode 100644 modules/comment/queries/deleteComment.xml create mode 100644 modules/comment/queries/deleteComments.xml create mode 100644 modules/comment/queries/deleteModuleComments.xml create mode 100644 modules/comment/queries/getChildCommentCount.xml create mode 100644 modules/comment/queries/getComment.xml create mode 100644 modules/comment/queries/getCommentCount.xml create mode 100644 modules/comment/queries/getCommentList.xml create mode 100644 modules/comment/queries/getComments.xml create mode 100644 modules/comment/queries/insertComment.xml create mode 100644 modules/comment/queries/updateComment.xml create mode 100644 modules/comment/schemas/comments.xml create mode 100644 modules/document/document.module.php create mode 100644 modules/document/lang/ko.lang.php create mode 100644 modules/document/module.xml create mode 100644 modules/document/queries/deleteCategory.xml create mode 100644 modules/document/queries/deleteDocument.xml create mode 100644 modules/document/queries/deleteFile.xml create mode 100644 modules/document/queries/deleteFiles.xml create mode 100644 modules/document/queries/deleteModuleCategory.xml create mode 100644 modules/document/queries/deleteModuleDocument.xml create mode 100644 modules/document/queries/deleteModuleFiles.xml create mode 100644 modules/document/queries/getCategory.xml create mode 100644 modules/document/queries/getCategoryDocumentCount.xml create mode 100644 modules/document/queries/getCategoryList.xml create mode 100644 modules/document/queries/getDocument.xml create mode 100644 modules/document/queries/getDocumentCount.xml create mode 100644 modules/document/queries/getDocumentList.xml create mode 100644 modules/document/queries/getDocumentPage.xml create mode 100644 modules/document/queries/getDocuments.xml create mode 100644 modules/document/queries/getFile.xml create mode 100644 modules/document/queries/getFiles.xml create mode 100644 modules/document/queries/getFilesCount.xml create mode 100644 modules/document/queries/insertCategory.xml create mode 100644 modules/document/queries/insertDocument.xml create mode 100644 modules/document/queries/insertFile.xml create mode 100644 modules/document/queries/updateCategory.xml create mode 100644 modules/document/queries/updateCategoryCount.xml create mode 100644 modules/document/queries/updateCommentCount.xml create mode 100644 modules/document/queries/updateDocument.xml create mode 100644 modules/document/queries/updateDocumentCategory.xml create mode 100644 modules/document/queries/updateFileDownloadCount.xml create mode 100644 modules/document/queries/updateReadedCount.xml create mode 100644 modules/document/queries/updateTrackbackCount.xml create mode 100644 modules/document/queries/updateVotedCount.xml create mode 100644 modules/document/schemas/category.xml create mode 100644 modules/document/schemas/documents.xml create mode 100644 modules/document/schemas/files.xml create mode 100644 modules/install/install.module.php create mode 100644 modules/install/lang/ko.lang.php create mode 100644 modules/install/module.xml create mode 100644 modules/install/schemas/sequence.xml create mode 100644 modules/install/skins/default/css/install.css create mode 100644 modules/install/skins/default/db_form.mysql.html create mode 100644 modules/install/skins/default/disp_license.html create mode 100644 modules/install/skins/default/filter/filter.mysql_form.xml create mode 100644 modules/install/skins/default/js/install.js create mode 100644 modules/log/log.module.php create mode 100644 modules/log/module.xml create mode 100644 modules/log/schemas/log.xml create mode 100644 modules/member/admin/delete_form.html create mode 100644 modules/member/admin/denied_list.html create mode 100644 modules/member/admin/filter/filter.delete.xml create mode 100644 modules/member/admin/filter/filter.insert.xml create mode 100644 modules/member/admin/filter/filter.insert_denied_id.xml create mode 100644 modules/member/admin/filter/filter.insert_group.xml create mode 100644 modules/member/admin/filter/filter.update_denied_id.xml create mode 100644 modules/member/admin/filter/filter.update_group.xml create mode 100644 modules/member/admin/group_list.html create mode 100644 modules/member/admin/group_update_form.html create mode 100644 modules/member/admin/header.html create mode 100644 modules/member/admin/insert_member.html create mode 100644 modules/member/admin/js/admin.js create mode 100644 modules/member/admin/list.html create mode 100644 modules/member/admin/member_info.html create mode 100644 modules/member/lang/ko.lang.php create mode 100644 modules/member/member.admin.php create mode 100644 modules/member/member.module.php create mode 100644 modules/member/module.xml create mode 100644 modules/member/queries/addMemberToGroup.xml create mode 100644 modules/member/queries/changeGroup.xml create mode 100644 modules/member/queries/chkDeniedID.xml create mode 100644 modules/member/queries/deleteDeniedID.xml create mode 100644 modules/member/queries/deleteGroup.xml create mode 100644 modules/member/queries/deleteMember.xml create mode 100644 modules/member/queries/deleteMemberGroupMember.xml create mode 100644 modules/member/queries/getDefaultGroup.xml create mode 100644 modules/member/queries/getDeniedIDList.xml create mode 100644 modules/member/queries/getGroup.xml create mode 100644 modules/member/queries/getGroups.xml create mode 100644 modules/member/queries/getMemberGroups.xml create mode 100644 modules/member/queries/getMemberInfo.xml create mode 100644 modules/member/queries/getMemberInfoByMemberSrl.xml create mode 100644 modules/member/queries/getMemberList.xml create mode 100644 modules/member/queries/getMemberSrl.xml create mode 100644 modules/member/queries/insertDeniedID.xml create mode 100644 modules/member/queries/insertGroup.xml create mode 100644 modules/member/queries/insertMember.xml create mode 100644 modules/member/queries/updateGroup.xml create mode 100644 modules/member/queries/updateGroupDefaultClear.xml create mode 100644 modules/member/queries/updateLastLogin.xml create mode 100644 modules/member/queries/updateMember.xml create mode 100644 modules/member/schemas/member.xml create mode 100644 modules/member/schemas/member_denied_user_id.xml create mode 100644 modules/member/schemas/member_group.xml create mode 100644 modules/member/schemas/member_group_member.xml create mode 100644 modules/message/message.module.php create mode 100644 modules/message/module.xml create mode 100644 modules/message/skins/default/css/message.css create mode 100644 modules/message/skins/default/system_message.html create mode 100644 modules/module_manager/admin/index.html create mode 100644 modules/module_manager/lang/ko.lang.php create mode 100644 modules/module_manager/module.xml create mode 100644 modules/module_manager/module_manager.admin.php create mode 100644 modules/module_manager/module_manager.module.php create mode 100644 modules/module_manager/queries/clearDefaultModule.xml create mode 100644 modules/module_manager/queries/deleteModule.xml create mode 100644 modules/module_manager/queries/getDefaultMidInfo.xml create mode 100644 modules/module_manager/queries/getMidInfo.xml create mode 100644 modules/module_manager/queries/getModuleInfoByDocument.xml create mode 100644 modules/module_manager/queries/insertModule.xml create mode 100644 modules/module_manager/queries/updateModule.xml create mode 100644 modules/module_manager/queries/updateModuleExtraVars.xml create mode 100644 modules/module_manager/queries/updateModuleGrant.xml create mode 100644 modules/module_manager/schemas/module_addon.xml create mode 100644 modules/module_manager/schemas/module_plugin.xml create mode 100644 modules/module_manager/schemas/modules.xml create mode 100644 modules/rss/module.xml create mode 100644 modules/rss/rss.module.php create mode 100644 modules/tag/module.xml create mode 100644 modules/tag/queries/deleteModuleTags.xml create mode 100644 modules/tag/queries/deleteTag.xml create mode 100644 modules/tag/queries/insertTag.xml create mode 100644 modules/tag/schemas/tags.xml create mode 100644 modules/tag/tag.module.php create mode 100644 modules/trackback/module.xml create mode 100644 modules/trackback/queries/deleteModuleTrackbacks.xml create mode 100644 modules/trackback/queries/deleteTrackback.xml create mode 100644 modules/trackback/queries/deleteTrackbacks.xml create mode 100644 modules/trackback/queries/getTrackback.xml create mode 100644 modules/trackback/queries/getTrackbackCount.xml create mode 100644 modules/trackback/queries/getTrackbackList.xml create mode 100644 modules/trackback/queries/insertTrackback.xml create mode 100644 modules/trackback/schemas/trackbacks.xml create mode 100644 modules/trackback/trackback.module.php create mode 100644 rss.php create mode 100644 trackback.php diff --git a/addons/spam_filter/spam_filter.addon.php b/addons/spam_filter/spam_filter.addon.php new file mode 100644 index 000000000..6582e53ac --- /dev/null +++ b/addons/spam_filter/spam_filter.addon.php @@ -0,0 +1,16 @@ + + * @desc : 스팸필터링 애드온 + **/ + + class spam_filter { + + function proc(&$oModule, $oModuleInfo) { + $oModule->setError(-1); + $oModule->setMessage('error'); + } + + } +?> diff --git a/admin.php b/admin.php new file mode 100644 index 000000000..23dfe47ee --- /dev/null +++ b/admin.php @@ -0,0 +1,62 @@ + + * @desc : 관리자 페이지 + * admin은 ModuleHandler를 이용하지 않는다. + **/ + + // 필요한 설정 파일들을 include + require_once("./config/config.inc.php"); + + // Request Method와 설정값들을 세팅 + $oContext = &Context::getInstance(); + $oContext->init(); + + // 설치가 안되어 있다면 index.php로 이동 + if(!Context::isInstalled()) { + header("location:./index.php"); + exit(); + } + + // sid 검사 + $sid = Context::get('sid'); + if($sid) { + $oModule = module_manager::getAdminModuleObject($sid); + if(!$oModule) { + $sid = null; + Context::set('sid',$sid); + unset($oModule); + } + } + + // 관리자(admin) 모듈 객체 생성 + $oAdmin = getModule('admin'); + $oAdmin->moduleInit(null); + + // act검사 + $act = Context::get('act'); + if(!$sid&&!$oAdmin->isExistsAct($act)) $act = 'dispAdminIndex'; + + // 관리자 모듈의 실행 결과가 있으면 해당 실행결과를 출력 + if($oAdmin->proc($act)) { + + $oModule = &$oAdmin; + + // 관리자 모듈의 실행 결과가 없으면 호출된 다른 모듈의 관리자를 확인 + } else { + $oModule = module_manager::getAdminModuleObject($sid); + if($oModule) { + $oModule->moduleInit(null); + $oModule->proc(); + + // 관리자용 레이아웃으로 변경 + $oModule->setLayoutPath($oAdmin->getLayoutPath()); + $oModule->setLayoutTpl($oAdmin->getLayoutTpl()); + } + } + + // DisplayHandler로 컨텐츠 출력 + $oDisplayHandler = new DisplayHandler(); + $oDisplayHandler->printContent($oModule); +?> diff --git a/classes/addon/AddOnHandler.class.php b/classes/addon/AddOnHandler.class.php new file mode 100644 index 000000000..0afd95235 --- /dev/null +++ b/classes/addon/AddOnHandler.class.php @@ -0,0 +1,51 @@ + + * @desc : addon 실행 + **/ + + class AddOnHandler { + + var $addon_name; + + function callAddOns(&$oModule, $oModuleInfo, $status) { + if(!$oModuleInfo->isAddOnExists($status, ContextHandler::get('act'))) return; + + $addon_list = $oModuleInfo->getAddOnList($status, ContextHandler::get('act')); + $addon_cnt = count($addon_list); + if(!$addon_cnt) return; + for($i=0; $i<$addon_cnt; $i++) { + $addon_name = $addon_list[$i]; + + $oAddOn = new AddOnHandler($addon_name); + $oAddOn->proc($oModule, $oModuleInfo); + } + + } + + function AddOnHandler($addon_name) { + $this->addon_name = $addon_name; + } + + function proc(&$oModule, $oModuleInfo) { + // 해당 모듈을 읽어서 객체를 만듬 + $addon_file = sprintf('./addons/%s/%s.addon.php', $this->addon_name, $this->addon_name); + + // 모듈 파일이 없으면 에러 + if(!file_exists($addon_file)) return; + + // 모듈 파일을 include + require_once($addon_file); + + // 선택된 모듈의 instance는 eval string으로 처리 + $eval_str = sprintf('$oAddOn = new %s();', $this->addon_name); + eval($eval_str); + + // 애드온 실행 + $oAddOn->proc($oModule, $oModuleInfo); + } + + } + +?> diff --git a/classes/context/Context.class.php b/classes/context/Context.class.php new file mode 100644 index 000000000..f650f426d --- /dev/null +++ b/classes/context/Context.class.php @@ -0,0 +1,547 @@ + + * @desc : Request Argument/Module Config/ Layout-AddOn-Plugin과 + * 결과물까지 모두 처리 + **/ + + class Context { + + // GET/POST/XMLRPC 중 어떤 방식으로 요청이 왔는지에 대한 값이 세팅 + var $request_method = 'GET'; + + // request parameter 를 정리하여 담을 변수 + var $context = NULL; + + // DB 정보 + var $db_info = NULL; + + // js file + var $js_files = array(); + + // css file + var $css_files = array(); + + // html header 정보 + var $html_header = NULL; + + // 언어정보 + var $lang_type = 'ko'; + var $lang = NULL; + var $loaded_lang_files = array(); + + // 현 사이트의 title + var $site_title = ''; + + // 현재 요청 들어온 $_GET을 별도로 정리/보관 ( set method에 의해 값 변경 적용) + var $get_vars = NULL; + + // 업로드 유무 체크 + var $is_uploaded = false; + + /** + * Context 객체 생성 및 초기화 + **/ + // public object getInstance()/*{{{*/ + // Context는 어디서든 객체 선언없이 사용하기 위해서 static 하게 사용 + function &getInstance() { + if(!$GLOBALS['__ContextInstance__']) $GLOBALS['__ContextInstance__'] = new Context(); + return $GLOBALS['__ContextInstance__']; + }/*}}}*/ + + // public void init()/*{{{*/ + // DB정보, Request Argument등을 세팅 + function init() { + // context 변수를 $GLOBALS의 변수로 지정 + $this->context = &$GLOBALS['__Context__']; + $this->context->lang = &$GLOBALS['lang']; + + // 인증관련 데이터를 Context에 설정 + $oMember = getModule('member'); + if($oMember->isLogged()) { + $this->_set('is_logged', true); + $this->_set('logged_info', $_SESSION['logged_info']); + } + + // 기본적인 DB정보 세팅 + $this->_loadDBInfo(); + + // 기본 언어파일 로드 + $this->lang = &$GLOBALS['lang']; + $this->_loadLang("./common/lang/"); + + // Request Method 설정 + $this->_setRequestMethod(); + + // Request Argument 설정 + $this->_setXmlRpcArgument(); + $this->_setRequestArgument(); + $this->_setUploadedArgument(); + }/*}}}*/ + + /** + * DB 정보를 설정하고 DB Type과 DB 정보를 return + **/ + // private void _loadDBInfo()/*{{{*/ + // 설정파일을 통해 DB정보를 로드 + function _loadDBInfo() { + if(!$this->isInstalled()) return; + + // db 정보 설정 + $db_config_file = $this->getConfigFile(); + if(file_exists($db_config_file)) { + include $db_config_file; + } + $this->_setDBInfo($db_info); + }/*}}}*/ + + // public string getDBType()/*{{{*/ + // DB의 db_type을 return + function getDBType() { + $oContext = &Context::getInstance(); + return $oContext->_getDBType(); + }/*}}}*/ + + // private string _getDBType()/*{{{*/ + function _getDBType() { + return $this->db_info->db_type; + }/*}}}*/ + + // public object setDBInfo($db_info) /*{{{*/ + // DB 정보가 담긴 object를 return + function setDBInfo($db_info) { + $oContext = &Context::getInstance(); + $oContext->_setDBInfo($db_info); + }/*}}}*/ + + // private string _setDBInfo($db_info)/*{{{*/ + function _setDBInfo($db_info) { + $this->db_info = $db_info; + }/*}}}*/ + + // public object getDBInfo() /*{{{*/ + // DB 정보가 담긴 object를 return + function getDBInfo() { + $oContext = &Context::getInstance(); + return $oContext->_getDBInfo(); + }/*}}}*/ + + // private string _getDBInfo()/*{{{*/ + function _getDBInfo() { + return $this->db_info; + }/*}}}*/ + + /** + * 사이트 title + **/ + // public void setBrowserTitle($site_title)/*{{{*/ + function setBrowserTitle($site_title) { + $oContext = &Context::getInstance(); + $oContext->_setBrowserTitle($site_title); + }/*}}}*/ + + // private void _setBrowserTitle($site_title)/*{{{*/ + function _setBrowserTitle($site_title) { + $this->site_title = $site_title; + }/*}}}*/ + + // public string getBrowserTitle()/*{{{*/ + function getBrowserTitle() { + $oContext = &Context::getInstance(); + return $oContext->_getBrowserTitle(); + }/*}}}*/ + + // private string _getBrowserTitle() /*{{{*/ + function _getBrowserTitle() { + return $this->site_title; + }/*}}}*/ + + /** + * 언어관련 + **/ + // public void loadLang($path)/*{{{*/ + // 지정된 언어파일 로드 + function loadLang($path) { + $oContext = &Context::getInstance(); + $oContext->_loadLang($path); + }/*}}}*/ + + // private void _loadLang($path)/*{{{*/ + // 지정된 언어파일 로드 + function _loadLang($path) { + global $lang; + if(substr($path,-1)!='/') $path .= '/'; + $filename = sprintf('%s%s.lang.php', $path, $this->lang_type); + if(!file_exists($filename)) $filename = sprintf('%slang/%s.lang.php', $path, $this->lang_type); + if(!file_exists($filename)) return; + if(in_array($filename, $this->loaded_lang_files)) return; + $this->loaded_lang_files[] = $filename; + include ($filename); + }/*}}}*/ + + // public void setLangType($lang_type = 'ko')/*{{{*/ + function setLangType($lang_type = 'ko') { + $oContext = &Context::getInstance(); + $oContext->_setLangType($lang); + }/*}}}*/ + + // private void _setLangType($lang_type = 'ko')/*{{{*/ + function _setLangType($lang_type = 'ko') { + $this->lang_type = $lang_type; + }/*}}}*/ + + // public string getLangType()/*{{{*/ + function getLangType() { + $oContext = &Context::getInstance(); + return $oContext->_getLangType(); + }/*}}}*/ + + // private string _getLangType()/*{{{*/ + function _getLangType() { + return $this->lang_type; + }/*}}}*/ + + // public string getLang($code)/*{{{*/ + function getLang($code) { + if($GLOBALS['lang']->{$code}) return $GLOBALS['lang']->{$code}; + return $code; + }/*}}}*/ + + // public string setLang($code, $val)/*{{{*/ + function setLang($code, $val) { + $GLOBALS['lang']->{$code} = $val; + }/*}}}*/ + + // public obj convertEncoding($obj) + // obj내의 문자들을 utf8로 변경 + function convertEncoding($source_obj) {/*{{{*/ + $charset_list = array( + 'UTF-8', 'EUC-KR', 'CP949', 'ISO-8859-1', 'EUC-JP', 'SHIFT_JIS', 'CP932', + 'EUC-CN', 'HZ', 'GBK', 'GB18030', 'EUC-TW', 'BIG5', 'CP950', 'BIG5-HKSCS', + 'ISO-2022-CN', 'ISO-2022-CN-EXT', 'ISO-2022-JP', 'ISO-2022-JP-2', 'ISO-2022-JP-1', + 'ISO-8859-6', 'ISO-8859-8', 'JOHAB', 'ISO-2022-KR', 'CP1255', 'CP1256', 'CP862', + 'ASCII', 'ISO-8859-1', 'ISO-8850-2', 'ISO-8850-3', 'ISO-8850-4', 'ISO-8850-5', + 'ISO-8850-7', 'ISO-8850-9', 'ISO-8850-10', 'ISO-8850-13', 'ISO-8850-14', + 'ISO-8850-15', 'ISO-8850-16', 'CP1250', 'CP1251', 'CP1252', 'CP1253', 'CP1254', + 'CP1257', 'CP850', 'CP866', + ); + + $obj = clone($source_obj); + + for($i=0;$i$val) { + if(!$val) continue; + if($val && !iconv($charset,'UTF-8',$val)) $flag = false; + } + + if($flag == true) { + foreach($obj as $key => $val) $obj->{$key} = iconv($charset,'UTF-8',$val); + return $obj; + } + } + }/*}}}*/ + + /** + * Request Method 및 Argument의 설정 및 return + **/ + // private void _setRequestMethod()/*{{{*/ + // request method가 어떤것인지 판단하여 저장 (GET/POST/XMLRPC) + function _setRequestMethod() { + if($GLOBALS['HTTP_RAW_POST_DATA']) $this->request_method = "XMLRPC"; + else $this->request_method = $_SERVER['REQUEST_METHOD']; + }/*}}}*/ + + // private void _setRequestArgument();/*{{{*/ + // GET/POST방식일 경우 처리 + function _setRequestArgument() { + if($this->_getRequestMethod() == 'XMLRPC') return; + if(!count($_REQUEST)) return; + foreach($_REQUEST as $key => $val) { + if(is_array($val)) { + for($i=0;$i_getRequestMethod()=='GET'&&$_GET[$key]) $set_to_vars = true; + elseif($this->_getRequestMethod()=='POST'&&$_POST[$key]) $set_to_vars = true; + else $set_to_vars = false; + $this->_set($key, $val, $set_to_vars); + } + }/*}}}*/ + + // private void _setXmlRpcArgument()/*{{{*/ + // XML RPC일때역시 + function _setXmlRpcArgument() { + if($this->_getRequestMethod() != 'XMLRPC') return; + $oXml = new XmlParser(); + $xml_obj = $oXml->parse(); + + $method_name = $xml_obj->methodcall->methodname->body; + $params = $xml_obj->methodcall->params; + unset($params->node_name); + + unset($params->attrs); + if(!count($params)) return; + foreach($params as $key => $obj) { + $val = trim($obj->body); + $this->_set($key, $val, true); + } + }/*}}}*/ + + // public boolean isUploaded() /*{{{*/ + // 업로드 되었을 경우 return true + function isUploaded() { + $oContext = &Context::getInstance(); + return $oContext->_isUploaded(); + }/*}}}*/ + + // private boolean isUploaded() /*{{{*/ + // 업로드 되었을 경우 return true + function _isUploaded() { + return $this->is_uploaded; + }/*}}}*/ + + // private void _setUploadedArgument()/*{{{*/ + // 업로드된 파일이 있을 경우도 역시 context에 통합 처리 (단 정상적인 업로드인지 체크) + function _setUploadedArgument() { + if($this->_getRequestMethod() != 'POST') return; + if(!eregi("^multipart\/form-data", $_SERVER['CONTENT_TYPE'])) return; + if(!$_FILES) return; + + foreach($_FILES as $key => $val) { + $tmp_name = $val['tmp_name']; + if(!$tmp_name || !is_uploaded_file($tmp_name)) continue; + $this->_set($key, $val, true); + $this->is_uploaded = true; + } + }/*}}}*/ + + // public string getRequestMethod()/*{{{*/ + // Request Method값을 return (GET/POST/XMLRPC); + function getRequestMethod() { + $oContext = &Context::getInstance(); + return $oContext->_getRequestMethod(); + }/*}}}*/ + + // private string _getRequestMethod()/*{{{*/ + function _getRequestMethod() { + return $this->request_method; + }/*}}}*/ + + // public string getUrl($num_args, $args_list)/*{{{*/ + // 요청받은 url에 args_list를 적용하여 return + function getUrl($num_args, $args_list) { + $oContext = &Context::getInstance(); + return $oContext->_getUrl($num_args, $args_list); + }/*}}}*/ + + // private string _getUrl($num_args, $args_list)/*{{{*/ + // 요청받은 url에 args_list를 적용하여 return + function _getUrl($num_args, $args_list) { + if(!is_object($this->get_vars)) $get_vars = null; + else $get_vars = clone($this->get_vars); + for($i=0;$i<$num_args;$i=$i+2) { + $key = $args_list[$i]; + $val = $args_list[$i+1]; + $get_vars->{$key} = trim($val); + } + + $var_count = count(get_object_vars($get_vars)); + if(!$var_count) return; + foreach($get_vars as $key => $val) { + if(!$val) continue; + $url_list[] = sprintf("%s=%s",$key, $val); + } + + preg_match("/([a-zA-Z\_]+)\.php/i", $_SERVER['PHP_SELF'], $match); + $filename = $match[0]; + if($filename == 'index.php') $filename = ''; + + return './'.$filename.'?'.htmlspecialchars(implode('&', $url_list)); + }/*}}}*/ + + // public string getRequestUri() /*{{{*/ + function getRequestUri() { + $hostname = $_SERVER['SERVER_NAME']; + $port = $_SERVER['SERVER_PORT']; + if($port!=80) $hostname .= ":{$port}"; + $path = $_SERVER['REDIRECT_URL']; + $path = $_SERVER['REDIRECT_URL']?$_SERVER['REDIRECT_URL']:preg_replace('/([a-zA-Z0-9\_]+).php/i','',$_SERVER['PHP_SELF']); + return sprintf("http://%s%s",$hostname,$path); + }/*}}}*/ + + /** + * Request Argument외의 데이터 set/get + **/ + // public void set($key, $val, $set_to_get_vars = false)/*{{{*/ + // key/val 로 데이터 세팅 + function set($key, $val, $set_to_get_vars = false) { + $oContext = &Context::getInstance(); + $oContext->_set($key, $val, $set_to_get_vars); + }/*}}}*/ + + // private void _set($key, $val, $set_to_get_vars = false)/*{{{*/ + function _set($key, $val, $set_to_get_vars = false) { + $this->context->{$key} = $val; + if($set_to_get_vars || $this->get_vars->{$key}) $this->get_vars->{$key} = $val; + }/*}}}*/ + + // public object get($key)/*{{{*/ + // key값에 해당하는 값을 return + function get($key) { + $oContext = &Context::getInstance(); + return $oContext->_get($key); + }/*}}}*/ + + // private object _get($key)/*{{{*/ + function _get($key) { + return $this->context->{$key}; + }/*}}}*/ + + // public object gets(void)/*{{{*/ + // 받고자 하는 변수만 object에 입력하여 받음 + function gets() { + $num_args = func_num_args(); + if($num_args<1) return; + $args_list = func_get_args(); + + $oContext = &Context::getInstance(); + return $oContext->_gets($num_args, $args_list); + }/*}}}*/ + + // private object _gets($args_list)/*{{{*/ + function _gets($num_args, $args_list) { + for($i=0;$i<$num_args;$i++) { + $args = $args_list[$i]; + $output->{$args} = $this->_get($args); + } + return $output; + }/*}}}*/ + + // public object getAll()/*{{{*/ + // 모든 데이터를 return + function getAll() { + $oContext = &Context::getInstance(); + return $oContext->_getAll(); + }/*}}}*/ + + // private object _getAll()/*{{{*/ + function _getAll() { + return $this->context; + }/*}}}*/ + + // public object getRequestVars()/*{{{*/ + // GET/POST/XMLRPC에서 넘어온 변수값을 return + function getRequestVars() { + $oContext = &Context::getInstance(); + return $oContext->_getRequestVars(); + }/*}}}*/ + + // private object _getRequestVars()/*{{{*/ + function _getRequestVars() { + return clone($this->get_vars); + }/*}}}*/ + + /** + * CSS/JS/HeaderText 등 html을 출력할때 사용할 값들 + **/ + // public void addJsFile($file)/*{{{*/ + // js file 추가 + function addJsFile($file) { + $oContext = &Context::getInstance(); + return $oContext->_addJsFile($file); + }/*}}}*/ + + // private void _addJsFile($file)/*{{{*/ + function _addJsFile($file) { + if(in_array($file, $this->js_files)) return; + $this->js_files[] = $file; + }/*}}}*/ + + // public array getJsFile()/*{{{*/ + function getJsFile() { + $oContext = &Context::getInstance(); + return $oContext->_getJsFile(); + }/*}}}*/ + + // private array _getJsFile()/*{{{*/ + function _getJsFile() { + return $this->js_files; + }/*}}}*/ + + // public void addCSSFile($file)/*{{{*/ + // CSS file 추가 + function addCSSFile($file) { + $oContext = &Context::getInstance(); + return $oContext->_addCSSFile($file); + }/*}}}*/ + + // private void _addCSSFile($file)/*{{{*/ + function _addCSSFile($file) { + if(in_array($file, $this->css_files)) return; + $this->css_files[] = $file; + }/*}}}*/ + + // public array getCSSFile()/*{{{*/ + // CSS file 추가 + function getCSSFile() { + $oContext = &Context::getInstance(); + return $oContext->_getCSSFile(); + }/*}}}*/ + + // private array _getCSSFile()/*{{{*/ + function _getCSSFile() { + return $this->css_files; + }/*}}}*/ + + // public void addHtmlHeader($file)/*{{{*/ + // HtmlHeader 추가 + function addHtmlHeader($file) { + $oContext = &Context::getInstance(); + return $oContext->_addHtmlHeader($file); + }/*}}}*/ + + // private void _addHtmlHeader($file)/*{{{*/ + function _addHtmlHeader($file) { + $this->HtmlHeader .= ($this->HtmlHeader?"\n":"").$file; + }/*}}}*/ + + // public string getHtmlHeader()/*{{{*/ + // HtmlHeader 추가 + function getHtmlHeader() { + $oContext = &Context::getInstance(); + return $oContext->_getHtmlHeader(); + }/*}}}*/ + + // private string _getHtmlHeader()/*{{{*/ + function _getHtmlHeader() { + return $this->HtmlHeader; + }/*}}}*/ + + /** + * 인스톨 관련 + **/ + // public String getConfigFile()/*{{{*/ + // db설정내용이 저장되어 있는 config file의 path를 return + function getConfigFile() { + return "./files/config/db.config.php"; + }/*}}}*/ + + // public boolean isInstalled()/*{{{*/ + // 설치가 되어 있는지에 대한 체크 + function isInstalled() { + return file_exists(Context::getConfigFile()); + }/*}}}*/ + + } +?> diff --git a/classes/db/DB.class.php b/classes/db/DB.class.php new file mode 100644 index 000000000..59dffa7b9 --- /dev/null +++ b/classes/db/DB.class.php @@ -0,0 +1,237 @@ + + * @desc : DB*의 상위 클래스 + **/ + + class DB { + + // connector resource or file description + var $fd = NULL; + + // result + var $result = NULL; + + // errno, errstr + var $errno = 0; + var $errstr = ''; + var $query = ''; + + // isconnected + var $is_connected = false; + + // 지원하는 DB의 종류 + var $supported_list = array(); + + // public Object &getInstance($db_type)/*{{{*/ + // DB를 상속받는 특정 db type의 instance를 생성 후 return + function &getInstance($db_type = NULL) { + if(!$db_type) $db_type = Context::getDBType(); + if(!$db_type) return new Output(-1, 'msg_db_not_setted'); + + if(!$GLOBALS['__DB__']) { + $class_name = sprintf("DB%s%s", strtoupper(substr($db_type,0,1)), strtolower(substr($db_type,1))); + $class_file = sprintf("./classes/db/%s.class.php", $class_name); + if(!file_exists($class_file)) new Output(-1, 'msg_db_not_setted'); + + require_once($class_file); + $eval_str = sprintf('$GLOBALS[\'__DB__\'] = new %s();', $class_name); + eval($eval_str); + } + + return $GLOBALS['__DB__']; + }/*}}}*/ + + /** + * 지원 가능한 DB 목록을 return + **/ + // public array getSupportedList()/*{{{*/ + // 지원하는 DB의 종류 return + function getSupportedList() { + $oDB = new DB(); + return $oDB->_getSupportedList(); + }/*}}}*/ + + // private array _getSupportedList()/*{{{*/ + function _getSupportedList() { + if(!count($this->supported_list)) { + $db_classes_path = "./classes/db/"; + $filter = "/^DB([^\.]+)\.class\.php/i"; + $this->supported_list = FileHandler::readDir($db_classes_path, $filter, true); + } + return $this->supported_list; + }/*}}}*/ + + // public boolean isSupported($db_type) /*{{{*/ + // 지원하는 DB인지에 대한 check + function isSupported($db_type) { + $supported_list = DB::getSupportedList(); + return in_array($db_type, $supported_list); + }/*}}}*/ + + /** + * 에러 남기기 + **/ + // public void setError($errno, $errstr) /*{{{*/ + function setError($errno, $errstr) { + $this->errno = $errno; + $this->errstr = $errstr; + + if(__DEBUG__ && $this->errno!=0) debugPrint(sprintf("Query Fail\t#%05d : %s - %s\n\t\t%s", $GLOBALS['__dbcnt'], $errno, $errstr, $this->query)); + }/*}}}*/ + + /** + * 각종 bool 값 return + **/ + // public boolean isConnected()/*{{{*/ + // 접속되었는지 return + function isConnected() { + return $this->is_connected; + }/*}}}*/ + + // public boolean isError()/*{{{*/ + // 오류가 발생하였는지 return + function isError() { + return $error===0?true:false; + }/*}}}*/ + + // public object getError()/*{{{*/ + function getError() { + return new Output($this->errno, $this->errstr); + }/*}}}*/ + + /** + * query execute + **/ + // public object executeQuery($query_id, $args = NULL)/*{{{*/ + // query_id = module.queryname + // query_id에 해당하는 xml문(or 캐싱파일)을 찾아서 실행 + function executeQuery($query_id, $args = NULL) { + if(!$query_id) return new Output(-1, 'msg_invalid_queryid'); + + list($module, $id) = explode('.',$query_id); + if(!$module||!$id) return new Output(-1, 'msg_invalid_queryid'); + + $xml_file = sprintf('./modules/%s/queries/%s.xml', $module, $id); + if(!file_exists($xml_file)) { + $xml_file = sprintf('./files/modules/%s/queries/%s.xml', $module, $id); + if(!file_exists($xml_file)) return new Output(-1, 'msg_invalid_queryid'); + } + + // 일단 cache 파일을 찾아본다 + $cache_file = sprintf('./files/queries/%s.cache.php', $query_id); + + // 없으면 원본 쿼리 xml파일을 찾아서 파싱을 한다 + if(!file_exists($cache_file)||filectime($cache_file)parse($query_id, $xml_file, $cache_file); + } + + // 쿼리를 실행한다 + return $this->_executeQuery($cache_file, $args, $query_id); + }/*}}}*/ + + // private object _executeQuery($cache_file, $args)/*{{{*/ + // 쿼리문을 실행하고 결과를 return한다 + function _executeQuery($cache_file, $source_args, $query_id) { + global $lang; + + if(!file_exists($cache_file)) return new Output(-1, 'msg_invalid_queryid'); + + if(__DEBUG__) $query_start = getMicroTime(); + + if($source_args) $args = clone($source_args); + $output = include($cache_file); + + if( (is_a($output, 'Output')||is_subclass_of($output,'Output'))&&!$output->toBool()) return $output; + + // action값에 따라서 쿼리 생성으로 돌입 + switch($action) { + case 'insert' : + $output = $this->_executeInsertAct($tables, $column, $pass_quotes); + break; + case 'update' : + $output = $this->_executeUpdateAct($tables, $column, $condition, $pass_quotes); + break; + case 'delete' : + $output = $this->_executeDeleteAct($tables, $condition, $pass_quotes); + break; + case 'select' : + $output = $this->_executeSelectAct($tables, $column, $invert_columns, $condition, $navigation, $group_script, $pass_quotes); + break; + } + + if(__DEBUG__) { + $query_end = getMicroTime(); + $elapsed_time = $query_end - $query_start; + $GLOBALS['__db_elapsed_time__'] += $elapsed_time; + $GLOBALS['__db_queries__'] .= sprintf("\t%02d. %s (%0.4f sec)\n\t %s\n", ++$GLOBALS['__dbcnt'], $query_id, $elapsed_time, $this->query); + } + + if($this->errno!=0) return new Output($this->errno, $this->errstr); + if(is_a($output, 'Output') || is_subclass_of($output, 'Output')) return $output; + return new Output(); + }/*}}}*/ + + // private object _checkFilter($key, $val, $filter_type, $minlength, $maxlength) /*{{{*/ + // $val을 $filter_type으로 검사 + function _checkFilter($key, $val, $filter_type, $minlength, $maxlength) { + global $lang; + + $length = strlen($val); + if($minlength && $length < $minlength) return new Output(-1, sprintf($lang->filter->outofrange, $lang->{$key}?$lang->{$key}:$key)); + if($maxlength && $length > $maxlength) return new Output(-1, sprintf($lang->filter->outofrange, $lang->{$key}?$lang->{$key}:$key)); + + switch($filter_type) { + case 'email' : + case 'email_adderss' : + if(!eregi('^[_0-9a-z-]+(\.[_0-9a-z-]+)*@[0-9a-z-]+(\.[0-9a-z-]+)*$', $val)) return new Output(-1, sprintf($lang->filter->invalid_email, $lang->{$key}?$lang->{$key}:$key)); + break; + case 'homepage' : + if(!eregi('^(http|https)+(:\/\/)+[0-9a-z_-]+\.[^ ]+$', $val)) return new Output(-1, sprintf($lang->filter->invalid_homepage, $lang->{$key}?$lang->{$key}:$key)); + break; + case 'userid' : + case 'user_id' : + if(!eregi('^[a-zA-Z]+([_0-9a-zA-Z]+)*$', $val)) return new Output(-1, sprintf($lang->filter->invalid_userid, $lang->{$key}?$lang->{$key}:$key)); + break; + case 'number' : + if(!eregi('^[0-9]+$', $val)) return new Output(-1, sprintf($lang->filter->invalid_number, $lang->{$key}?$lang->{$key}:$key)); + break; + case 'alpha' : + if(!eregi('^[a-z]+$', $val)) return new Output(-1, sprintf($lang->filter->invalid_alpha, $lang->{$key}?$lang->{$key}:$key)); + break; + case 'alpha_number' : + if(!eregi('^[0-9a-z]+$', $val)) return new Output(-1, sprintf($lang->filter->invalid_alpha_number, $lang->{$key}?$lang->{$key}:$key)); + break; + } + + return new Output(); + }/*}}}*/ + + // private string _combineCondition($cond_group, $group_pipe) /*{{{*/ + function _combineCondition($cond_group, $group_pipe) { + if(!is_array($cond_group)) return; + $cond_query = ''; + foreach($cond_group as $group_idx => $group) { + if(!is_array($group)) continue; + + $buff = ''; + foreach($group as $key => $val) { + $pipe = key($val); + $cond = array_pop($val); + if($buff) $buff .= $pipe.' '.$cond; + else $buff = $cond; + } + + $g_pipe = $group_pipe[$group_idx]; + if(!$g_pipe) $g_pipe = 'and'; + if($cond_query) $cond_query .= sprintf(' %s ( %s )', $g_pipe, $buff); + else $cond_query = '('.$buff.')'; + } + return $cond_query; + }/*}}}*/ + + } +?> diff --git a/classes/db/DBMysql.class.php b/classes/db/DBMysql.class.php new file mode 100644 index 000000000..bac4ae71a --- /dev/null +++ b/classes/db/DBMysql.class.php @@ -0,0 +1,375 @@ + + * @desc : db(mysql, cubrid, sqlite..)를 이용하기 위한 db class의 abstract class + **/ + + class DBMysql extends DB { + + // db info + var $hostname = '127.0.0.1'; + var $userid = NULL; + var $password = NULL; + var $database = NULL; + var $prefix = 'zb'; + + // mysql에서 사용될 column type + var $column_type = array( + 'number' => 'int', + 'varchar' => 'varchar', + 'char' => 'char', + 'text' => 'text', + 'date' => 'varchar(14)', + ); + + // public void DBMysql()/*{{{*/ + function DBMysql() { + $this->_setDBInfo(); + $this->_connect(); + }/*}}}*/ + + /** + * DB정보 설정 및 connect/ close + **/ + // public boolean _setDBInfo()/*{{{*/ + function _setDBInfo() { + $db_info = Context::getDBInfo(); + $this->hostname = $db_info->db_hostname; + $this->userid = $db_info->db_userid; + $this->password = $db_info->db_password; + $this->database = $db_info->db_database; + $this->prefix = $db_info->db_table_prefix; + if(!substr($this->prefix,-1)!='_') $this->prefix .= '_'; + }/*}}}*/ + + // public boolean _connect()/*{{{*/ + function _connect() { + // db 정보가 없으면 무시 + if(!$this->hostname || !$this->userid || !$this->password || !$this->database) return; + + // 접속시도 + $this->fd = @mysql_connect($this->hostname, $this->userid, $this->password); + if(mysql_error()) { + $this->setError(mysql_errno(), mysql_error()); + return; + } + + // db 선택 + @mysql_select_db($this->database, $this->fd); + if(mysql_error()) { + $this->setError(mysql_errno(), mysql_error()); + return; + } + + // 접속체크 + $this->is_connected = true; + + // mysql의 경우 utf8임을 지정 + $this->_query("SET NAMES 'utf8'"); + }/*}}}*/ + + // public boolean close()/*{{{*/ + function close() { + if(!$this->isConnected()) return; + @mysql_close($this->fd); + }/*}}}*/ + + /** + * add quotation + **/ + // public string addQuotes(string $string)/*{{{*/ + function addQuotes($string) { + if(get_magic_quotes_gpc()) $string = stripslashes(str_replace("\\","\\\\",$string)); + if(!is_numeric($string)) $string = @mysql_escape_string($string); + return $string; + }/*}}}*/ + + /** + * query : query문 실행하고 result return + * fetch : reutrn 된 값이 없으면 NULL + * rows이면 array object + * row이면 object + * return + * getNextSequence : 1씩 증가되는 sequence값을 return (mysql의 auto_increment는 sequence테이블에서만 사용) + */ + // private object _query(string $query) /*{{{*/ + function _query($query) { + if(!$this->isConnected()) return; + $this->query = $query; + + $this->setError(0,'success'); + + $result = @mysql_query($query, $this->fd); + + if(mysql_error()) { + $this->setError(mysql_errno(), mysql_error()); + return; + } + + return $result; + }/*}}}*/ + + // private object _fetch($result) /*{{{*/ + function _fetch($result) { + if($this->errno!=0 || !$result) return; + while($tmp = mysql_fetch_object($result)) { + $output[] = $tmp; + } + if(count($output)==1) return $output[0]; + return $output; + }/*}}}*/ + + // public int getNextSequence() /*{{{*/ + // sequence값을 받음 + function getNextSequence() { + $query = sprintf("insert into `%ssequence` (seq) values ('')", $this->prefix); + $this->_query($query); + return mysql_insert_id(); + }/*}}}*/ + + /** + * Table의 Create/Drop/Alter/Rename/Truncate/Dump... + **/ + // public boolean isTableExists(string $table_name)/*{{{*/ + function isTableExists($target_name) { + $query = sprintf("show tables like '%s%s'", $this->prefix, $this->addQuotes($target_name)); + $result = $this->_query($query); + $tmp = $this->_fetch($result); + if(!$tmp) return false; + return true; + }/*}}}*/ + + // public boolean createTableByXml($xml) /*{{{*/ + // xml 을 받아서 테이블을 생성 + function createTableByXml($xml_doc) { + return $this->_createTable($xml_doc); + }/*}}}*/ + + // public boolean createTableByXmlFile($file_name) /*{{{*/ + // xml 을 받아서 테이블을 생성 + function createTableByXmlFile($file_name) { + if(!file_exists($file_name)) return; + // xml 파일을 읽음 + $buff = FileHandler::readFile($file_name); + return $this->_createTable($buff); + }/*}}}*/ + + // private boolean _createTable($xml)/*{{{*/ + // type : number, varchar, text, char, date, + // opt : notnull, default, size + // index : primary key, index, unique + function _createTable($xml_doc) { + // xml parsing + $oXml = new XmlParser(); + $xml_obj = $oXml->parse($xml_doc); + + // 테이블 생성 schema 작성 + $table_name = $xml_obj->table->attrs->name; + if($this->isTableExists($table_name)) return; + $table_name = $this->prefix.$table_name; + + if(!is_array($xml_obj->table->column)) $columns[] = $xml_obj->table->column; + else $columns = $xml_obj->table->column; + foreach($columns as $column) { + $name = $column->attrs->name; + $type = $column->attrs->type; + $size = $column->attrs->size; + $notnull = $column->attrs->notnull; + $primary_key = $column->attrs->primary_key; + $index = $column->attrs->index; + $unique = $column->attrs->unique; + $default = $column->attrs->default; + $auto_increment = $column->attrs->auto_increment; + + $column_schema[] = sprintf('`%s` %s%s %s %s %s', + $name, + $this->column_type[$type], + $size?'('.$size.')':'', + $default?"default '".$default."'":'', + $notnull?'not null':'', + $auto_increment?'auto_increment':'' + ); + + if($primary_key) $primary_list[] = $name; + else if($unique) $unique_list[$unique][] = $name; + else if($index) $index_list[$index][] = $name; + } + + if(count($primary_list)) { + $column_schema[] = sprintf("primary key (%s)", '`'.implode($primary_list,'`,`').'`'); + } + + if(count($unique_list)) { + foreach($unique_list as $key => $val) { + $column_schema[] = sprintf("unique %s (%s)", $key, '`'.implode($val,'`,`').'`'); + } + } + + if(count($index_list)) { + foreach($index_list as $key => $val) { + $column_schema[] = sprintf("index %s (%s)", $key, '`'.implode($val,'`,`').'`'); + } + } + + $schema = sprintf('create table `%s` (%s%s);', $this->addQuotes($table_name), "\n", implode($column_schema,",\n")); + $output = $this->_query($schema); + if(!$output) return false; + }/*}}}*/ + + // public boolean dropTable($target_name) /*{{{*/ + // 테이블 삭제 + function dropTable($target_name) { + $query = sprintf('drop table `%s%s`;', $this->prefix, $this->addQuotes($target_name)); + $this->_query($query); + }/*}}}*/ + + // public boolean renameTable($source_name, $targe_name) /*{{{*/ + // 테이블의 이름 변경 + function renameTable($source_name, $targe_name) { + $query = sprintf("alter table `%s%s` rename `%s%s`;", $this->prefix, $this->addQuotes($source_name), $this->prefix, $this->addQuotes($targe_name)); + $this->_query($query); + }/*}}}*/ + + // public boolean truncateTable($target_name) /*{{{*/ + // 테이블을 비움 + function truncateTable($target_name) { + $query = sprintf("truncate table `%s%s`;", $this->prefix, $this->addQuotes($target_name)); + $this->_query($query); + }/*}}}*/ + + // public boolean dumpTable($target_name) 미완성 /*{{{*/ + // 테이블 데이터 Dump + function dumpTable($target_name) { + }/*}}}*/ + + /** + * insert/update/delete/select 구현 + **/ + // private string _executeInsertAct($tables, $column, $pass_quotes)/*{{{*/ + function _executeInsertAct($tables, $column, $pass_quotes) { + $table = array_pop($tables); + + foreach($column as $key => $val) { + $key_list[] = $key; + if(in_array($key, $pass_quotes)) $val_list[] = $this->addQuotes($val); + else $val_list[] = '\''.$this->addQuotes($val).'\''; + } + + $query = sprintf("insert into `%s%s` (%s) values (%s);", $this->prefix, $table, '`'.implode('`,`',$key_list).'`', implode(',', $val_list)); + return $this->_query($query); + }/*}}}*/ + + // private string _executeUpdateAct($tables, $column, $condition, $pass_quotes)/*{{{*/ + function _executeUpdateAct($tables, $column, $condition, $pass_quotes) { + $table = array_pop($tables); + + foreach($column as $key => $val) { + if(in_array($key, $pass_quotes)) $update_list[] = sprintf('`%s` = %s', $key, $this->addQuotes($val)); + else $update_list[] = sprintf('`%s` = \'%s\'', $key, $this->addQuotes($val)); + } + if(!count($update_list)) return; + $update_query = implode(',',$update_list); + + if($condition) $condition = ' where '.$condition; + + $query = sprintf("update `%s%s` set %s %s;", $this->prefix, $table, $update_query, $condition); + return $this->_query($query); + }/*}}}*/ + + // private string _executeDeleteAct($tables, $condition, $pass_quotes)/*{{{*/ + function _executeDeleteAct($tables, $condition, $pass_quotes) { + $table = array_pop($tables); + + if($condition) $condition = ' where '.$condition; + + $query = sprintf("delete from `%s%s` %s;", $this->prefix, $table, $condition); + return $this->_query($query); + }/*}}}*/ + + // private string _executeSelectAct($tables, $column, $invert_columns, $condition, $navigation, $pass_quotes)/*{{{*/ + // 네비게이션 변수 정리를 해야함 + function _executeSelectAct($tables, $column, $invert_columns, $condition, $navigation, $group_script, $pass_quotes) { + if(!count($tables)) $table = $this->prefix.array_pop($tables); + else { + foreach($tables as $key => $val) $table_list[] = sprintf('%s%s as %s', $this->prefix, $key, $val); + } + $table = implode(',',$table_list); + + if(!$column) $columns = '*'; + else { + foreach($invert_columns as $key => $val) { + $column_list[] = sprintf('%s as %s',$val, $key); + } + $columns = implode(',', $column_list); + } + + if($condition) $condition = ' where '.$condition; + + if($navigation->list_count) return $this->_getNavigationData($table, $columns, $condition, $navigation); + + $query = sprintf("select %s from %s %s", $columns, $table, $condition); + + $query .= ' '.$group_script; + + if($navigation->index) { + foreach($navigation->index as $index_obj) { + $index_list[] = sprintf('%s %s', $index_obj[0], $index_obj[1]); + } + if(count($index_list)) $query .= ' order by '.implode(',',$index_list); + } + + + $result = $this->_query($query); + if($this->errno!=0) return; + $data = $this->_fetch($result); + + $buff = new Output(); + $buff->data = $data; + return $buff; + }/*}}}*/ + + // private function _getNavigationData($query)/*{{{*/ + // query xml에 navigation 정보가 있을 경우 페이징 관련 작업을 처리한다 + // 그닥 좋지는 않은 구조이지만 편리하다.. -_-; + function _getNavigationData($table, $columns, $condition, $navigation) { + // 전체 개수를 구함 + $count_query = sprintf("select count(*) as count from %s %s", $table, $condition); + $result = $this->_query($count_query); + $count_output = $this->_fetch($result); + $total_count = (int)$count_output->count; + + // 전체 페이지를 구함 + $total_page = (int)(($total_count-1)/$navigation->list_count) +1; + + // 페이지 변수를 체크 + if($navigation->page > $total_page) $page = $navigation->page; + else $page = $navigation->page; + $start_count = ($page-1)*$navigation->list_count; + + foreach($navigation->index as $index_obj) { + $index_list[] = sprintf('%s %s', $index_obj[0], $index_obj[1]); + } + + $index = implode(',',$index_list); + $query = sprintf('select %s from %s %s order by %s limit %d, %d', $columns, $table, $condition, $index, $start_count, $navigation->list_count); + $result = $this->_query($query); + if($this->errno!=0) return; + + $virtual_no = $total_count - ($page-1)*$navigation->list_count; + while($tmp = mysql_fetch_object($result)) { + $data[$virtual_no--] = $tmp; + } + + $buff = new Output(); + $buff->total_count = $total_count; + $buff->total_page = $total_page; + $buff->page = $page; + $buff->data = $data; + + require_once('./classes/page/PageHandler.class.php'); + $buff->page_navigation = new PageHandler($total_count, $total_page, $page, $navigation->page_count); + return $buff; + }/*}}}*/ + } +?> diff --git a/classes/display/DisplayHandler.class.php b/classes/display/DisplayHandler.class.php new file mode 100644 index 000000000..22080644e --- /dev/null +++ b/classes/display/DisplayHandler.class.php @@ -0,0 +1,154 @@ + + * @desc : display 객체 + * Request Method에 따라서 html or xml 출력방법을 결정한다 + * xml : oModule의 variables를 simple xml 로 출력 + * html : oModule의 template/variables로 html을 만들고 contents_html로 처리 + * plugin이나 layout의 html과 연동하여 출력 + * + **/ + + class DisplayHandler { + + // 출력하는 컨텐츠의 사이즈 + var $content_size = 0; + + // public void printContent() /*{{{*/ + function printContent($oModule) { + // header 출력 + $this->_printHeader(); + + // request method에 따른 처리 + $content = $this->getContent($oModule); + + // 요청방식에 따라 출력을 별도로 + if(Context::getRequestMethod()!="XMLRPC") { + Context::set('content', $content); + + // content 래핑 (common/tpl/default.html) + require_once("./classes/template/TemplateHandler.class.php"); + $oTemplate = new TemplateHandler(); + $output = $oTemplate->compile($oModule->layout_path, $oModule->layout_tpl); + } else { + $output = $content; + } + + $this->content_size = strlen($output); + print $output; + + // 디버깅 데이터 출력 + $this->_debugOutput(); + }/*}}}*/ + + // public void getContent() /*{{{*/ + function getContent($oModule) { + // request method에 따른 처리 + return $this->_toDoc($oModule); + }/*}}}*/ + + /** + * 문서 출력 + **/ + // private string _toDoc($oModule) /*{{{*/ + function _toDoc($oModule) { + if(Context::getRequestMethod() == 'XMLRPC') $content = $this->_toXmlDoc($oModule); + else $content = $this->_toHTMLDoc($oModule); + return $content; + }/*}}}*/ + + // private string _toXmlDoc($oModule) /*{{{*/ + function _toXmlDoc($oModule) { + $xmlDoc = "\n"; + $xmlDoc .= sprintf("%s\n",$oModule->getError()); + $xmlDoc .= sprintf("%s\n",$oModule->getMessage()); + + $variables = $oModule->getVariables(); + if(count($variables)) { + foreach($variables as $key => $val) { + if(is_string($val)) $val = ''; + $xmlDoc .= "<{$key}>{$val}\n"; + } + } + + $xmlDoc .= ""; + + return $xmlDoc; + }/*}}}*/ + + // private string _toHTMLDoc($oModule) /*{{{*/ + function _toHTMLDoc($oModule) { + // template handler 객체 생성 + require_once("./classes/template/TemplateHandler.class.php"); + $oTemplate = new TemplateHandler(); + + // module tpl 변환 + $template_path = $oModule->getTemplatePath(); + $tpl_file = $oModule->getTemplateFile(); + return $oTemplate->compile($template_path, $tpl_file); + }/*}}}*/ + + // public int getContentSize() /*{{{*/ + function getContentSize() { + return $this->content_size; + }/*}}}*/ + + // private void _debugOutput()/*{{{*/ + // __DEBUG__가 true일 경우 각 부분의 실행시간등을 debugPrint 함수를 이용해서 출력 + // 개발시나 테스트시에 config/config.inc.php의 __DEBUG__를 true로 세팅하고 + // tail -f ./files/_debug_message.php로 하여 console로 확인하면 편리함 + function _debugOutput() { + if(!__DEBUG__) return; + $end = getMicroTime(); + + $buff = "\n\n** Debug at ".date('Y-m-d H:i:s')." ************************************************************\n"; + $buff .= "\n- Request/ Response info\n"; + $buff .= sprintf("\tRequest URI \t\t\t: %s:%s%s%s%s\n", $_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], $_SERVER['PHP_SELF'], $_SERVER['QUERY_STRING']?'?':'', $_SERVER['QUERY_STRING']); + $buff .= sprintf("\tRequest method \t\t\t: %s\n", $_SERVER['REQUEST_METHOD']); + $buff .= sprintf("\tResponse contents size\t\t: %d byte\n", $this->getContentSize()); + if($GLOBALS['__db_queries__']) { + $buff .= "\n- DB Queries\n"; + $buff .= $GLOBALS['__db_queries__']; + } + $buff .= "\n- Elapsed time\n"; + + if($GLOBALS['__db_elapsed_time__']) $buff .= sprintf("\tDB queries elapsed time\t\t: %0.5f sec\n", $GLOBALS['__db_elapsed_time__']); + $buff .= sprintf("\tclass file load elapsed time \t: %0.5f sec\n", __RequireClassEndTime__-__RequireClassStartTime__); + $buff .= sprintf("\tTemplate compile elapsed time\t: %0.5f sec\n", $GLOBALS['__template_elapsed__']); + $buff .= sprintf("\tPHP elapsed time \t\t: %0.5f sec\n", $end-__StartTime__-$GLOBALS['__template_elapsed__']-$GLOBALS['__db_elapsed_time__']-(__RequireClassEndTime__-__RequireClassStartTime__)); + $buff .= sprintf("\tTotal elapsed time \t\t: %0.5f sec", $end-__StartTime__); + + debugPrint($buff, false); + }/*}}}*/ + + /** + * 헤더 출력 + ***/ + // private void _printHeader()/*{{{*/ + function _printHeader() { + if(Context::getRequestMethod() == 'XMLRPC') return $this->_printXMLHeader(); + else return $this->_printHTMLHeader(); + }/*}}}*/ + + // private void _printXMLHeader()/*{{{*/ + function _printXMLHeader() { + header("Content-Type: text/xml; charset=UTF-8"); + header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); + header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); + header("Cache-Control: no-store, no-cache, must-revalidate"); + header("Cache-Control: post-check=0, pre-check=0", false); + header("Pragma: no-cache"); + }/*}}}*/ + + // private void _printHTMLHeader()/*{{{*/ + function _printHTMLHeader() { + header("Content-Type: text/html; charset=UTF-8"); + header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); + header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); + header("Cache-Control: no-store, no-cache, must-revalidate"); + header("Cache-Control: post-check=0, pre-check=0", false); + header("Pragma: no-cache"); + }/*}}}*/ + } +?> diff --git a/classes/file/FileHandler.class.php b/classes/file/FileHandler.class.php new file mode 100644 index 000000000..bbec5b2bb --- /dev/null +++ b/classes/file/FileHandler.class.php @@ -0,0 +1,94 @@ + + * @desc : 파일 시스템 관련 라이브러리 + **/ + + class FileHandler { + + // public String readFile()/*{{{*/ + function readFile($file_name) { + if(!file_exists($file_name)) return; + if(filesize($file_name)<1) return; + $fp = fopen($file_name, "r"); + $buff = fread($fp, filesize($file_name)); + fclose($fp); + return trim($buff); + }/*}}}*/ + + // public String writeFile($file_name, $buff, $mode = "w")/*{{{*/ + function writeFile($file_name, $buff, $mode = "w") { + $mode = strtolower($mode); + if($mode != "a") $mode = "w"; + if(@!$fp = fopen($file_name,$mode)) return; + fwrite($fp, $buff); + fclose($fp); + }/*}}}*/ + + // public array readDir($path, $filter = '', $to_lower = flase)/*{{{*/ + // $path내의 파일들을 return ('.', '..', '.로 시작하는' 파일들은 제외) + function readDir($path, $filter = '', $to_lower = false, $concat_prefix = false) { + if(substr($path,-1)!='/') $path .= '/'; + if(!is_dir($path)) return array(); + $oDir = dir($path); + while($file = $oDir->read()) { + if(substr($file,0,1)=='.') continue; + if($filter && !preg_match($filter, $file)) continue; + if($to_lower) $file = strtolower($file); + if($filter) $file = preg_replace($filter, '$1', $file); + else $file = $file; + + if($concat_prefix) $file = $path.$file; + $output[] = $file; + } + if(!$output) return array(); + return $output; + }/*}}}*/ + + // public boolean makeDir($path) {/*{{{*/ + // 디렉토리 생성 + function makeDir($path_string) { + $path_list = explode('/', $path_string); + + for($i=0;$iread()) { + if ($entry != "." && $entry != "..") { + if (is_dir($path."/".$entry)) { + FileHandler::removeDir($path."/".$entry); + } else { + @unlink($path."/".$entry); + } + } + } + $directory->close(); + @rmdir($path); + }/*}}}*/ + + // public string filesize($size) /*{{{*/ + // byte단위의 파일크기를 적절하게 변환해서 return + function filesize($size) { + if(!$size) return "0Byte"; + if($size<1024) return ($size."Byte"); + if($size >1024 && $size< 1024 *1024) return sprintf("%0.1fKB",$size / 1024); + return sprintf("%0.2fMB",$size / (1024*1024)); + }/*}}}*/ + + + } +?> diff --git a/classes/layout/LayoutHandler.class.php b/classes/layout/LayoutHandler.class.php new file mode 100644 index 000000000..2f14d7f1e --- /dev/null +++ b/classes/layout/LayoutHandler.class.php @@ -0,0 +1,45 @@ + + * @desc : layout 실행 + **/ + + class LayoutHandler { + + var $layout_info; + var $layout_name; + + function callLayout(&$oModule, $oModuleInfo) { + if($oModule->getActType() != 'disp') return; + if(!$oModuleInfo->isLayoutExists()) return; + + $oLayout = new LayoutHandler(); + $oLayout->proc($oModule, $oModuleInfo); + } + + function proc(&$oModule, $oModuleInfo) { + $this->layout_info = $oModuleInfo->getLayout(); + $this->layout_name = $this->layout_info->layout_name; + $this->layout_name = 'test'; + + // 해당 모듈을 읽어서 객체를 만듬 + $layout_file = sprintf('./layouts/%s/%s.layout.php', $this->layout_name, $this->layout_name); + + // 모듈 파일이 없으면 에러 + if(!file_exists($layout_file)) return; + + // 모듈 파일을 include + require_once($layout_file); + + // 선택된 모듈의 instance는 eval string으로 처리 + $eval_str = sprintf('$oLayout = new %s();', $this->layout_name); + eval($eval_str); + + // 애드온 실행 + $oLayout->proc($oModule, $oModuleInfo); + } + + + } +?> diff --git a/classes/module/Module.class.php b/classes/module/Module.class.php new file mode 100644 index 000000000..42eaf89aa --- /dev/null +++ b/classes/module/Module.class.php @@ -0,0 +1,132 @@ + + * @desc : modules의 abstract class + **/ + + // abstract class Module + class Module extends Output { + + // 현재 모듈의 실행 위치 + var $module_path = NULL; + + // skin 설정 (없을 경우도 있음) + var $skin = 'default'; + + // 현재 모듈 생성시 주어진 설정 정보들 + var $module_srl = NULL; + var $module_info = NULL; + + // 모듈의 action을 정의하는 변수 설정 + var $act = NULL; + var $act_type = 'disp'; + + // 레이아웃 path, tpl + var $layout_path = "./common/tpl/"; + var $layout_tpl = "default_layout"; + + // public void moduleInit($module_info)/*{{{*/ + // 모듈의 정보 세팅 + function moduleInit($module_info) { + // 브라우저 타이틀 지정 + Context::setBrowserTitle($module_info->browser_title?$module_info->browser_title:$module_info->mid); + + // 기본 변수 설정 + $this->module_info = $module_info; + context::set('module_info', &$this->module_info); + + $this->module_srl = $module_info->module_srl; + + // skin 설정 (기본으로는 default) + if($this->module_info->skin) $this->skin = $this->module_info->skin; + else $this->skin = 'default'; + + // 템플릿 위치 설정 + if(!$this->template_path) { + $template_path = $this->module_path.'skins/'.$this->skin; + $this->setTemplatePath($template_path); + } + }/*}}}*/ + + // public boolean isExistsAct($act)/*{{{*/ + // 현재 모듈에 $act에 해당하는 method가 있는지 체크 + function isExistsAct($act) { + return method_exists($this, $act); + }/*}}}*/ + + // public String getActType()/*{{{*/ + // 현재 acT_type의 return (disp/proc) + function getActType() { + return $this->act_type; + }/*}}}*/ + + // public void setModulePath($path)/*{{{*/ + // 현재 모듈의 path를 지정 + function setModulePath($path) { + if(substr($path,-1)!='/') $path.='/'; + $this->module_path = $path; + }/*}}}*/ + + // public boolean doError($msg_code) /*{{{*/ + function doError($msg_code) { + $this->setError(-1); + if(!Context::getLang($msg_code)) $this->setMessage($msg_code); + else $this->setMessage(Context::getLang($msg_code)); + return false; + }/*}}}*/ + + // public void setLayoutPath($path)/*{{{*/ + function setLayoutPath($path) { + $this->layout_path = $path; + }/*}}}*/ + + // public void setLayoutTpl($tpl)/*{{{*/ + function setLayoutTpl($tpl) { + $this->layout_tpl = $tpl; + }/*}}}*/ + + // public void proc($act = null)/*{{{*/ + //모듈의 각 action을 실행하는 부분 + //$act값에 의해서 $action_list에 선언된 것들을 실행한다 + function proc($act = null) { + + // 별도로 요청한 act가 없으면 주어진 act를 이용 + if($act) $this->act = $act; + else $this->act = Context::get('act'); + + // act의 종류가 disp/proc인지에 대한 확인 + if($this->act&&strtolower(substr($this->act,0,4)) != 'disp') $this->act_type = 'proc'; + + // act값이 없거나 존재하지 않는 method를 호출시에 default_act를 지정 + if(!$this->act || !$this->isExistsAct($this->act)) $this->act = $this->default_act; + + // module의 *init 호출 (기본 init과 proc/disp init 2가지 있음) + if($this->act_type == 'proc') { + $output = $this->procInit(); + if((is_a($output, 'Output') || is_subclass_of($output, 'Output')) && !$output->toBool() ) { + $this->setError($output->getError()); + $this->setMessage($output->getMessage()); + return; + } elseif(!$output) { + $this->setError(-1); + $this->setMessage('fail'); + return; + } + } else $this->dispInit(); + + // 기본 act조차 없으면 return + if(!$this->isExistsAct($this->act)) return false; + + // act값으로 method 실행 + $output = call_user_method($this->act, $this); + + if(is_a($output, 'Output') || is_subclass_of($output, 'Output')) { + $this->setError($output->getError()); + $this->setMessage($output->getMessage()); + } + + return true; + }/*}}}*/ + } +?> diff --git a/classes/module/ModuleHandler.class.php b/classes/module/ModuleHandler.class.php new file mode 100644 index 000000000..908a33b6b --- /dev/null +++ b/classes/module/ModuleHandler.class.php @@ -0,0 +1,87 @@ + + * @desc : mid의 값으로 모듈을 찾고 관련 정보들을 세팅 + **/ + + class ModuleHandler { + + // mid와 해당 mid의 설정 값 + var $mid = NULL; + var $module_info = NULL; + + // 모듈과 해당 모듈의 instance + var $module = NULL; + var $oModule = NULL; + + // public void ModuleHandler()/*{{{*/ + function ModuleHandler() { + + // 설치가 안되어 있다면 설치를 위한 준비 + if(!Context::isInstalled()) return $this->_prepareInstall(); + + // 설치가 되어 있다면 요청받은 mid에 해당하는 모듈 instance 생성 + // mid가 없이 document_srl만 있다면 document_srl로 mid를 찾음 + $mid = Context::get('mid'); + $document_srl = Context::get('document_srl'); + + // document_srl만 있다면 mid를 구해옴 + if(!$mid && $document_srl) { + $module_info = module_manager::getModuleInfoByDocument($document_srl); + if($module_info) $mid = $module_info->mid; + } + + // mid 값에 대한 모듈 정보를 추출 + if(!$module_info) $module_info = module_manager::getModuleInfo($mid); + + // 모듈 정보에서 module 이름을 구해움 + $module = $module_info->module; + + $this->mid = $module_info->mid; + $this->module_info = $module_info; + + Context::set('module', $module); + Context::set('mid', $this->mid, true); + Context::set('module_srl', $this->module_info->module_srl, true); + + // 만약 모듈이 없다면 오류 출력 + if(!$module) return $this->_moduleIsNotExists(); + + $this->oModule = getModule($module); + $this->module = $module; + }/*}}}*/ + + // private void _prepareInstall()/*{{{*/ + // 설치를 하기 위해서 mid, module등을 강제 지정 + function _prepareInstall() { + // module로 install 모듈을 지정 + $this->module = 'install'; + Context::set('mid', NULL); + Context::set('module', $this->module); + + // module_manager 호출 + $this->oModule = getModule($this->module); + }/*}}}*/ + + // private void _moduleIsNotExists()/*{{{*/ + // 아무런 설정이 되어 있지 않다면 오류 표시 + function _moduleIsNotExists() { + $this->module = 'message'; + Context::set('mid', NULL); + Context::set('module', $this->module); + + $this->oModule = getModule($this->module); + + Context::set('error', -1); + Context::set('message', Context::getLang('msg_mid_not_exists')); + }/*}}}*/ + + // public object proc()/*{{{*/ + function proc() { + $this->oModule->moduleInit($this->module_info); + $this->oModule->proc(); + return $this->oModule; + }/*}}}*/ + } +?> diff --git a/classes/output/Output.class.php b/classes/output/Output.class.php new file mode 100644 index 000000000..9f0fb3563 --- /dev/null +++ b/classes/output/Output.class.php @@ -0,0 +1,110 @@ + + * @desc : result 객체 + * request method에 따라서 error+message+variables[]를 xml문서로 + * 또는 html 출력을 + * 또는 사용법에 따라 error로 결과를 리턴한다 + * error != 0 이면 에러가 발생하였다는 것으로 정의 + **/ + + class Output { + + // template path 지정 + var $template_path = NULL; + var $template_file = NULL; + + // 기본 에러와 메세지 + var $error = 0; + var $message = 'success'; + + // 추가 변수 + var $variables = array(); + + // public void Output($error = 0, $message = 'success')/*{{{*/ + // error 코드를 지정 + function Output($error = 0, $message = 'success') { + $this->error = $error; + $this->message = $message; + }/*}}}*/ + + // public void setError($error)/*{{{*/ + // error 코드를 지정 + function setError($error = 0) { + $this->error = $error; + }/*}}}*/ + + // public string getError()/*{{{*/ + function getError() { + return $this->error; + }/*}}}*/ + + // public void setMessage($message)/*{{{*/ + // 메세지 지정 + function setMessage($message = 'success') { + if(Context::getLang($message)) $message = Context::getLang($message); + $this->message = $message; + return true; + }/*}}}*/ + + // public string getMessage()/*{{{*/ + // 메세지 지정 + function getMessage() { + return $this->message; + }/*}}}*/ + + // public void add($key, $val)/*{{{*/ + // xml문서를 작성시 필요한 key, val 추가 + function add($key, $val) { + $this->variables[$key] = $val; + }/*}}}*/ + + // public string get($key)/*{{{*/ + // 추가된 변수의 key에 해당하는 값을 return + function get($key) { + return $this->variables[$key]; + }/*}}}*/ + + // public array getVariables()/*{{{*/ + // 설정된 variables를 return + function getVariables() { + return $this->variables; + }/*}}}*/ + + // public boolean toBool()/*{{{*/ + // error값이 0이 아니면 오류 + function toBool() { + return $this->error==0?true:false; + }/*}}}*/ + + // public boolean toBoolean()/*{{{*/ + // error값이 0이 아니면 오류 + function toBoolean() { + return $this->toBool(); + }/*}}}*/ + + // public void setTemplatePath($path)/*{{{*/ + // 현재 모듈의 tpl 파일을 저장 + function setTemplatePath($path) { + if(!substr($path,-1)!='/') $path .= '/'; + $this->template_path = $path; + }/*}}}*/ + + // public string getTemplatePath()/*{{{*/ + // 설정된 template path를 return + function getTemplatePath() { + return $this->template_path; + }/*}}}*/ + + // public void setTemplateFile($filename)/*{{{*/ + function setTemplateFile($filename) { + $this->template_file = $filename; + }/*}}}*/ + + // public string getTemplateFile()/*{{{*/ + function getTemplateFile() { + return $this->template_file; + }/*}}}*/ + } +?> diff --git a/classes/page/PageHandler.class.php b/classes/page/PageHandler.class.php new file mode 100644 index 000000000..d68549200 --- /dev/null +++ b/classes/page/PageHandler.class.php @@ -0,0 +1,42 @@ + + * @desc : 페이지 처리 + **/ + + class PageHandler { + + var $total_count = 0; + var $total_page = 0; + var $cur_page = 0; + var $page_count = 10; + var $first_page = 1; + var $last_page = 1; + var $point = 0; + + function PageHandler($total_count, $total_page, $cur_page, $page_count = 10) { + $this->total_count = $total_count; + $this->total_page = $total_page; + $this->cur_page = $cur_page; + $this->page_count = $page_count; + $this->point = 0; + + $first_page = $cur_page-(int)($page_count/2); + if($first_page<1) $first_page = 1; + $last_page = $first_page+$page_count-1; + if($last_page>$total_page) $last_page = $total_page; + + $this->first_page = $first_page; + $this->last_page = $last_page; + } + + function getNextPage() { + $page = $this->first_page+$this->point++; + if($page > $this->last_page) $page = 0; + return $page; + } + + } + +?> diff --git a/classes/template/TemplateHandler.class.php b/classes/template/TemplateHandler.class.php new file mode 100644 index 000000000..6b8ab2c70 --- /dev/null +++ b/classes/template/TemplateHandler.class.php @@ -0,0 +1,286 @@ + + * @desc : 템플릿 컴파일 + **/ + + class TemplateHandler { + + var $compiled_path = './files/template_compiled/'; + + var $tpl_path = ''; + var $tpl_file = ''; + + // public string compile($tpl_path, $tpl_filename)/*{{{*/ + function compile($tpl_path, $tpl_filename) { + $this->tpl_path = $tpl_path; + + // 디버그를 위한 컴파일 시작 시간 저장 + if(__DEBUG__) $start = getMicroTime(); + + // 변수 체크 + if(substr($tpl_path,-1)!='/') $tpl_path .= '/'; + if(substr($tpl_filename,-5)!='.html') $tpl_filename .= '.html'; + + // tpl_file 변수 생성 + $tpl_file = $tpl_path.$tpl_filename; + + // tpl_file이 비어 있거나 해당 파일이 없으면 return + if(!$tpl_file || !file_exists($tpl_file)) return; + + $this->tpl_file = $tpl_file; + + // compiled된(or 될) 파일이름을 구함 + $compiled_tpl_file = $this->_getCompiledFileName($tpl_file); + + // 일단 컴파일 + $buff = $this->_compile($tpl_file, $compiled_tpl_file); + + if(__DEBUG__) { + $template_elapsed = getMicroTime() - $start; + $GLOBALS['__template_elapsed__'] += $template_elapsed; + } + + // Context와 compiled_tpl_file로 컨텐츠 생성 + $output = $this->_fetch($compiled_tpl_file, $buff); + + // 컴파일된 파일을 실행 + return $output; + }/*}}}*/ + + // private void _compile($tpl_file, $compiled_tpl_file)/*{{{*/ + // tpl_file이 컴파일이 되어 있는 것이 있는지 체크 + function _compile($tpl_file, $compiled_tpl_file) { + if(!file_exists($compiled_tpl_file)) return $this->_compileTplFile($tpl_file, $compiled_tpl_file); + + $source_ftime = filectime($tpl_file); + $target_ftime = filectime($compiled_tpl_file); + if($source_ftime>$target_ftime) return $this->_compileTplFile($tpl_file, $compiled_tpl_file); + }/*}}}*/ + + // private void _compileTplFile($tpl_file, $compiled_tpl_file)/*{{{*/ + // tpl_file을 compile + function _compileTplFile($tpl_file, $compiled_tpl_file) { + + // tpl 파일을 읽음 + $buff = FileHandler::readFile($tpl_file); + if(!$buff) return; + + // 변수를 변경 + $buff = preg_replace_callback('/\{[^@^ ]([^\}]+)\}/i', array($this, '_compileVarToContext'), $buff); + + // 이미지 태그 img의 src의 값이 ./ 로 시작하면 {$tpl_path}로 변경 + $buff = preg_replace_callback('!src=[\'"]{1}(.*?)[\'"]{1}!is', array($this, '_compileImgPath'), $buff); + + // 함수를 변경 + $buff = preg_replace_callback('/\{\@([^\}]+)\}/i', array($this, '_compileVarToFunc'), $buff); + + // 의 변경 + $buff = preg_replace_callback('!<\!--@(.*?)-->!is', array($this, '_compileFuncToCode'), $buff); + + // include 변경 + $buff = preg_replace_callback('!<\!--#include\(([^\)]*?)\)-->!is', array($this, '_compileIncludeToCode'), $buff); + + // import xml filter/ css/ js + $buff = preg_replace_callback('!<\!--%import\(\"([^\"]*?)\"\)-->!is', array($this, '_compileImportCode'), $buff); + + // 파일에 쓰기 전에 직접 호출되는 것을 방지 + $buff = sprintf('%s%s%s','',"\n",$buff); + + // 컴파일된 코드를 파일에 저장 + FileHandler::writeFile($compiled_tpl_file, $buff); + + return $buff; + }/*}}}*/ + + // private string _compileVarToContext($matches)/*{{{*/ + // {$와 } 안의 $... 변수를 Context::get(...) 으로 변경 + function _compileVarToContext($matches) { + $str = trim(substr($matches[0],1,strlen($matches[0])-2)); + return ']+)/i','$__Context->\\1', $str).');?>'; + }/*}}}*/ + + // private string _compileImgPath($matches)/*{{{*/ + // {$와 } 안의 $... 변수를 Context::get(...) 으로 변경 + function _compileImgPath($matches) { + $str1 = $matches[0]; + $str2 = $matches[1]; + $path = $str2; + if(!eregi("^\.\/(images|img)",$path)) return $str1; + + $path = 'tpl_path?>'.substr($path,2); + return str_replace($str2, $path, $str1); + }/*}}}*/ + + // private string _compileVarToFunc($matches)/*{{{*/ + // {@와 } 안의 @... 함수를 print func(..)로 변경 + function _compileVarToFunc($matches) { + return ']+)/i','$__Context->\\1', trim($matches[1])).');?>'; + }/*}}}*/ + + // private string _compileFuncToCode($matches)/*{{{*/ + // 사이의 구문을 php코드로 변경 + function _compileFuncToCode($matches) { + $code = trim($matches[1]); + if(!$code) return; + switch(strtolower($code)) { + case 'else' : + $output = '}else{'; + break; + case 'end' : + case 'endif' : + case 'endfor' : + case 'endforeach' : + $output = '}'; + break; + default : + if(substr($code,0,4)=='else') { + $code = '}'.$code; + } elseif(substr($code,0,7)=='foreach') { + $tmp_str = substr($code,8); + $tmp_arr = explode(' ', $tmp_str); + $var_name = $tmp_arr[0]; + if(substr($var_name,0,1)=='$') $prefix = sprintf('if(is_array($__Context->%s)) ', substr($var_name,1)); + else $prefix = sprintf('if(is_array(%s)) ', $var_name); + } + $output = preg_replace('/\$([a-zA-Z0-9\_\-]+)/i','$__Context->\\1', $code).'{'; + break; + } + + return sprintf('', $prefix, $output); + }/*}}}*/ + + // private string _compileIncludeToCode($matches)/*{{{*/ + // 를 변환 + function _compileIncludeToCode($matches) { + // include하려는 대상문자열에 변수가 있으면 변수 처리 + $arg = str_replace(array('"','\''), '', $matches[1]); + if(!$arg) return; + + $tmp_arr = explode("/", $arg); + for($i=0;$itpl_file), $arg); + + // 2단계로 root로부터 경로를 체크 + if(!file_exists($filename)) $filename = './'.$arg; + if(!file_exists($filename)) return; + + // path, filename으로 분리 + $tmp_arr = explode('/', $filename); + $filename = array_pop($tmp_arr); + $path = implode('/', $tmp_arr).'/'; + + // include 시도 + $output = sprintf( + 'compile(\'%s\',\'%s\');%s'. + '?>%s', + "\n", + "\n", + $path, + $filename, + "\n", + "\n" + ); + return $output; + }/*}}}*/ + + // private string _compileImportCode($matches)/*{{{*/ + // 의 확장자를 봐서 js filter/ css/ js 파일을 include하도록 수정 + function _compileImportCode($matches) { + // 현재 tpl 파일의 위치를 구해서 $base_path에 저장하여 적용하려는 xml file을 찾음 + $base_path = dirname($this->tpl_file).'/'; + $given_file = trim($matches[1]); + if(!$given_file) return; + $filename = sprintf("%s%s",$base_path, $given_file); + + // path와 파일이름을 구함 + $tmp_arr = explode("/",$filename); + $filename = array_pop($tmp_arr); + + $base_path = implode("/",$tmp_arr)."/"; + + // 확장자를 구함 + $tmp_arr = explode(".",$filename); + $ext = strtolower(array_pop($tmp_arr)); + + // 확장자에 따라서 파일 import를 별도로 + switch($ext) { + // xml js filter + case 'xml' : + // XmlJSFilter 클래스의 객체 생성후 js파일을 만들고 Context::addJsFile처리 + $output = sprintf( + 'compile();%s'. + '?>%s', + "\n", + "\n", + $base_path, + $filename, + "\n", + "\n", + "\n" + ); + break; + // css file + case 'css' : + $output = sprintf('', $base_path, $filename); + break; + // js file + case 'js' : + $output = sprintf('', $base_path, $filename); + break; + } + + return $output; + }/*}}}*/ + + // private string _getComliedFileName($tpl_file) /*{{{*/ + // $tpl_file로 compiled_tpl_file이름을 return + function _getCompiledFileName($tpl_file) { + return sprintf('%s%s.compiled.php',$this->compiled_path, md5($tpl_file)); + }/*}}}*/ + + // private string _fetch($compiled_tpl_file)/*{{{*/ + // ob_* 함수를 이용하여 fetch... + function _fetch($compiled_tpl_file, $buff = NULL) { + $__Context = &$GLOBALS['__Context__']; + + if($_SESSION['is_logged']) $__Context->logged_info->$_SESSION['logged_info']; + + // ob_start를 시킨후 컴파일된 tpl파일을 include하고 결과를 return + ob_start(); + // tpl파일을 compile하지 못할 경우 $buff로 넘어온 값을 eval시킴 (미설치시에나..) + if($buff) { + $eval_str = "?>".$buff; + eval($eval_str); + } else { + @include $compiled_tpl_file; + } + $output = ob_get_contents(); + ob_end_clean(); + + return $output; + }/*}}}*/ + + } +?> diff --git a/classes/xml/XmlJsFilter.class.php b/classes/xml/XmlJsFilter.class.php new file mode 100644 index 000000000..7a2e92f4b --- /dev/null +++ b/classes/xml/XmlJsFilter.class.php @@ -0,0 +1,158 @@ + + * @desc : filter xml문서를 해석하여 js파일로 만듬 + * filter xml은 tpl 파일과 같은 위치에 있어야 함 + * + * <-- 폼 항목의 체크 + * + * + * <-- 폼 항목을 조합하여 key=val 의 js array로 return, act는 필수 + * + * + * <-- 서버에 ajax로 전송하여 받을 결과값 + * <-- error이름의 결과값을 받겠다는 것 + * + * + * + * - field + * target = 폼 element의 이름 + * required = true/ false 꼭 있어야 하는지에 대한 체크 + * minlength, maxlength = 최소/최대 길이 + * filter = javascript로 체크하기 위한 체크 필터 + * email : email의 형식 ( aaa.aaa@aaa.com) + * userid : 영문+숫자+_, 첫 글자는 영문, 소문자 + * alpha : 영문값만 허용 + * number : 숫자만 허용 + * equalto = target , 현재 폼과 지정 target의 값이 동일해야 함 + * - parameter + * param = key : key를 이름으로 가지고 value의 값을 가지는 array 값 생성 + * value = target : target form element의 값을 가져옴 + * concat = str1,str2,target2... : 값들의 string 또는 form element value를 연결 + * - response + * name = key : return받을 결과값의 변수명 + **/ + + class XmlJsFilter { + var $compiled_path = './files/js_filter_compiled/'; + var $xml_file = NULL; + var $js_file = NULL; + + // public void XmlJsFilter($path, $xml_file)/*{{{*/ + function XmlJsFilter($path, $xml_file) { + $this->xml_file = sprintf("%s%s",$path, $xml_file); + $this->js_file = $this->_getCompiledFileName($this->xml_file); + }/*}}}*/ + + // public void compile()/*{{{*/ + // 원 xml파일과 compiled된js파일의 시간 비교 및 유무 비교등을 처리 + function compile() { + if(!file_exists($this->xml_file)) return; + if(!file_exists($this->js_file)) $this->_compile(); + if(filectime($this->xml_file)>filectime($this->js_file)) $this->_compile(); + $this->_compile(); + Context::addJsFile($this->js_file); + }/*}}}*/ + + // private void _compile()/*{{{*/ + // 실제 xml_file을 컴파일하여 js_file을 생성 + function _compile() { + global $lang; + + // xml 파일을 읽음 + $buff = FileHandler::readFile($this->xml_file); + + // xml parsing + $oXml = new XmlParser(); + $xml_obj = $oXml->parse($buff); + + // XmlJsFilter는 filter_id, field, parameter 3개의 데이터를 핸들링 + $filter_id = $xml_obj->filter->attrs->id; + $confirm_msg_code = $xml_obj->filter->attrs->confirm_msg_code; + $field_item = $xml_obj->filter->field->item; + $parameter_item = $xml_obj->filter->parameter->item; + $response_item = $xml_obj->filter->response->item; + + // 언어 입력을 위한 사용되는 필드 조사 + $target_list = array(); + + // js function 을 만들기 시작 + $js_doc = sprintf("function %s(fo_obj, callback_user_func) {\n", $filter_id); + $js_doc .= "\tvar oFilter = new XmlJsFilter(fo_obj, callback_user_func);\n"; + + // field, 즉 체크항목의 script 생성 + $field_cnt = count($field_item); + if($field_cnt) { + foreach($field_item as $key =>$field_obj) { + $attrs = $field_obj->attrs; + $target = trim($attrs->target); + if(!$target) continue; + $required = $attrs->required=='true'?'true':'false'; + $minlength = $attrs->minlength>0?$attrs->minlength:'0'; + $maxlength = $attrs->maxlength>0?$attrs->maxlength:'0'; + $equalto = trim($attrs->equalto); + $filter = $attrs->filter; + + $js_doc .= sprintf( + "\toFilter.addFieldItem(\"%s\",%s,%s,%s,\"%s\",\"%s\");\n", + $target, $required, $minlength, $maxlength, $equalto, $filter + ); + + if(!in_array($target, $target_list)) $target_list[] = $target; + } + } + + // 데이터를 만들기 위한 parameter script 생성 + $parameter_cnt = count($parameter_item); + if($parameter_cnt) { + foreach($parameter_item as $key =>$parameter_obj) { + $attrs = $parameter_obj->attrs; + $param = trim($attrs->param); + $target = trim($attrs->target); + if(!$param || !$target) continue; + $target = htmlentities($target,ENT_QUOTES); + $js_doc .= sprintf( + "\toFilter.addParameterItem(\"%s\",\"%s\");\n", + $param, $target + ); + if(!in_array($param, $target_list)) $target_list[] = $param; + } + } + + // response script 생성 + $response_cnt = count($response_item); + for($i=0;$i<$response_cnt;$i++) { + $attrs = $response_item[$i]->attrs; + $name = $attrs->name; + $js_doc .= sprintf("\toFilter.addResponseItem(\"%s\");\n", $name); + } + + if($confirm_msg_code) $js_doc .= sprintf("\treturn oFilter.proc(\"%s\");\n",str_replace('"','\"',$lang->{$confirm_msg_code})); + else $js_doc .= sprintf("\treturn oFilter.proc();\n"); + $js_doc .= "}\n"; + + // form 필드 lang 값을 기록 + $target_cnt = count($target_list); + for($i=0;$i<$target_cnt;$i++) { + $target = $target_list[$i]; + $js_doc .= sprintf("alertMsg[\"%s\"] = \"%s\"\n", $target, str_replace("\"","\\\"",$lang->{$target})); + } + + // 에러 메세지를 기록 + foreach($lang->filter as $key => $val) { + $js_doc .= sprintf("alertMsg[\"%s\"] = \"%s\";\n", $key, str_replace("\"","\\\"",$val)); + } + + // js파일 생성 + FileHandler::writeFile($this->js_file, $js_doc); + }/*}}}*/ + + // private string _getCompiledFileName($xml_file) /*{{{*/ + // $xml_file로 compiled_xml_file이름을 return + function _getCompiledFileName($xml_file) { + return sprintf('%s%s.%s.compiled.js',$this->compiled_path, md5($xml_file),Context::getLangType()); + }/*}}}*/ + } +?> diff --git a/classes/xml/XmlParser.class.php b/classes/xml/XmlParser.class.php new file mode 100644 index 000000000..cc95a3f00 --- /dev/null +++ b/classes/xml/XmlParser.class.php @@ -0,0 +1,111 @@ + + * @desc : xmlrpc를 해석하여 object로 return 하는 simple xml parser + **/ + + class XmlParser { + + var $oParser = NULL; + + var $input = NULL; + var $output = array(); + + var $lang = "en"; + + // public object loadXmlFile($filename)/*{{{*/ + function loadXmlFile($filename) { + if(!file_exists($filename)) return; + + $buff = FileHandler::readFile($filename); + + $oXmlParser = new XmlParser(); + return $oXmlParser->parse($buff); + }/*}}}*/ + + // public void parse($input)/*{{{*/ + function parse($input = '') { + $this->lang = Context::getLangType(); + + $this->input = $input?$input:$GLOBALS['HTTP_RAW_POST_DATA']; + + // 지원언어 종류를 뽑음 + preg_match_all("/xml:lang=\"([^\"].+)\"/i", $this->input, $matches); + + // xml:lang이 쓰였을 경우 지원하는 언어종류를 뽑음 + if(count($matches[1]) && $supported_lang = array_unique($matches[1])) { + // supported_lang에 현재 접속자의 lang이 없으면 en이 있는지 확인하여 en이 있으면 en을 기본, 아니면 첫번째것을.. + if(!in_array($this->lang, $supported_lang)) { + if(in_array('en', $supported_lang)) { + $this->lang = 'en'; + } else { + $this->lang = array_shift($supported_lang); + } + } + // 특별한 언어가 지정되지 않았다면 언어체크를 하지 않음 + } else { + unset($this->lang); + } + + + $this->oParser = xml_parser_create(); + + xml_set_object($this->oParser, $this); + xml_set_element_handler($this->oParser, "_tagOpen", "_tagClosed"); + xml_set_character_data_handler($this->oParser, "_tagBody"); + + xml_parse($this->oParser, $this->input); + xml_parser_free($this->oParser); + + if(!count($this->output)) return; + return array_shift($this->output); + }/*}}}*/ + + // private void _tagOpen($parser, $node_name, $attrs)/*{{{*/ + function _tagOpen($parser, $node_name, $attrs) { + $obj->node_name = strtolower($node_name); + $obj->attrs = $this->_arrToObj($attrs); + + array_push($this->output, $obj); + }/*}}}*/ + + // private void _tagBody($parser, $body)/*{{{*/ + function _tagBody($parser, $body) { + if(!trim($body)) return; + $this->output[count($this->output)-1]->body .= $body; + }/*}}}*/ + + // private void _tagClosed($parser, $node_name)/*{{{*/ + function _tagClosed($parser, $node_name) { + $node_name = strtolower($node_name); + $cur_obj = array_pop($this->output); + $parent_obj = &$this->output[count($this->output)-1]; + if($this->lang&&$cur_obj->attrs->{'xml:lang'}&&$cur_obj->attrs->{'xml:lang'}!=$this->lang) return; + if($this->lang&&$parent_obj->{$node_name}->attrs->{'xml:lang'}&&$parent_obj->{$node_name}->attrs->{'xml:lang'}!=$this->lang) return; + + if($parent_obj->{$node_name}) { + $tmp_obj = $parent_obj->{$node_name}; + if(is_array($tmp_obj)) { + array_push($parent_obj->{$node_name}, $cur_obj); + } else { + $parent_obj->{$node_name} = array(); + array_push($parent_obj->{$node_name}, $tmp_obj); + array_push($parent_obj->{$node_name}, $cur_obj); + } + } else { + $parent_obj->{$node_name} = $cur_obj; + } + }/*}}}*/ + + // private void _arrToObj($arr)/*{{{*/ + function _arrToObj($arr) { + if(!count($arr)) return; + foreach($arr as $key => $val) { + $key = strtolower($key); + $output->{$key} = $val; + } + return $output; + }/*}}}*/ + } +?> diff --git a/classes/xml/XmlQueryParser.class.php b/classes/xml/XmlQueryParser.class.php new file mode 100644 index 000000000..5fc01051f --- /dev/null +++ b/classes/xml/XmlQueryParser.class.php @@ -0,0 +1,340 @@ + + * @desc : query xml을 파싱하여 결과를 return + **/ + + class XmlQueryParser { + + // 조건문에서 조건을 등호로 표시하는 변수 + var $cond_operation = array( + 'equal' => '=', + 'more' => '>=', + 'excess' => '>', + 'less' => '<=', + 'below' => '<', + 'notequal' => '!=', + 'notnull' => 'is not null', + 'null' => 'is null', + ); + + // private string parse($query_id, $xml_file, $cache_file)/*{{{*/ + // 쿼리 파일을 찾아서 파싱하고 cacheing한다 + function parse($query_id, $xml_file, $cache_file) { + // query xml 파일을 찾아서 파싱, 결과가 없으면 return + $buff = FileHandler::readFile($xml_file); + $oXml = new XmlParser(); + $xml_obj = $oXml->parse($buff); + if(!$xml_obj) return; + + // 쿼리 스크립트를 만들때 필요한 변수들 + $filter_script = $notnull_script = $column_script = $default_script = ''; + + // insert, update, delete, select등의 action + $action = strtolower($xml_obj->query->attrs->action); + if(!$action) return; + + // 테이블 정리 (배열코드로 변환) + $tables = $this->_getTablesScript($xml_obj); + + // 컬럼 정리 + $column_script = $this->_getColumnsScript($xml_obj, $default_script, $notnull_script, $filter_script, $action); + + // 조건절 정리 + $condition_script = $this->_getConditionScript($xml_obj, $default_script, $notnull_script, $filter_script); + + // group 정리 + $group_script = $this->_getGroupScript($xml_obj); + + // 네비게이션 정리 + $navigation_script = $this->_getNavigationScript($xml_obj); + + // 캐쉬 내용 작성 + $buff = + sprintf( + '', + $query_id, + $action, + $tables, + $default_script, + $column_script, + $notnull_script, + $filter_script, + $condition_script, + $navigation_script, + $group_script + ); + + // 저장 + FileHandler::writeFile($cache_file, $buff); + }/*}}}*/ + + // private string _getDefaultCode($name, $value)/*{{{*/ + function _getDefaultCode($name, $value) { + if(!$value) return; + if(substr($value, -1)!=')') return sprintf('if(!$args->%s) $args->%s = \'%s\';'."\n", $name, $name, $value); + + $str_pos = strpos($value, '('); + $func_name = substr($value, 0, $str_pos); + $args = substr($value, $str_pos+1, strlen($value)-1); + + switch($func_name) { + case 'ipaddress' : + $val = '\''.$_SERVER['REMOTE_ADDR'].'\''; + break; + case 'unixtime' : + $val = 'time()'; + break; + case 'curdate' : + $val = 'date("YmdHis")'; + break; + case 'sequence' : + $val = '$this->getNextSequence()'; + break; + case 'plus' : + $args = abs($args); + $val = sprintf('\'%s+%d\'', $name, $args); + $pass_quotes = true; + break; + case 'minus' : + $args = abs($args); + $val = sprintf('\'%s-%d\'', $name, $args); + $pass_quotes = true; + break; + } + + $output = sprintf('if(!$args->%s) $args->%s = %s;'."\n", $name, $name, $val); + if($pass_quotes) $output .= sprintf('$pass_quotes[] = \'%s\';'."\n",$name); + return $output; + }/*}}}*/ + + // private string _getFilterCode($key, $type, $minlength, $maxlength, $var='column')/*{{{*/ + function _getFilterCode($key, $type, $minlength, $maxlength, $var='column', $notnull='') { + if(!$type||!$minlength||!$maxlength) return; + if(!$notnull) $notnull_code = sprintf('if($%s->%s) ', $var, $key); + return + sprintf('unset($output); %s$output = $this->_checkFilter(\'%s\', $%s->%s, \'%s\', \'%d\', \'%d\'); if(!$output->toBool()) return $output;'."\n", + $notnull_code, + $key, + $var, + $key, + $type, + (int)$minlength, + (int)$maxlength + ); + }/*}}}*/ + + // private string _getNotNullCode($name)/*{{{*/ + function _getNotNullCode($name, $var='column') { + return + sprintf('if(!$%s->%s) return new Output(-1, sprintf($lang->filter->isnull, $lang->%s?$lang->%s:\'%s\'));'."\n", + $var, + $name, + $name, + $name, + $name + ); + }/*}}}*/ + + // private string _getTablesScript($xml_obj) /*{{{*/ + function _getTablesScript($xml_obj) { + $obj_tables = $xml_obj->query->tables->table; + if(!is_array($obj_tables)) $obj_tables = array('', $obj_tables); + + foreach($obj_tables as $table_info) { + $name = trim($table_info->attrs->name); + if(!$name) continue; + $alias = trim($table_info->attrs->alias); + if(!$alias) $alias = $name; + $table_list[] = sprintf('\'%s\'=>\'%s\'', $name, $alias); + } + return implode(",",$table_list); + }/*}}}*/ + + // private string _getColumnsScript($xml_obj, &$default_script, &$notnull_script, &$filter_script, $action)/*{{{*/ + function _getColumnsScript($xml_obj, &$default_script, &$notnull_script, &$filter_script, $action) { + $obj_columns = $xml_obj->query->columns->column; + if(!is_array($obj_columns)) $obj_columns = array('', $obj_columns); + + foreach($obj_columns as $column_info) { + $name = trim($column_info->attrs->name); + if(!$name || $name == '*') continue; + + $var = trim($column_info->attrs->var); + $alias = trim($column_info->attrs->alias); + if(!$alias) $alias = $name; + $default = trim($column_info->attrs->default); + $notnull = trim($column_info->attrs->notnull); + + $filter_type = trim($column_info->attrs->filter); + $minlength = (int)trim($column_info->attrs->minlength); + $maxlength = (int)trim($column_info->attrs->maxlength); + + $column_script .= sprintf('$column->%s = $args->%s;'."\n", $alias, $var?$var:$alias); + $invert_columns[] = sprintf('\'%s\'=>\'%s\'', $alias, $name); + + $default_script .= $this->_getDefaultCode($alias, $default); + if($action != 'select') { + if($filter_type) $filter_script .= $this->_getFilterCode($alias, $filter_type, $minlength, $maxlength, 'column', $notnull); + if($notnull) $notnull_script .= $this->_getNotNullCode($alias); + } + } + if(is_array($invert_columns)) $column_script .= sprintf('$invert_columns = array(%s);'."\n", implode(',',$invert_columns)); + return $column_script; + }/*}}}*/ + + // private string _getConditionScript($xml_obj, &$default_script, &$notnull_script, &$filter_script)/*{{{*/ + function _getConditionScript($xml_obj, &$default_script, &$notnull_script, &$filter_script) { + $cond_idx = 0; + + $obj_conditions = $xml_obj->query->conditions->condition; + + $condition_script = $condition = $this->_getConditionQuery($cond_idx++, $obj_conditions, NULL, $notnull_script, $filter_script); + + $obj_groups = $xml_obj->query->conditions->group; + if(!is_array($obj_groups)) $obj_groups = array('', $obj_groups); + + foreach($obj_groups as $obj_group) { + $group_pipe = $obj_group->attrs->pipe; + if(!$group_pipe) continue; + $buff = $this->_getConditionQuery($cond_idx++, $obj_group->condition, $group_pipe, $notnull_script, $filter_script); + $condition_script .= $buff; + } + + $condition_script .= '$condition = $this->_combineCondition($cond_group, $group_pipe);'."\n"; + return $condition_script; + }/*}}}*/ + + // private string _getConditionQuery($cond_idx, $obj, $group_pipe, &$notnull_script, &$filter_script) /*{{{*/ + // 조건문의 쿼리를 만들어 줌 + function _getConditionQuery($cond_idx, $obj, $group_pipe, &$notnull_script, &$filter_script) { + if(!is_array($obj)) $obj = array('', $obj); + + $idx = 0; + foreach($obj as $obj_cond) { + $operation = $obj_cond->attrs->operation; + if(!$operation) continue; + + $column = $obj_cond->attrs->column; + $var = $obj_cond->attrs->var; + $filter = $obj_cond->attrs->filter; + $notnull = $obj_cond->attrs->notnull; + $pipe = $obj_cond->attrs->pipe; + if(!$pipe) $pipe = 'and'; + $default = $obj_cond->attrs->default; + + // 비교 대상이 다른 혹은 같은 테이블의 column일 경우 + if(eregi("\.", $var)) { + switch($operation) { + case 'in' : + $buff = sprintf('%s in (%s)', $column, $var); + break; + default : + $operation = $this->cond_operation[$operation]; + if(!$operation) $operation = 'and'; + $buff = sprintf('%s %s %s', $column, $operation, $var); + break; + } + $condition_script .= sprintf('$cond_group[%d][][\'%s\'] = \'%s\';'."\n",$cond_idx, $pipe, $buff); + + // 입력받을 변수일 경우 + } else { + switch($operation) { + case 'like' : + $buff = sprintf('sprintf("%s like \'%%%%%%s%%%%\' ", $this->addQuotes($args->%s))', $column, $var); + break; + case 'like_prefix' : + $buff = sprintf('sprintf("%s like \'%%s%%%%\' ", $this->addQuotes($args->%s))', $column, $var); + break; + case 'in' : + $buff = sprintf('sprintf("%s in (%%s) ", $this->addQuotes($args->%s))', $column, $var); + break; + case 'notnull' : + case 'null' : + $operation = $this->cond_operation[$operation]; + unset($var); + $buff = sprintf('"%s %s "', $column, $operation); + break; + default : + $operation = $this->cond_operation[$operation]; + if($default) $buff = sprintf('sprintf("%s %s \'%%s\' ", $args->%s?$this->addQuotes($args->%s):\'%s\')', $column, $operation, $var?$var:$column, $var?$var:$column, $default); + else $buff = sprintf('sprintf("%s %s \'%%s\' ", $this->addQuotes($args->%s))', $column, $operation, $var?$var:$column); + break; + } + $buff = sprintf('$cond_group[%d][][\'%s\'] = %s;'."\n",$cond_idx, $pipe, $buff); + + if(!$notnull && $var) $buff = sprintf('if($args->%s) ', $var).$buff; + $condition_script .= $buff; + if($notnull) $notnull_script .= $this->_getNotNullCode($var?$var:$column, 'args'); + if($filter) $filter_script .= $this->_getFilterCode($var, $filter, 0, 0, 'args', $notnull); + } + } + $condition_script .= sprintf('$group_pipe[%d] = \'%s\';'."\n", $cond_idx, $group_pipe); + return $condition_script; + }/*}}}*/ + + // private string _getGroupScript($xml_obj)/*{{{*/ + function _getGroupScript($xml_obj) { + $group_list = $xml_obj->query->groups->group; + if(!$group_list) return; + if(!is_array($group_list)) $group_list = array($group_list); + for($i=0;$iattrs->column); + if(!$column) continue; + $group_column_list[] = $column; + } + if(count($group_column_list)) { + return ' group by '.implode(" , ", $group_column_list); + } + }/*}}}*/ + + // private string _getNavigationScript($xml_obj) /*{{{*/ + function _getNavigationScript($xml_obj) { + $obj_navigation = $xml_obj->query->navigation; + if(!$obj_navigation) return; + + $obj_index = $obj_navigation->index->attrs; + $index_list = array(); + if(!is_array($obj_index)) $obj_index = array('', $obj_index); + foreach($obj_index as $index_info) { + $var = trim($index_info->var); + if(!$var) continue; + $default = trim($index_info->default); + $order = trim($index_info->order); + if(!$order) $order = 'asc'; + + $navigation_script .= sprintf('$navigation->index[] = array($args->%s?$args->%s:\'%s\', \'%s\');'."\n", $var, $var, $default, $order); + } + + $obj_list_count = $obj_navigation->list_count->attrs; + $count_var = $obj_list_count->var; + $count_default = $obj_list_count->default; + if($count_var) $navigation_script .= sprintf('$navigation->list_count = $args->%s?$args->%s%s;'."\n", $count_var, $count_var, $count_default?':'.$count_default:''); + + $obj_page_count = $obj_navigation->page_count->attrs; + $count_var = $obj_page_count->var; + $count_default = $obj_page_count->default; + if($count_var) $navigation_script .= sprintf('$navigation->page_count = $args->%s?$args->%s%s;'."\n", $count_var, $count_var, $count_default?':'.$count_default:''); + + $obj_page = $obj_navigation->page->attrs; + $page_var = $obj_page->var; + $page_default = $obj_page->default; + if($page_var) $navigation_script .= sprintf('$navigation->page = $args->%s?$args->%s%s;'."\n", $page_var, $page_var, $page_default?':'.$page_default:''); + return $navigation_script; + }/*}}}*/ + } +?> diff --git a/common/css/default.css b/common/css/default.css new file mode 100644 index 000000000..0273c3871 --- /dev/null +++ b/common/css/default.css @@ -0,0 +1,42 @@ +#waitingforserverresponse { + display:inline; + border:2px solid #444444; + background-color:#FFFFFF; + padding:15px 20px 13px 20px; + font-weight:bold; + font-size:9pt; + color:#444444; + top:40px; + left:40px; + position:absolute; + z-index:100; + visibility:hidden; +} + +A.bold { + font-weight:bold; +} + +A.editor_blue_text:link { color: #17B1B7; text-decoration:none; border-bottom:2px solid #17B1B7;} +A.editor_blue_text:visited { color: #17B1B7; text-decoration:none; border-bottom:2px solid #17B1B7;} +A.editor_blue_text:active { color: #17B1B7; text-decoration:none; border-bottom:2px solid #17B1B7;} +A.editor_blue_text:hover { color: #17B1B7; text-decoration:none; border-bottom:2px solid #17B1B7;} + +A.editor_red_text:link { color: #B71717; text-decoration:none; border-bottom:2px solid #B71717; } +A.editor_red_text:visited { color: #B71717; text-decoration:none; border-bottom:2px solid #B71717;} +A.editor_red_text:active { color: #B71717; text-decoration:none; border-bottom:2px solid #B71717;} +A.editor_red_text:hover { color: #B71717; text-decoration:none; border-bottom:2px solid #B71717;} + +A.editor_yellow_text:link { color: #6A8308; text-decoration:none; border-bottom:2px solid #6A8308; } +A.editor_yellow_text:visited { color: #6A8308; text-decoration:none; border-bottom:2px solid #6A8308;} +A.editor_yellow_text:active { color: #6A8308; text-decoration:none; border-bottom:2px solid #6A8308;} +A.editor_yellow_text:hover { color: #6A8308; text-decoration:none; border-bottom:2px solid #6A8308;} + +A.editor_green_text:link { color: #08830B; text-decoration:none; border-bottom:2px solid #08830B;} +A.editor_green_text:visited { color: #08830B; text-decoration:none; border-bottom:2px solid #08830B;} +A.editor_green_text:active { color: #08830B; text-decoration:none; border-bottom:2px solid #08830B;} +A.editor_green_text:hover { color: #08830B; text-decoration:none; border-bottom:2px solid #08830B;} + +.folder_opener { display: block; } +.folder_closer { display: none; } +.folder_area { display: none; } diff --git a/common/js/common.js b/common/js/common.js new file mode 100644 index 000000000..495fececb --- /dev/null +++ b/common/js/common.js @@ -0,0 +1,122 @@ +/** + * 몇가지 유용한 & 기본적으로 자주 사용되는 자바스크립트 함수들 모음 + **/ + +// string prototype으로 trim 함수 추가 +String.prototype.trim = function() {/*{{{*/ + return this.replace(/(^\s*)|(\s*$)/g, ""); +}/*}}}*/ + +// 주어진 인자가 하나라도 defined되어 있지 않으면 false return +function isDef() {/*{{{*/ + for(var i=0; i"+ + "document.writeln(\""+ + ""+ + ""+ + ""+ + ""+ + "<\/object>"+ + "\");"+ + ""; + break; + default : + html = ""+ + ""; + break; + } + + return html; +}/*}}}*/ + +// 화면내에서 이미지 리사이즈 및 클릭할 수 있도록 +function resizeImageContents() {/*{{{*/ + var objs = xGetElementsByTagName('img'); + for(var i in objs) { + var obj = objs[i]; + var parent = xParent(obj); + if(!obj||!parent) continue; + + var parent_width = xWidth(parent); + var obj_width = xWidth(obj); + if(parent_width>=obj_width) continue; + + obj.style.cursor = 'pointer'; + obj.source_width = obj_width; + obj.source_height = xHeight(obj); + xWidth(obj, xWidth(parent)-1); + + xAddEventListener(obj,'click', resizeImagePopup); + } +}/*}}}*/ +xAddEventListener(window, 'load', resizeImageContents); + +function resizeImagePopup(evt) {/*{{{*/ + var e = new xEvent(evt); + if(!e.target.src) return; + var obj = e.target; + var scrollbars = "no"; + var resizable = "no"; + + var width = obj.source_width; + if(width>screen.availWidth) { + width = screen.availWidth-50; + scrollbars = "yes"; + resizable = "yes"; + } + var height = obj.source_height; + if(height>screen.availHeight) { + height = screen.availHeight-50; + scrollbars = "yes"; + resizable = "yes"; + } + var popup = window.open(e.target.src,"_imagePopup","width="+width+",height="+height+",top=1,left=1,resizable="+resizable+",toolbars=no,scrollbars="+resizable); + if(popup) popup.focus(); +}/*}}}*/ + +// 에디터에서 사용하는 내용 여닫는 코드 (고정) +function svc_folder_open(id) {/*{{{*/ + var open_text_obj = xGetElementById("_folder_open_"+id); + var close_text_obj = xGetElementById("_folder_close_"+id); + var folder_obj = xGetElementById("_folder_"+id); + open_text_obj.style.display = "none"; + close_text_obj.style.display = "block"; + folder_obj.style.display = "block"; +}/*}}}*/ + +function svc_folder_close(id) {/*{{{*/ + var open_text_obj = xGetElementById("_folder_open_"+id); + var close_text_obj = xGetElementById("_folder_close_"+id); + var folder_obj = xGetElementById("_folder_"+id); + open_text_obj.style.display = "block"; + close_text_obj.style.display = "none"; + folder_obj.style.display = "none"; +}/*}}}*/ diff --git a/common/js/x.js b/common/js/x.js new file mode 100644 index 000000000..fbc5ae13a --- /dev/null +++ b/common/js/x.js @@ -0,0 +1,633 @@ +/* x.js compiled from X 4.0 with XC 0.27b. + * Distributed by GNU LGPL. For copyrights, license, documentation and more visit Cross-Browser.com + * Copyright 2001-2005 Michael Foster (Cross-Browser.com) + */ + +var xOp7Up,xOp6Dn,xIE4Up,xIE4,xIE5,xIE6,xNN4,xUA=navigator.userAgent.toLowerCase(); +if(window.opera){ + var i=xUA.indexOf('opera'); + if(i!=-1){ + var v=parseInt(xUA.charAt(i+6)); + xOp7Up=v>=7; + xOp6Dn=v<7; + } +} +else if(navigator.vendor!='KDE' && document.all && xUA.indexOf('msie')!=-1){ + xIE4Up=parseFloat(navigator.appVersion)>=4; + xIE4=xUA.indexOf('msie 4')!=-1; + xIE5=xUA.indexOf('msie 5')!=-1; + xIE6=xUA.indexOf('msie 6')!=-1; +} +else if(document.layers){xNN4=true;} +xMac=xUA.indexOf('mac')!=-1; + +// (element, event(without 'on'), event listener(function name)[, caption]) +function xAddEventListener(e,eT,eL,cap) +{ + if(!(e=xGetElementById(e))) return; + eT=eT.toLowerCase(); + if((!xIE4Up && !xOp7Up) && e==window) { + if(eT=='resize') { window.xPCW=xClientWidth(); window.xPCH=xClientHeight(); window.xREL=eL; xResizeEvent(); return; } + if(eT=='scroll') { window.xPSL=xScrollLeft(); window.xPST=xScrollTop(); window.xSEL=eL; xScrollEvent(); return; } + } + var eh='e.on'+eT+'=eL'; + if(e.addEventListener) e.addEventListener(eT,eL,cap); + else if(e.attachEvent) e.attachEvent('on'+eT,eL); + else eval(eh); +} +// called only from the above +function xResizeEvent() +{ + if (window.xREL) setTimeout('xResizeEvent()', 250); + var cw = xClientWidth(), ch = xClientHeight(); + if (window.xPCW != cw || window.xPCH != ch) { window.xPCW = cw; window.xPCH = ch; if (window.xREL) window.xREL(); } +} + +function xScrollEvent() +{ + if (window.xSEL) setTimeout('xScrollEvent()', 250); + var sl = xScrollLeft(), st = xScrollTop(); + if (window.xPSL != sl || window.xPST != st) { window.xPSL = sl; window.xPST = st; if (window.xSEL) window.xSEL(); } +} + +function xAppendChild(oParent, oChild) +{ + if (oParent.appendChild) return oParent.appendChild(oChild); + else return null; +} + +function xClientHeight() +{ + var h=0; + if(xOp6Dn) h=window.innerHeight; + else if(document.compatMode == 'CSS1Compat' && !window.opera && document.documentElement && document.documentElement.clientHeight) + h=document.documentElement.clientHeight; + else if(document.body && document.body.clientHeight) + h=document.body.clientHeight; + else if(xDef(window.innerWidth,window.innerHeight,document.width)) { + h=window.innerHeight; + if(document.width>window.innerWidth) h-=16; + } + return h; +} + +function xClientWidth() +{ + var w=0; + if(xOp6Dn) w=window.innerWidth; + else if(document.compatMode == 'CSS1Compat' && !window.opera && document.documentElement && document.documentElement.clientWidth) + w=document.documentElement.clientWidth; + else if(document.body && document.body.clientWidth) + w=document.body.clientWidth; + else if(xDef(window.innerWidth,window.innerHeight,document.height)) { + w=window.innerWidth; + if(document.height>window.innerHeight) w-=16; + } + return w; +} + +function xCreateElement(sTag) +{ + if (document.createElement) return document.createElement(sTag); + else return null; +} + +function xDef() +{ + for(var i=0; i 0) { + var offset = document.cookie.indexOf(search); + if (offset != -1) { + offset += search.length; + var end = document.cookie.indexOf(";", offset); + if (end == -1) end = document.cookie.length; + value = unescape(document.cookie.substring(offset, end)); + } + } + return value; +} + +function xGetElementById(e) +{ + if(typeof(e)!='string') return e; + if(document.getElementById) e=document.getElementById(e); + else if(document.all) e=document.all[e]; + else e=null; + return e; +} + +function xGetElementsByAttribute(sTag, sAtt, sRE, fn) +{ + var a, list, found = new Array(), re = new RegExp(sRE, 'i'); + list = xGetElementsByTagName(sTag); + for (var i = 0; i < list.length; ++i) { + a = list[i].getAttribute(sAtt); + if (!a) {a = list[i][sAtt];} + if (typeof(a)=='string' && a.search(re) != -1) { + found[found.length] = list[i]; + if (fn) fn(list[i]); + } + } + return found; +} + +function xGetElementsByClassName(c,p,t,f) +{ + var found = new Array(); + var re = new RegExp('\\b'+c+'\\b', 'i'); + var list = xGetElementsByTagName(t, p); + for (var i = 0; i < list.length; ++i) { + if (list[i].className && list[i].className.search(re) != -1) { + found[found.length] = list[i]; + if (f) f(list[i]); + } + } + return found; +} + +function xGetElementsByTagName(t,p) +{ + var list = null; + t = t || '*'; + p = p || document; + if (xIE4 || xIE5) { + if (t == '*') list = p.all; + else list = p.all.tags(t); + } + else if (p.getElementsByTagName) list = p.getElementsByTagName(t); + return list || new Array(); +} + +function xGetURLArguments() +{ + var idx = location.href.indexOf('?'); + var params = new Array(); + if (idx != -1) { + var pairs = location.href.substring(idx+1, location.href.length).split('&'); + for (var i=0; i=0) { + var pt=0,pb=0,bt=0,bb=0; + if (document.compatMode=='CSS1Compat') { + var gcs = xGetComputedStyle; + pt=gcs(e,'padding-top',1); + if (pt !== null) { + pb=gcs(e,'padding-bottom',1); + bt=gcs(e,'border-top-width',1); + bb=gcs(e,'border-bottom-width',1); + } + // Should we try this as a last resort? + // At this point getComputedStyle and currentStyle do not exist. + else if(xDef(e.offsetHeight,e.style.height)){ + e.style.height=h+'px'; + pt=e.offsetHeight-h; + } + } + h-=(pt+pb+bt+bb); + if(isNaN(h)||h<0) return; + else e.style.height=h+'px'; + } + h=e.offsetHeight; + } + else if(css && xDef(e.style.pixelHeight)) { + if(h>=0) e.style.pixelHeight=h; + h=e.style.pixelHeight; + } + return h; +} + +function xHex(n, digits, prefix) +{ + var p = '', n = Math.ceil(n); + if (prefix) p = prefix; + n = n.toString(16); + for (var i=0; i < digits - n.length; ++i) { + p += '0'; + } + return p + n; +} + +function xHide(e){return xVisibility(e,0);} + +function xInnerHtml(e,h) +{ + if(!(e=xGetElementById(e)) || !xStr(e.innerHTML)) return null; + var s = e.innerHTML; + if (xStr(h)) {e.innerHTML = h;} + return s; +} + +function xLeft(e, iX) +{ + if(!(e=xGetElementById(e))) return 0; + var css=xDef(e.style); + if (css && xStr(e.style.left)) { + if(xNum(iX)) e.style.left=iX+'px'; + else { + iX=parseInt(e.style.left); + if(isNaN(iX)) iX=0; + } + } + else if(css && xDef(e.style.pixelLeft)) { + if(xNum(iX)) e.style.pixelLeft=iX; + else iX=e.style.pixelLeft; + } + return iX; +} + +function xMoveTo(e,x,y) +{ + xLeft(e,x); + xTop(e,y); +} + +function xName(e) +{ + if (!e) return e; + else if (e.id && e.id != "") return e.id; + else if (e.name && e.name != "") return e.name; + else if (e.nodeName && e.nodeName != "") return e.nodeName; + else if (e.tagName && e.tagName != "") return e.tagName; + else return e; +} + +function xNextSib(e,t) +{ + var s = e ? e.nextSibling : null; + if (t) while (s && s.nodeName != t) { s = s.nextSibling; } + else while (s && s.nodeType != 1) { s = s.nextSibling; } + return s; +} + +function xNum() +{ + for(var i=0; i=0) { + var pl=0,pr=0,bl=0,br=0; + if (document.compatMode=='CSS1Compat') { + var gcs = xGetComputedStyle; + pl=gcs(e,'padding-left',1); + if (pl !== null) { + pr=gcs(e,'padding-right',1); + bl=gcs(e,'border-left-width',1); + br=gcs(e,'border-right-width',1); + } + // Should we try this as a last resort? + // At this point getComputedStyle and currentStyle do not exist. + else if(xDef(e.offsetWidth,e.style.width)){ + e.style.width=w+'px'; + pl=e.offsetWidth-w; + } + } + w-=(pl+pr+bl+br); + if(isNaN(w)||w<0) return; + else e.style.width=w+'px'; + } + w=e.offsetWidth; + } + else if(css && xDef(e.style.pixelWidth)) { + if(w>=0) e.style.pixelWidth=w; + w=e.style.pixelWidth; + } + return w; +} + +function xZIndex(e,uZ) +{ + if(!(e=xGetElementById(e))) return 0; + if(e.style && xDef(e.style.zIndex)) { + if(xNum(uZ)) e.style.zIndex=uZ; + uZ=parseInt(e.style.zIndex); + } + return uZ; +} + +function xStopPropagation(evt) +{ + if (evt && evt.stopPropagation) evt.stopPropagation(); + else if (window.event) window.event.cancelBubble = true; +} + diff --git a/common/js/xml_handler.js b/common/js/xml_handler.js new file mode 100644 index 000000000..668765c5e --- /dev/null +++ b/common/js/xml_handler.js @@ -0,0 +1,136 @@ +/** + * @file : common/js/xml_handler.js + * @author : zero + * @desc : ajax 사용을 위한 기본 js + **/ + +// xml handler을 이용하는 user function +function exec_xml(method_name, act, params, callback_func, response_tags, callback_func_arg) { + var oXml = new xml_handler(); + oXml.reset(); + oXml.setMethod(method_name); + oXml.addParam('act', act); + for(var key in params) { + var val = params[key]; + oXml.addParam(key, val); + } + + var waiting_obj = document.getElementById('waitingforserverresponse'); + waiting_obj.style.visibility = 'visible'; + oXml.request(xml_response_filter, oXml, callback_func, response_tags, callback_func_arg); +} + +// 결과 처리 후 callback_func에 넘겨줌 +function xml_response_filter(oXml, callback_func, response_tags, callback_func_arg) { + var xmlDoc = oXml.getResponseXml(); + if(!xmlDoc) return; + + var waiting_obj = document.getElementById('waitingforserverresponse'); + waiting_obj.style.visibility = 'hidden'; + var ret_obj = oXml.toZMsgObject(xmlDoc, response_tags); + if(ret_obj['error']!=0) { + alert(ret_obj['message']); + return; + } + + callback_func(ret_obj, response_tags, callback_func_arg); +} + +// xml handler +function xml_handler() { + this.obj_xmlHttp = null; + this.method_name = null; + if(location.href.indexOf('admin.php')>0) this.xml_path = "./admin.php"; + else this.xml_path = "./index.php"; + + this.params = new Array(); + + this.reset = xml_handlerReset; + this.getXmlHttp = zGetXmlHttp; + this.request = xml_handlerRequest; + this.setPath = xml_handlerSetPath; + this.setMethod = xml_handlerSetMethod; + this.addParam = xml_handlerAddParam; + this.getResponseXml = xml_handlerGetResponseXML; + this.toZMsgObject = xml_handlerToZMsgObject; + + this.obj_xmlHttp = this.getXmlHttp(); +} + +function zGetXmlHttp() { + if (window.XMLHttpRequest) return new XMLHttpRequest(); + else if (window.ActiveXObject) { + try { + return new ActiveXObject("Msxml2.XMLHTTP"); + } catch (e) { + return new ActiveXObject("Microsoft.XMLHTTP"); + } + } + return null; +} + +function xml_handlerRequest(callBackFunc, xmlObj, callBackFunc2, response_tags, callback_func_arg) { + + var rd = ""; + rd += "\n" + + "\n" + + ""+this.method_name+"\n" + + "\n" + + for (var key in this.params) { + var val = this.params[key]; + rd += "<"+key+">\n"; + } + + rd += "\n" + + "\n"; + if(this.obj_xmlHttp.readyState!=0) { + this.obj_xmlHttp.abort(); + this.obj_xmlHttp = this.getXmlHttp(); + } + this.obj_xmlHttp.onreadystatechange = function () {callBackFunc(xmlObj, callBackFunc2, response_tags, callback_func_arg)}; + this.obj_xmlHttp.open('POST', this.xml_path, true); + this.obj_xmlHttp.send(rd); +} + +function xml_handlerSetPath(path) { + this.xml_path = "./"+path; +} + +function xml_handlerSetMethod(method_name) { + this.method_name = method_name; +} + +function xml_handlerReset() { + this.obj_xmlHttp = this.getXmlHttp(); + this.params = new Array(); +} + +function xml_handlerAddParam(key, val) { + this.params[key] = val; +} + +function xml_handlerGetResponseXML() { + if(this.obj_xmlHttp && this.obj_xmlHttp.readyState == 4 && isDef(this.obj_xmlHttp.responseXML)) { + var xmlDoc = this.obj_xmlHttp.responseXML; + this.reset(); + return xmlDoc; + } + return null; +} + +function xml_handlerToZMsgObject(xmlDoc, tags) { + if(!xmlDoc) return null; + if(!tags) { + tags = new Array('error','message'); + } + var obj_ret = new Array(); + for(var i=0; i + * @desc : xml filter에서 사용될 js + **/ + +var alertMsg = new Array(); + +// filtering +function XmlJsFilter(form_object, callback_user_func) { + + this.fo_obj = null; + this.user_func = null; + this.field = new Array(); + this.parameter = new Array(); + this.response = new Array(); + + this.fo_obj = form_object; + this.user_func = callback_user_func; + + this.addFieldItem = XmlJsFilterAddFieldItem; + this.addParameterItem = XmlJsFilterAddParameterItem; + this.addResponseItem = XmlJsFilterAddResponseItem; + this.getValue = XmlJsFilterGetValue; + this.executeFilter = XmlJsFilterExecuteFilter; + this.checkFieldItem = XmlJsFilterCheckFieldItem; + this.getParameterParam = XmlJsFilterGetParameterParam; + this.alertMsg = XmlJsFilterAlertMsg; + this.proc = XmlJsFilterProc; +} + +function XmlJsFilterAddFieldItem(target, required, minlength, maxlength, equalto, filter) { + var obj = new Array(target, required, minlength, maxlength, equalto, filter); + this.field[this.field.length] = obj; +} + +function XmlJsFilterAddParameterItem(param, target) { + var obj = new Array(param, target); + this.parameter[this.parameter.length] = obj; +} + +function XmlJsFilterAddResponseItem(name) { + this.response[this.response.length] = name; +} + +function XmlJsFilterGetValue(target_name) { + var obj = this.fo_obj[target_name]; + if(typeof(obj)=='undefined') return ''; + var value = ''; + var length = obj.length; + var type = obj.type; + + if(length) type = obj[0].type; + + switch(type) { + case 'checkbox' : + if(typeof(length)!='undefined') { + value_list = new Array(); + for(var i=0;i=0) msg = alertMsg[msg_code].replace('%s',target_msg); + else msg = target_msg+alertMsg[msg_code]; + } else { + msg = msg_code; + } + + if(typeof(minlength)!='undefined' && typeof(maxlength)!='undefined') msg += "("+minlength+"~"+maxlength+")"; + + alert(msg); + try { + this.fo_obj[target].focus(); + } catch(e) { + } + return false; +} + +function XmlJsFilterCheckFieldItem() { + for(var i=0; i0 && maxlength>0 && (value.length < minlength || value.length > maxlength)) return this.alertMsg(target, 'outofrange', minlength, maxlength); + + if(equalto) { + var equalto_value = this.getValue(equalto); + if(equalto_value != value) return this.alertMsg(target, 'equalto'); + } + + if(filter.length && filter[0]) { + for(var j=0;j + * @desc : 한국어 언어팩 (기본적인 내용만 수록) + **/ + + // 기본적으로 사용되는 action 언어 + $lang->cmd_write = '쓰기'; + $lang->cmd_reply = '답글'; + $lang->cmd_delete = '삭제'; + $lang->cmd_modify = '수정'; + $lang->cmd_list = '목록'; + $lang->cmd_prev = '이전'; + $lang->cmd_next = '다음'; + $lang->cmd_send_trackback = '엮인글발송'; + $lang->cmd_registration = '등록'; + $lang->cmd_save = '저장'; + $lang->cmd_input = '입력'; + $lang->cmd_search = '검색'; + $lang->cmd_cancel = '취소'; + $lang->cmd_back = '돌아가기'; + $lang->cmd_vote= '추천'; + $lang->cmd_login = '로그인'; + $lang->cmd_logout = '로그아웃'; + $lang->cmd_signup = '가입'; + $lang->cmd_leave = '탈퇴'; + $lang->cmd_move = '이동'; + $lang->cmd_move_up = '위로'; + $lang->cmd_move_down = '아래로'; + $lang->cmd_management = '관리'; + $lang->cmd_make = "생성"; + $lang->cmd_select_all = "모두선택"; + $lang->cmd_unselect_all = "모두해제"; + + $lang->enable = '가능'; + $lang->disable = '불가능'; + + // 기본 단어 + $lang->no = '번호'; + $lang->notice = '공지'; + $lang->secret = '비밀'; + $lang->category = '분류'; + $lang->document_srl = '문서번호'; + $lang->user_id = '아이디'; + $lang->author = '작성자'; + $lang->password = '비밀번호'; + $lang->password1 = '비밀번호'; + $lang->password2 = '비밀번호 확인'; + $lang->admin_id = '관리자ID'; + $lang->user_name = '이름'; + $lang->nick_name = '닉네임'; + $lang->email_address = '이메일 주소'; + $lang->homepage = '홈페이지'; + $lang->browser_title = '브라우저 제목'; + $lang->title = '제목'; + $lang->title_content = '제목+내용'; + $lang->content = '내용'; + $lang->document = '게시물'; + $lang->comment = '댓글'; + $lang->description = '설명'; + $lang->trackback = '엮인글'; + $lang->tag = '태그'; + $lang->about_tag = '태그 입력시 , (쉼표)를 이용하시면 복수 등록이 가능합니다'; + $lang->allow_comment = '댓글허용'; + $lang->lock_comment = '댓글잠금'; + $lang->allow_trackback = '엮인글허용'; + $lang->uploaded_file = '첨부파일'; + $lang->grant = "권한"; + $lang->target = "대상"; + + $lang->document_url = '게시글 주소'; + $lang->trackback_url = '엮인글 주소'; + $lang->blog_name = '블로그이름'; + $lang->excerpt = '발췌'; + + $lang->document_count = '글수'; + $lang->page_count = '페이지수'; + $lang->readed_count = '조회수'; + $lang->voted_count = '추천수'; + $lang->member_count = '회원수'; + $lang->date = '날짜'; + $lang->regdate = '등록일'; + $lang->last_update = '최근수정일'; + $lang->last_login = '최종로그인'; + $lang->first_page = '첫페이지'; + $lang->last_page = '끝페이지'; + $lang->search_target = '검색대상'; + $lang->keyword = '검색어'; + $lang->is_default = "기본"; + + $lang->use = "사용"; + $lang->notuse = "미사용"; + + // xml filter에서 사용되는 javascript용 alert msg + $lang->filter->isnull = '%s의 값을 입력해주세요'; + $lang->filter->outofrange = '%s의 글자 길이를 맞추어 주세요.'; + $lang->filter->equalto = '%s의 값이 잘못 되었습니다.'; + $lang->filter->invalid_email = '%s의 형식이 잘못되었습니다. (예: zb5@zeroboard.com)'; + $lang->filter->invalid_user_id = $lang->filter->invalid_userid = "%s의 형식이 잘못되었습니다.\\n영문,숫자와 _로 만드실 수 있으며 제일 앞은 영문이어야 합니다"; + $lang->filter->invalid_homepage = '%s의 형식이 잘못되었습니다. (예: http://www.zeroboard.com)'; + $lang->filter->invalid_korean = '%s의 형식이 잘못되었습니다. 한글로만 입력해주셔야 합니다'; + $lang->filter->invalid_korean_number = '%s의 형식이 잘못되었습니다. 한글과 숫자로만 입력해주셔야 합니다'; + $lang->filter->invalid_alpha = '%s의 형식이 잘못되었습니다. 영문으로만 입력해주셔야 합니다'; + $lang->filter->invalid_alpha_number = '%s의 형식이 잘못되었습니다. 영문과 숫자로만 입력해주셔야 합니다'; + $lang->filter->invalid_number = '%s의 형식이 잘못되었습니다. 숫자로만 입력해주셔야 합니다'; + + // 메세지 관련 + $lang->msg_call_server = '서버에 요청중입니다. 잠시만 기다려주세요.'; + $lang->msg_db_not_setted = 'DB설정이 되어 있지 않습니다'; + $lang->msg_mid_not_exists = '설정이 되어 있지 않습니다. 관리자 페이지에서 기본 설정을 해주시기 바랍니다.'; + $lang->msg_invalid_queryid = 'Query ID값이 잘못 지정되었습니다'; + $lang->msg_not_permitted = '권한이 없습니다'; + $lang->msg_input_password = '비밀번호를 입력하여 주세요'; + $lang->msg_invalid_document = '잘못된 문서번호입니다'; + $lang->msg_invalid_request = '잘못된 요청입니다'; + $lang->msg_invalid_password = '비밀번호가 올바르지 않습니다'; + $lang->msg_error_occured = '오류가 발생하였습니다'; + $lang->msg_not_founded = '대상을 찾을 수 없습니다'; + + $lang->success_registed = '등록되었습니다'; + $lang->success_updated = '수정되었습니다'; + $lang->success_deleted = '삭제되었습니다'; + $lang->success_voted = '추천되었습니다'; + $lang->success_moved = '이동되었습니다'; + + $lang->failed_voted = '추천하실 수 없습니다'; + $lang->fail_to_delete_have_children = '답글이 있어서 삭제할 수 없습니다'; + + $lang->confirm_submit = '등록하시겠습니까?'; + $lang->confirm_logout = '로그아웃하시겠습니까?'; + $lang->confirm_vote = '추천하시겠습니까?'; + $lang->confirm_delete = '삭제하시겠습니까?'; + +?> diff --git a/common/tpl/common_footer.html b/common/tpl/common_footer.html new file mode 100644 index 000000000..d254cb43e --- /dev/null +++ b/common/tpl/common_footer.html @@ -0,0 +1,3 @@ +
{$lang->msg_call_server}
+ + diff --git a/common/tpl/common_header.html b/common/tpl/common_header.html new file mode 100644 index 000000000..51846c504 --- /dev/null +++ b/common/tpl/common_header.html @@ -0,0 +1,19 @@ + + + + +{Context::getBrowserTitle()} + + + + + + + + + + + +{Context::getHtmlHeader()} + + diff --git a/common/tpl/default_layout.html b/common/tpl/default_layout.html new file mode 100644 index 000000000..d1da8601d --- /dev/null +++ b/common/tpl/default_layout.html @@ -0,0 +1,3 @@ + +{$content} + diff --git a/config/config.inc.php b/config/config.inc.php new file mode 100644 index 000000000..5b9493f8c --- /dev/null +++ b/config/config.inc.php @@ -0,0 +1,37 @@ + + * @desc : 기본적으로 사용하는 class파일의 include 및 환경 설정을 함 + **/ + + // 기본적인 상수 선언 + // 웹에서 직접 호출되는 것을 막기 위해 체크하는 상수 선언 + define('__ZB5__', true); + + // 기본 함수 라이브러리 파일 + require_once("./config/func.inc.php"); + + // debug mode = true 일때 files/_debug_message.php 에 디버그 내용이 쌓임 + define('__DEBUG__', true); + if(__DEBUG__) define('__StartTime__', getMicroTime()); + + // 세션 설정 + @session_cache_limiter('no-cache, must-revalidate'); + @session_start(); + + // 기본적인 class 파일 include + if(__DEBUG__) define('__RequireClassStartTime__', getMicroTime()); + require_once("./classes/xml/XmlParser.class.php"); + require_once("./classes/context/Context.class.php"); + require_once("./classes/db/DB.class.php"); + require_once("./classes/file/FileHandler.class.php"); + require_once("./classes/output/Output.class.php"); + require_once("./classes/module/Module.class.php"); + require_once("./classes/display/DisplayHandler.class.php"); + require_once("./classes/module/ModuleHandler.class.php"); + require_once('./modules/module_manager/module_manager.module.php'); + //require_once("./classes/addon/AddOnHandler.class.php"); + //require_once("./classes/layout/LayoutHandler.class.php"); + if(__DEBUG__) define('__RequireClassEndTime__', getMicroTime()); +?> diff --git a/config/func.inc.php b/config/func.inc.php new file mode 100644 index 000000000..c6ffa9637 --- /dev/null +++ b/config/func.inc.php @@ -0,0 +1,84 @@ + + * @desc : 편의 목적으로 만든 함수라이브러리 파일 + **/ + + // php5에 대비하여 clone 정의/*{{{*/ + if (version_compare(phpversion(), '5.0') < 0) { + eval(' + function clone($object) { + return $object; + } + '); + }/*}}}*/ + + // function object getModule($module_name, $is_admin=false)/*{{{*/ + // module_manager::getModuleObject($module_name)을 쓰기 쉽게 함수로 선언 + function getModule($module_name, $is_admin=false) { + if($is_admin) return module_manager::getAdminModuleObject($module_name); + return module_manager::getModuleObject($module_name); + }/*}}}*/ + + // function string getUrl($args_list)/*{{{*/ + // Context::getUrl($args_list)를 쓰기 쉽게 함수로 선언 + function getUrl() { + $num_args = func_num_args(); + $args_list = func_get_args(); + + if(!$num_args) return Context::getRequestUri(); + + return Context::getUrl($num_args, $args_list); + }/*}}}*/ + + // function string cut_str($string, $cut_size, $tail = '...')/*{{{*/ + // microtime + function cut_str($string, $cut_size, $tail='...') { + if(!$string || !$cut_size) return $string; + $unicode_str = iconv("UTF-8","UCS-2",$string); + if(strlen($unicode_str) < $cut_size*2) return $string; + + $output = substr($unicode_str, 0, $cut_size*2); + return iconv("UCS-2","UTF-8",$output_str).$tail; + }/*}}}*/ + + // function string zdate($str, $format = "Y-m-d H:i:s")/*{{{*/ + // 시간 출력 + function zdate($str, $format = "Y-m-d H:i:s") { + return date($format, mktime(substr($str,8,2), substr($str,10,2), substr($str,12,2), substr($str,4,2), substr($str,6,2), substr($str,0,4))); + }/*}}}*/ + + // function void debugPrint($buff)/*{{{*/ + // 간단한 console debugging용 함수 + function debugPrint($buff, $display_line = true) { + $debug_file = "./files/_debug_message.php"; + $buff = sprintf("%s\n",print_r($buff,true)); + + if($display_line) $buff = "\n====================================\n".$buff."------------------------------------\n"; + + if(@!$fp = fopen($debug_file,"a")) return; + fwrite($fp, $buff); + fclose($fp); + }/*}}}*/ + + // function float getMicroTime()/*{{{*/ + // microtime + function getMicroTime() { + list($time1, $time2) = explode(' ', microtime()); + return (float)$time1+(float)$time2; + }/*}}}*/ + + // function string delObjectVars($target_obj, $del_obj)/*{{{*/ + // 첫번째 인자로 오는 object var에서 2번째 object의 var들을 빼낸다 + function delObjectVars($target_obj, $del_obj) { + if(count(get_object_vars($target_obj))<1) return; + if(count(get_object_vars($del_obj))<1) clone($target_obj); + + if(is_object($target_var)) $var = clone($target_var); + foreach($del_obj as $key => $val) { + unset($var->{$var_name}); + } + return $var; + }/*}}}*/ +?> diff --git a/editor/default/editor.css b/editor/default/editor.css new file mode 100644 index 000000000..2b70a4461 --- /dev/null +++ b/editor/default/editor.css @@ -0,0 +1,176 @@ +div.editor_content { + margin:3px; +} + +div.editor_fontbox { + margin : 3px 3px 3px 0px; + float:left; +} + +div.editor_fontbox select { + width:70px; + height:18px; +} + +div.editor_iconbox { + margin : 3px 3px 3px 0px; + white-space:nowrap; + font-size:1pt; + float:left; +} + +div.editor_iconbox img { + width : 16px; + height : 16px; + border : 1px solid #EEEEEE; + background-color : #FFFFFF; + padding:1px; + cursor : pointer; + margin-right:1px; +} + +div.editor_parabox { + margin : 3px 3px 3px 0px; + font-size:9pt; + text-align:right; + display:none; + float:right; +} + +div.editor_iframe_box { + clear:left; + border:1px solid #EFEFEF; + margin:3px 0px 0px 0px; +} + +div.editor_drag_down_area { + width:100%; + height:15px; + background:url(./images/icon_drag_down.gif) no-repeat center; + background-color:#EFEFEF; + cursor:s-resize; + position:relative; + margin-top:10px; +} + +.editor_pop_body { + padding:4px 4px 4px 4px; + margin:0px; + border:0px; + background-color:#FFFFFF; +} + +.editor_window { + background-color : #EFEFEF; +} + +textarea.editor_small_textarea { + font-family:tahoma; + border : 1px solid #CCCCCC; + background-color : #FFFFFF; + font-size : 8pt; + width:99%; + height:100px; +} + +textarea.editor_textarea { + font-family:tahoma; + border : 1px solid #CCCCCC; + background-color : #FFFFFF; + font-size : 8pt; + width:100%; + height:450px; +} + +input.editor_submit { + border : 1px solid #555555; + background-color : #AAAAAA; + color : #000000; + font-weight:bold; + font-family:verdana; + width : 100%; + height : 20px; + font-size : 8pt; +} + +div.quotation_box { + font-size:8pt; + font-family:tahoma; + margin-bottom:8px; + padding-bottom:5px; + border-bottom:1px dotted #AAAAAA; +} + +#quotation th { width:80px; font-size:8pt; font-family:tahoma; } + +img.color_icon { + width:15px; + height:15px; + border:1px solid #FFFFFF; +} + +img.color_icon_over { + width:15px; + height:15px; + border:1px solid #000000; + cursor:pointer; +} + +td.editor_field { + font-family:tahoma; + font-size:8pt; + font-weight:bold; + background-color : #CCCCCC; + text-align : center; +} + +input.editor_input { + font-family:tahoma; + border : 1px solid #CCCCCC; + background-color : #FFFFFF; + width : 330px; + height : 18px; + padding : 1px; + font-size : 8pt; +} + +.editor_uploader_box { + margin:0px; + border:0px; + padding:0px; +} + +.editor_uploader_box table { + border:0px; + margin:0px; + padding:2px; + table-layout:fixed; + width:100%; +} + +.uploaded_file_preview_box { + border:1px solid #EEEEEE; + width:120px; + height:120px; +} + +.uploaded_file_list { + width:100%; + height:120px; +} + +.editor_align_icon { + margin:0px 0px 6px 5px; + font-size:9pt; +} + +.editor_align_icon img { + vertical-align:middle; + cursor:pointer; +} + +img.editor_multimedia { + background:url(./images/multimedia_icon.gif) no-repeat center; + background-color:#FFFFFF; + border:2px dotted #B7AD10; +} diff --git a/editor/default/editor.html b/editor/default/editor.html new file mode 100644 index 000000000..262f94020 --- /dev/null +++ b/editor/default/editor.html @@ -0,0 +1,59 @@ + + + + + + + +
+
+ + +
+
+ {$lang->edit->help_fontcolor} + {$lang->edit->help_fontbgcolor} + {$lang->edit->help_bold} + {$lang->edit->help_italic} + {$lang->edit->help_underline} + {$lang->edit->help_strike} + {$lang->edit->help_add_url} + {$lang->edit->help_add_image} + {$lang->edit->help_add_multimedia} + {$lang->edit->help_add_emoticon} + {$lang->edit->help_add_quotation} + {$lang->edit->help_add_html} +
+ +
+ + +
+ +
+
diff --git a/editor/default/editor.js b/editor/default/editor.js new file mode 100755 index 000000000..7f7c42370 --- /dev/null +++ b/editor/default/editor.js @@ -0,0 +1,706 @@ +/** + * richtext 에디터 관련 + **/ +// iframe의 id prefix +var iframe_id = 'editor_iframe_'; + +// srl값에 해당하는 iframe의 object를 return +function editorGetIFrame(document_srl) {/*{{{*/ + var obj_id = iframe_id+document_srl; + return xGetElementById(obj_id); +}/*}}}*/ + +// editor 초기화를 onload이벤트 후에 시작시킴 +function editorInit(document_srl) {/*{{{*/ + var start_func = function _editorStart() { editorStart(document_srl); } + var init_func = function _editorInit() { setTimeout(start_func, 300); } + xAddEventListener(window, 'load', init_func); +}/*}}}*/ + +// editor 초기화 (document_srl로 iframe객체를 얻어서 쓰기 모드로 전환) +function editorStart(document_srl) {/*{{{*/ + // iframe obj를 찾음 + var iframe_obj = editorGetIFrame(document_srl); + if(!iframe_obj) return; + + // 현 에디터를 감싸고 있는 form문을 찾아서 content object를 찾아서 내용 sync + var fo_obj = iframe_obj.parentNode; + while(fo_obj.nodeName != 'FORM') { fo_obj = fo_obj.parentNode; } + + var content = fo_obj.content.value; + + // 기본 폰트를 가져옴 + var default_font = xGetElementById('editor_font_'+document_srl).options[1].value; + + // iframe내의 document object + var contentDocument = iframe_obj.contentWindow.document; + + // editing가능하도록 설정 + + + // 기본 내용 작성 + var contentHtml = ''+ + ''+ + ''; + + /********* 오페라에서 stylesheet를 못 가져와서 일단 주석 처리하고 수동 처리 + for(var i in document.styleSheets) { + var tmp_obj = document.styleSheets[i]; + if(typeof(tmp_obj.href)=='undefined'||tmp_obj.href.lastIndexOf(".css")<0) continue; + contentHtml += ""; + } + **********/ + contentHtml += ""; + contentHtml += ""; + contentHtml += ""+ + ""+ + content+ + ""; + + contentDocument.designMode = 'on'; + contentDocument.open("text/html","replace"); + contentDocument.write(contentHtml); + contentDocument.close(); + + // 작성시 필요한 이벤트 체크 + if(xIE4Up) xAddEventListener(contentDocument, 'keydown',editorKeyPress); + else xAddEventListener(contentDocument, 'keypress',editorKeyPress); + xAddEventListener(contentDocument,'mousedown',editorHideObject); + + //xAddEventListener(document,'keypress',editorKeyPress); + xAddEventListener(document,'mouseup',editorEventCheck); + xAddEventListener(document,'mousedown',editorHideObject); + + // 문단작성기능 on/off + if(xIE4Up) { + xDisplay('editor_paragraph_'+document_srl, 'none'); + xDisplay('editor_use_paragraph_box_'+document_srl, 'inline'); + } else { + xDisplay('editor_paragraph_'+document_srl, 'block'); + xDisplay('editor_use_paragraph_box_'+document_srl, 'none'); + } + + // 에디터의 내용을 지속적으로 fo_obj.content.value에 입력 + editorSyncContent(fo_obj.content, document_srl); +}/*}}}*/ + +var _editorSyncList = new Array(); /*{{{*/ +function editorSyncContent(obj, document_srl) { + _editorSyncList[_editorSyncList.length] = {field:obj, document_srl:document_srl} +}/*}}}*/ + +function _editorSync() {/*{{{*/ + for(var i=0;i<_editorSyncList.length;i++) { + var field = _editorSyncList[i].field; + var document_srl = _editorSyncList[i].document_srl; + var content = editorGetContent(document_srl); + if(typeof(content)=='undefined'||!content) continue; + field.value = content; + } + setTimeout(_editorSync, 1000); +}/*}}}*/ +xAddEventListener(window, 'load', _editorSync); + +// 문단기능 toggle +function editorUseParagraph(obj, document_srl) { /*{{{*/ + toggleDisplay('editor_paragraph_'+document_srl); +}/*}}}*/ + +// 에디터의 내용 return +function editorGetContent(document_srl) {/*{{{*/ + var iframe_obj = editorGetIFrame(document_srl); + if(!iframe_obj) return; + var html = ''; + html = xInnerHtml(iframe_obj.contentWindow.document.body); + if(!html) return; + return html.trim(); +}/*}}}*/ + +// 에디터 내의 선택된 부분의 html 코드를 return +function editorGetSelectedHtml(document_srl) {/*{{{*/ + var iframe_obj = editorGetIFrame(document_srl); + if(xIE4Up) { + var range = iframe_obj.contentWindow.document.selection.createRange(); + var html = range.htmlText; + range.select(); + return html; + } else { + var range = iframe_obj.contentWindow.getSelection().getRangeAt(0); + var dummy = xCreateElement('div'); + dummy.appendChild(range.cloneContents()); + var html = xInnerHtml(dummy); + return html; + } +}/*}}}*/ + +// 에디터 내의 선택된 부분의 html코드를 변경 +function editorReplaceHTML(iframe_obj, html) {/*{{{*/ + iframe_obj.contentWindow.focus(); + if(xIE4Up) { + var range = iframe_obj.contentWindow.document.selection.createRange(); + range.pasteHTML(html); + } else { + var range = iframe_obj.contentWindow.getSelection().getRangeAt(0); + range.deleteContents(); + range.insertNode(range.createContextualFragment(html)); + } +}/*}}}*/ + +// 입력 키에 대한 이벤트 체크 +function editorKeyPress(evt) {/*{{{*/ + var e = new xEvent(evt); + if (e.keyCode == 13) { + if(xIE4Up && e.shiftKey == false && !xGetElementById("use_paragraph").checked ) { + if(e.target.parentElement.document.designMode!="On") return; + var obj = e.target.parentElement.document.selection.createRange(); + obj.pasteHTML('
'); + obj.select(); + evt.cancelBubble = true; + evt.returnValue = false; + return; + } + } + + if (e.ctrlKey) { + switch(e.keyCode) { + case 98 : // b + editorDo('Bold',null,e.target); + xPreventDefault(evt); + xStopPropagation(evt); + break; + case 105 : // i + editorDo('Italic',null,e.target); + xPreventDefault(evt); + xStopPropagation(evt); + break; + case 117 : // u + editorDo('Underline',null,e.target); + xPreventDefault(evt); + xStopPropagation(evt); + break; + case 83 : // s + case 115 : // s + editorDo('StrikeThrough',null,e.target); + xPreventDefault(evt); + xStopPropagation(evt); + break; + } + } +}/*}}}*/ + +// 에디터 상단의 버튼 클릭시 action 처리 +var editorPrevObj = null;/*{{{*/ +var editorPrevSrl = null; +function editorEventCheck(evt) { + var e = new xEvent(evt); + var target_id = e.target.id; + if(target_id.indexOf('editor_')!=-1) { + var tmp_str = target_id.split('_'); + var method_name = tmp_str[1]; + var document_srl = tmp_str[2]; + switch(method_name) { + case 'Bold' : + case 'Italic' : + case 'Underline' : + case 'StrikeThrough' : + case 'justifyleft' : + case 'justifycenter' : + case 'justifyright' : + case 'indent' : + case 'outdent' : + case 'insertorderedlist' : + case 'insertunorderedlist' : + editorDo(method_name, '', document_srl); + break; + default : + editorPrevSrl = document_srl; + switch(method_name) { + case "addemoticon" : + var x = (screen.availWidth - 225)/2; + var y = (screen.availHeight - 150)/2; + var editor_popup = window.open(editor_path+"popup/add_emoticon.php","_editorPopup","top="+y+",left="+x+",width=225,height=150,resizable=no,toolbars=no,scrollbars=no"); + if(editor_popup) editor_popup.focus(); + return; + break; + case "quotation" : + var x = (screen.availWidth - 400)/2; + var y = (screen.availHeight - 400)/2; + var editor_popup = window.open(editor_path+"popup/add_quotation.php","_editorPopup","top="+y+",left="+x+",width=400,height=400,resizable=no,toolbars=no,scrollbars=no"); + if(editor_popup) editor_popup.focus(); + return; + break; + case "addurl" : + var x = (screen.availWidth - 400)/2; + var y = (screen.availHeight - 220)/2; + var editor_popup = window.open(editor_path+"popup/add_url.php","_editorPopup","top="+y+",left="+x+",width=400,height=220,resizable=no,toolbars=no,scrollbars=no"); + if(editor_popup) editor_popup.focus(); + return; + break; + case "addimage" : + var x = (screen.availWidth - 420)/2; + var y = (screen.availHeight - 80)/2; + var editor_popup = window.open(editor_path+"popup/add_image.php","_editorPopup","top="+y+",left="+x+",width=420,height=80,resizable=no,toolbars=no,scrollbars=no"); + if(editor_popup) editor_popup.focus(); + return; + break; + case "addmultimedia" : + var x = (screen.availWidth - 400)/2; + var y = (screen.availHeight - 220)/2; + var editor_popup = window.open(editor_path+"popup/add_multi.php","_editorPopup","top="+y+",left="+x+",width=420,height=110,resizable=no,toolbars=no,scrollbars=no"); + if(editor_popup) editor_popup.focus(); + return; + break; + case "addhtml" : + var x = (screen.availWidth - 400)/2; + var y = (screen.availHeight - 500)/2; + var editor_popup = window.open(editor_path+"popup/add_html.php","_editorPopup","top="+y+",left="+x+",width=400,height=500,resizable=no,toolbars=no,scrollbars=no"); + if(editor_popup) editor_popup.focus(); + return; + break; + case "ForeColor" : + case "BackColor" : + var x = (screen.availWidth - 145)/2; + var y = (screen.availHeight - 95)/2; + var editor_popup = window.open(editor_path+"popup/color_box.php?mode="+method_name,"_editorPopup","top="+y+",left="+x+",width=145,height=95,resizable=no,toolbars=no,scrollbars=no"); + if(editor_popup) editor_popup.focus(); + return; + } + break; + } + } + return; +}/*}}}*/ + +// focus +function editorFocus(document_srl) {/*{{{*/ + var iframe_obj = editorGetIFrame(document_srl); + iframe_obj.contentWindow.focus(); +} +/*}}}*/ + +// 편집 기능 실행 +function editorDo(name, value, target) {/*{{{*/ + if(typeof(target)=='object') _editorDoObject(name, value, target); + else _editorDoSrl(name, value, target); +}/*}}}*/ + +function _editorDoSrl(name, value, document_srl) {/*{{{*/ + var iframe_obj = editorGetIFrame(document_srl); + editorFocus(document_srl); + if(xIE4Up) iframe_obj.contentWindow.document.execCommand(name, false, value); + else iframe_obj.contentWindow.document.execCommand(name, false, value); + editorFocus(document_srl); +}/*}}}*/ + +function _editorDoObject(name, value, obj) {/*{{{*/ + if(xIE4Up) { + obj.parentElement.document.execCommand(name, false, value); + } else { + obj.parentNode.execCommand(name, false, value); + } +}/*}}}*/ + +function editorHideObject(evt) {/*{{{*/ + if(!editorPrevObj) return; + var e = new xEvent(evt); + var tobj = e.target; + while(tobj) { + if(tobj.id == editorPrevObj.id) { + return; + } + tobj = xParent(tobj); + } + editorPrevObj.style.visibility = 'hidden'; + editorPrevObj = null; + return; +}/*}}}*/ + +function editorChangeFontName(obj,srl) {/*{{{*/ + var value = obj.options[obj.selectedIndex].value; + if(!value) return; + editorDo('FontName',value,srl); + obj.selectedIndex = 0; +}/*}}}*/ + +function editorChangeFontSize(obj,srl) {/*{{{*/ + var value = obj.options[obj.selectedIndex].value; + if(!value) return; + editorDo('FontSize',value,srl); + obj.selectedIndex = 0; +}/*}}}*/ + +function editorSetForeColor(color_code) {/*{{{*/ + editorDo("ForeColor",color_code,editorPrevSrl); + editorPrevObj.style.visibility = 'hidden'; + editorFocus(editorPrevSrl); +}/*}}}*/ + +function editorSetBackColor(color_code) {/*{{{*/ + if(xIE4Up) editorDo("BackColor",color_code,editorPrevSrl); + else editorDo("hilitecolor",color_code,editorPrevSrl); + editorFocus(editorPrevSrl); +}/*}}}*/ + +function editorInsertEmoticon(obj) {/*{{{*/ + editorFocus(editorPrevSrl); + editorDo("InsertImage",obj.src,editorPrevSrl); + editorFocus(editorPrevSrl); +}/*}}}*/ + +function editorDoInsertUrl(link, document_srl) {/*{{{*/ + editorFocus(document_srl); + var iframe_obj = editorGetIFrame(srl); + editorReplaceHTML(iframe_obj, link); +}/*}}}*/ + +function editorInsertUrl(text, url, link_type) {/*{{{*/ + if(!text || !url) return; + //if(!/^(http|ftp)/i.test(url)) url = 'http://'+url; + + var link = ''; + if(!link_type) link = ""+text+""; + else link = ""+text+""; + + editorFocus(editorPrevSrl); + var obj = editorGetIFrame(editorPrevSrl) + editorReplaceHTML(obj, link); +}/*}}}*/ + +function editorInsertImage(url, src_align) {/*{{{*/ + if(!url) return; + //if(!/^(http|ftp)/i.test(url)) url = 'http://'+url; + + editorFocus(editorPrevSrl); + + var html = "\"i\"
"; + return html; +}/*}}}*/ + +function editorInsertMultimedia(url, width, height) {/*{{{*/ + if(url) { + var html = editorGetMultimediaHtml(url, width, height); + editorFocus(editorPrevSrl); + var obj = editorGetIFrame(editorPrevSrl) + editorReplaceHTML(obj, html); + editorFocus(editorPrevSrl); + } +}/*}}}*/ + +function editorInsertHTML(html) {/*{{{*/ + if(!html) return; + + editorFocus(editorPrevSrl); + var obj = editorGetIFrame(editorPrevSrl) + editorReplaceHTML(obj, html); + editorFocus(editorPrevSrl); +}/*}}}*/ + +function editorInsertQuotation(html) {/*{{{*/ + if(!html) return; + + if(!xIE4Up) html += "
"; + editorFocus(editorPrevSrl); + var obj = editorGetIFrame(editorPrevSrl) + editorReplaceHTML(obj, html); + editorFocus(editorPrevSrl); +}/*}}}*/ + +function editorHighlight(ret_obj, response_tags, obj) {/*{{{*/ + var html = ret_obj['html']; + html = "
"+html+"
"; + if(!xIE4Up) html += "
"; + editorReplaceHTML(obj, html); +}/*}}}*/ + +/** + * iframe 드래그 관련 + **/ +var editorIsDrag = false; +var editorDragY = 0; +var editorDragObj = null; +var editorDragID = ''; +xAddEventListener(document, 'mousedown', editorDragStart); +xAddEventListener(document, 'mouseup', editorDragStop); +function editorDragStart(evt) {/*{{{*/ + var e = new xEvent(evt); + var obj = e.target; + if(typeof(obj.id)=='undefined'||!obj.id) return; + var id = obj.id; + if(id.indexOf('editor_drag_bar_')!=0) return; + + editorIsDrag = true; + editorDragObj = e.target; + editorDragY = e.pageY; + editorDragID = id.substr('editor_drag_bar_'.length); + xAddEventListener(document, 'mousemove', editorDragMove); + xAddEventListener(editorDragObj, 'mouseout', editorDragMove); + + var iframe_obj = editorGetIFrame(editorDragID); + xAddEventListener(iframe_obj, 'mousemove', editorDragMove); +}/*}}}*/ + +function editorDragStop(evt) {/*{{{*/ + var iframe_obj = editorGetIFrame(editorDragID); + xRemoveEventListener(document, 'mousemove', editorDragMove); + xRemoveEventListener(iframe_obj, 'mousemove', editorDragMove); + + editorIsDrag = false; + editorDragY = 0; + editorDragObj = null; + editorDragID = ''; +}/*}}}*/ + +function editorDragMove(evt) {/*{{{*/ + if(typeof(editorIsDrag)=='undefined'||!editorIsDrag) return; + var e = new xEvent(evt); + var iframe_obj = editorGetIFrame(editorDragID); + + var y = e.pageY; + var yy = y - editorDragY; + if(yy<0) return; + editorDragY = y; + + var editorHeight = xHeight(iframe_obj); + xHeight(iframe_obj, editorHeight+yy); +}/*}}}*/ + +/** + * 파일 업로드 관련 + **/ +var uploading_file = false; +var uploaded_files = new Array(); + +// 업로드를 하기 위한 준비 시작 +function editor_upload_init(document_srl) {/*{{{*/ + xAddEventListener(window,'load',function _change_form_target() {editor_upload_form_set(document_srl);} ); +}/*}}}*/ + +// document_srl에 해당하는 form의 action을 iframe으로 변경 +function editor_upload_form_set(document_srl) {/*{{{*/ + // 업로드용 iframe을 생성 + if(!xGetElementById('tmp_upload_iframe')) { + if(xIE4Up) { + window.document.body.insertAdjacentHTML("afterEnd", ""); + } else { + var obj_iframe = xCreateElement('IFRAME'); + obj_iframe.name = obj_iframe.id = 'tmp_upload_iframe'; + obj_iframe.style.display = 'none'; + obj_iframe.style.width = '1px'; + obj_iframe.style.height = '1px'; + obj_iframe.style.position = 'absolute'; + obj_iframe.style.top = '-10px'; + obj_iframe.style.left = '-10px'; + window.document.body.appendChild(obj_iframe); + } + } + + // form의 action 을 변경 + var field_obj = xGetElementById("uploaded_file_list_"+document_srl); + if(!field_obj) return; + var fo_obj = field_obj.parentNode; + while(fo_obj.nodeName != 'FORM') { fo_obj = fo_obj.parentNode; } + fo_obj.target = 'tmp_upload_iframe'; + + // document_srl에 해당하는 첨부파일 목록을 로드 + var mid = fo_obj.mid.value; + var document_srl = fo_obj.document_srl.value; + var url = "./?mid="+mid+"&act=procDeleteFile&document_srl="+document_srl; + + // iframe에 url을 보내버림 + var iframe_obj = xGetElementById('tmp_upload_iframe'); + if(!iframe_obj) return; + + iframe_obj.contentWindow.document.location.href=url; +}/*}}}*/ + +// 파일 업로드 +function editor_file_upload(field_obj, document_srl) {/*{{{*/ + if(uploading_file) return; + + var fo_obj = field_obj.parentNode; + while(fo_obj.nodeName != 'FORM') { fo_obj = fo_obj.parentNode; } + + uploading_file = true; + fo_obj.submit(); + uploading_file = false; + + var sel_obj = xGetElementById('uploaded_file_list_'+document_srl); + var string = 'wait for uploading...'; + var opt_obj = new Option(string, '', true, true); + sel_obj.options[sel_obj.options.length] = opt_obj; +}/*}}}*/ + +// 업로드된 파일 목록을 삭제 +function editor_upload_clear_list(document_srl) {/*{{{*/ + var obj = xGetElementById('uploaded_file_list_'+document_srl); + while(obj.options.length) { + obj.remove(0); + } + var preview_obj = xGetElementById('uploaded_file_preview_box_'+document_srl); + xInnerHtml(preview_obj,'') +}/*}}}*/ + +// 업로드된 파일 정보를 목록에 추가 +function editor_insert_uploaded_file(document_srl, file_srl, filename, file_size, disp_file_size, uploaded_filename, sid) {/*{{{*/ + var obj = xGetElementById('uploaded_file_list_'+document_srl); + var string = filename+' ('+disp_file_size+')'; + var opt_obj = new Option(string, file_srl, true, true); + obj.options[obj.options.length] = opt_obj; + + var file_obj = {file_srl:file_srl, filename:filename, file_size:file_size, uploaded_filename:uploaded_filename, sid:sid} + uploaded_files[file_srl] = file_obj; + + editor_preview(obj, document_srl); +}/*}}}*/ + +// 파일 목록창에서 클릭 되었을 경우 미리 보기 +function editor_preview(sel_obj, document_srl) {/*{{{*/ + if(sel_obj.options.length<1) return; + var file_srl = sel_obj.options[sel_obj.selectedIndex].value; + var obj = uploaded_files[file_srl]; + if(typeof(obj)=='undefined'||!obj) return; + var uploaded_filename = obj.uploaded_filename; + var preview_obj = xGetElementById('uploaded_file_preview_box_'+document_srl); + + if(!uploaded_filename) { + xInnerHtml(preview_obj, ''); + return; + } + + var html = ""; + + // 플래쉬 동영상의 경우 + if(/\.flv$/i.test(uploaded_filename)) { + html = ""; + // 플래쉬 파일의 경우 + } else if(/\.swf$/i.test(uploaded_filename)) { + html = ""; + // wmv, avi, mpg, mpeg등의 동영상 파일의 경우 + } else if(/\.(wmv|avi|mpg|mpeg|asx|asf|mp3)$/i.test(uploaded_filename)) { + html = ""; + // 이미지 파일의 경우 + } else if(/\.(jpg|jpeg|png|gif)$/i.test(uploaded_filename)) { + html = ""; + } + xInnerHtml(preview_obj, html); +}/*}}}*/ + +// 업로드된 파일 삭제 +function editor_remove_file(document_srl) {/*{{{*/ + var obj = xGetElementById('uploaded_file_list_'+document_srl); + if(obj.options.length<1) return; + var file_srl = obj.options[obj.selectedIndex].value; + if(!file_srl) return; + + // 삭제하려는 파일의 정보를 챙김;; + var fo_obj = obj; + while(fo_obj.nodeName != 'FORM') { fo_obj = fo_obj.parentNode; } + var mid = fo_obj.mid.value; + var document_srl = fo_obj.document_srl.value; + var url = "./?mid="+mid+"&act=procDeleteFile&document_srl="+document_srl+"&file_srl="+file_srl; + + // iframe에 url을 보내버림 + var iframe_obj = xGetElementById('tmp_upload_iframe'); + if(!iframe_obj) return; + + iframe_obj.contentWindow.document.location.href=url; +}/*}}}*/ + +// 업로드 목록의 선택된 파일을 내용에 추가 +function editor_insert_file(document_srl, align) {/*{{{*/ + var obj = xGetElementById('uploaded_file_list_'+document_srl); + if(obj.options.length<1) return; + var file_srl = obj.options[obj.selectedIndex].value; + if(!file_srl) return; + var file_obj = uploaded_files[file_srl]; + var filename = file_obj.filename; + var sid = file_obj.sid; + var uploaded_filename = file_obj.uploaded_filename; + editorPrevSrl = document_srl; + + // 바로 링크 가능한 파일의 경우 (이미지, 플래쉬, 동영상 등..) + if(uploaded_filename && typeof(align)!='undefined') { + + var type = ""; + + // 이미지 파일의 경우 + if(/\.(jpg|jpeg|png|gif)$/i.test(uploaded_filename)) { + + editorFocus(editorPrevSrl); + + var html = "\""+filename+"\""; + + var iframe_obj = editorGetIFrame(editorPrevSrl); + editorReplaceHTML(iframe_obj, html); + } + + // binary파일의 경우 다운로드 링크를 추가 + } else { + var fo_obj = obj; + while(fo_obj.nodeName != 'FORM') { fo_obj = fo_obj.parentNode; } + var mid = fo_obj.mid.value; + var document_srl = fo_obj.document_srl.value; + var url = "./?mid="+mid+"&act=procDownload&document_srl="+document_srl+"&file_srl="+file_srl+"&sid="+sid; + + var x = (screen.availWidth - 400)/2; + var y = (screen.availHeight - 220)/2; + var editor_popup = window.open(editor_path+"popup/add_url.php?title="+escape(filename)+"&url="+escape(url),"_editorPopup","top="+y+",left="+x+",width=400,height=220,resizable=no,toolbars=no,scrollbars=no"); + if(editor_popup) editor_popup.focus(); + } + +}/*}}}*/ + +/** + * 글을 쓰다가 페이지 이동시 첨부파일에 대한 정리 + **/ +function editorRemoveAttachFiles(mid, document_srl) {/*{{{*/ + var obj = xGetElementById('uploaded_file_list_'+document_srl); + if(obj.options.length<1) return; + + var params = new Array(); + params['document_srl'] = document_srl; + exec_xml(mid, 'procClearFile', params, null, null, null); +}/*}}}*/ diff --git a/editor/default/editor_uploader.html b/editor/default/editor_uploader.html new file mode 100644 index 000000000..d12fcc7b3 --- /dev/null +++ b/editor/default/editor_uploader.html @@ -0,0 +1,44 @@ + + + +
+ + + + + + + + + + + +
+
+ {$lang->edit->icon_align_article} + {$lang->edit->icon_align_article} +
+
+ {$lang->edit->icon_align_left} + {$lang->edit->icon_align_left} +
+
+ {$lang->edit->icon_align_middle} + {$lang->edit->icon_align_middle} +
+
+ {$lang->edit->icon_align_right} + {$lang->edit->icon_align_right} +
+
+ + + + + +
+
+ diff --git a/editor/default/flvplayer/flvplayer.swf b/editor/default/flvplayer/flvplayer.swf new file mode 100644 index 0000000000000000000000000000000000000000..5b5412a52ebed45f4a70792d3081b13b4e49fb56 GIT binary patch literal 3443 zcmV-(4UFriZR)n{-1|O$j!U&}M%;JbIp>~x{`b6_7?^qi9syX$z{Y&QUlW6a2O6}k8h}I3 zLN0U*{s9gW{r(8o&IdS%^4(+({z!Nr3O#KQ0$` z^#>r5#Zik;^45@-gQE`rPr@j{7Ubcm2c5>?OZcM+%IDDnEd_cWHLb#l0Y<(uZJj%3 z?mfC%4>ySfbBw57B|1J5?%(SYco+IRE`YeiIB&@u{%*Ns3KkPnK#T^J*`p!ksN|(y zX7=VUw2vRZxm9~0go@aZ%!G5pFP+7LXgS- zboV=5FXr6i&`w|9;ppWi=U{Zy3F_6+Wt?e2Q_@QI?x z+o7t{XHFk=tg}n9TV&bIvTFzrs|-cYOc@FgQo$hUC5Si7UFtjw;r^(k=@^c=unT-1 zxCpYU+h@kFs5G@bcJ6%D(CzCc=P4OfG-YOl$n}{{F>(RMz44ZO9=HcGk5d4!J}hp_4ZDnLa)g zd$07#T*vb_$EhKR@AAt3^?~8QiQ3P1zYsidvbH2Abba#7(Fb#wiGxSCme!UWuI-VG zViVP8khP@daUAnu=Z6!+Ge0-@c%tefd{tQg<% z#e0ocKMGEazoaw%ZQF^W=qELHeQR&k8 z5N>gQx(Binf(FcL`*fucxe+iNo^U&$>Gb5&%^MaSKK1nY?77w#dJnc-D7KF0-w41T z1F&cDjUSMw&nZ5)=in0ssY6CZqJn`5;$N z8_~TMVIC@unRmwYxtDK~OkFG+u1Gc~fi94t8W~E)g)-Ek%A{hLU|BF7upzsoc76dJ?Ae z~ixImD57pFa`{ z`5_VFM}mpIq#*E7@Wpvv62cvf41+%@@CkZClbLu{_miWWv|G@a3i&{jfGt~;>lebfX}>rn&~72l`G+9E2_o;FFy>_<8W0<}enbjf^H59} zYv+f<9PSwdzaaSgLmQHTFpol#v71lg3goea>MBvt{tXgCs9*?1h5*+W;rsWJDIaa; z1ph|A;0J*h{1LiqAQ|^l@%SjJAtZ5o(!wf2x=AbO?iTnMZpH0|I2S|dRCrMXcS|yY z)jw+)u_PbuB+j7@qzZ|FAx`;dGd8vHmbf2CBVMPxnk{APu`Oy&@!`O(2he$Bc5lsORE;@i=F&G;V zVbqyKPf`7oxhk^&#HEhApx_jPC7QfwoJtGL&=y*Y%`>*mpx2Z=$KYX+GDErv7fEzt zf32tewL!1xkQ#IP2K0?pa3}NB{s36}4IGUb9Q6vvV-7`s26ThKjDR)-%eCp9Ol*$$ z)G-H98M0odmc&f(_~BsIX^o^sFwdj1P^?wQ&<_i1N)JZT)tgnwTwJOk?Fuqa`pU3S zMXX+eCFb0u!sbfYTs2mQ-wLdaez4@X5{I;D$h<&WVU(VF=~*Z}?b6es2(>6vpZ|8I z@|soJ#Y%RcZ->;a*mp?c8qw^=l@eG26d6g&L;;1_EDtEwE0mW1UZ%EZQ~MNaI5 z1t~dNr|rPFHUE#cwErKr6cxn?G}bBl706LJPyPy#g2q6xDh8TCGJ+}(3Z)1yq%mZo zF_f?DkT%$z6o$&@W-t+jTR<0UyfpQ#AbxW%Bq^RJy~q@0Y4Q?DvNl{(2*qhcsY+y# zS*chrSm^~Qmr_Ek*Qm&xY#AY|hBPmyS|%sEC@qsyp(sm#&zDO%Rn9t{Y6l?5#V)4w zOOPI4mrAd<;j0zcW$B_*;VDb8z=&mU86{dSmOX~N$_23!$t++bANuMFS%stpsuH$B zyo|V=B3Fu)j7f7@LE)=J{%-OrW2!~|oeF<9C0(7xf~D{^B3z8~wNh}fG=c6g>g5Cy zWvn@7CD$F=Dq#4&L1J8%gxWeC!`6B`RD^dPvr)o9N=O=rZ5k4m3|mKi{2l7N8A#dE z8mo=5p6Z3H?^1 z-FoW{>N6MCWGuXgE_8kE!ZOuDs#gv*K*LGmDX0fYaU2bVmmVlDN9O71sV{zxeBNdN zH`Et*q*qG}Z$V@H1{#kF!Q)NRupYH7qkFNgh381xVO6aDdUOjz&2?;e4V zkGTi<%2jKsq)O?aOLnLu0PE#5nGt}HeG;VIE6Que0-&h0xu8uvy^7IicnFgQVt^K` zEz&YETXuR$7?~)W4w)Yb79y|(gG9EQNG^_UuXG-CWC~2ZuNFV;eN)=|^ZY2%@0u6z zQ-EiqqRrRtzq^aXuuMX2-UO*!Fz%7hf?J6_&j7U3BiA^@oh^_N8Q+2pMwv-jC|YJI z)y+juOnMmasn7UCQAhHte5G+PY2^iV*Er)c&mV>cO5%OhcGIJzuSc V{3$~N!N_n-{96&h{RiC!l_~1mkm&#b literal 0 HcmV?d00001 diff --git a/editor/default/images/add_image.gif b/editor/default/images/add_image.gif new file mode 100644 index 0000000000000000000000000000000000000000..a376c161f6343bfc8984d040b620ed0195dcc737 GIT binary patch literal 1019 zcmZ?wbhEHb6krfw_}*E(6z9mnynYZcE>-V3!4@EZa3wrzU`ebnO>mJl> zsHoq(aK)vPsjJV=Tz}!{<@JYe?pl7KY0B#J?b~;}1iEU?y$@f$SFD=<_S5$XN8?gw z*v;E?v1!@yXK%lqyz(S#+TssizfazFamu0Y+C?`%fBDj|FSz|+MEj=vPoKZc-2P>L^*}RktUoe1*@&^?9?ZP19#N%-->|cG1!JNj=Zre$Se@w0-lohUTz^dtYoi zcx(C2%jI*gl{LjJJUw~F$*i~uoh{4n%-V2q>Y58*zJ8y%{^FrK`~Uy{&oBz;5(0`p zSr{1@+8J~}wt?~l1IG;peoh&W4GRuP842)2?J#IK%wWgCaVNQrYhky9zLCNv7X>Dr z^kX@UjZHlw(rQ0eSSScED6%{M`S9b=Q-4lt=~EkQSRS}d6Lz#(Gb2HjWv(Va%hnd9 zboUu5ni^XinLUnhFSUv6*|C|;M^qxI#D+74L7Rbxb&<@@OHC|&dc`(VL@hWx=P}9u zO6h29_v}+*-oUr%!69C03vQ8$&c!TF35`x#60`m!ACp#?%xkKtvcY}UnFYqzAJ%xB lW;K-(l6a`FU@L=^kP=79BKLrWw|5kpPsrHt{XheQH2^w4aa#ZY literal 0 HcmV?d00001 diff --git a/editor/default/images/add_indent.gif b/editor/default/images/add_indent.gif new file mode 100644 index 0000000000000000000000000000000000000000..a092d8c2a0a2ec1c895637807ebe8919a5342ae7 GIT binary patch literal 525 zcmZ?wbhEHb6krfwc;>_q8ylOGlarpFZe(O+VPT=EsVOHXmz0#`>FHTkR_5a35*!>H z5fRb2;f1ZOZDCkfq@<*@v~=f|7vbUIzP`Tp_V)LlefRS6DqsFY zOiU~?GO}RtV-XRNnl&$*H$CU)=T}ox^Y{06c6PS2vokRiYlxe}HCM7aW319f(*gt}%6YE#cr0ieNYh zf}#Ob=z>H8u-b!Op1{;<_01W)(hXT=@RXDklgT6=fG67GAJ>g)Ug9(+OPO z>gwtW7bMZ$)jh}VEfG9B^esEP=l9G~aHk+==rqya|Yin=KZL}>CDwV2I z(<-XHqZ);8&l8)Qo5275gMpY0Dg^-A0mfhU?9-tJ_tmtGHwTx?ql)8_-*DUpF^z#ntg6DPMtE!WE}Krpj0iVWxa W`6q7Ajkxl%cdFhmHp`z1uzmwovwr0O literal 0 HcmV?d00001 diff --git a/editor/default/images/add_url.gif b/editor/default/images/add_url.gif new file mode 100644 index 0000000000000000000000000000000000000000..d923ff08309793c53c8809f30fc34ba533a73c38 GIT binary patch literal 1082 zcmciBeN);60KoB|Ls75Q+3IfHTzB*2%v!r{tE=s{D+0xwxPi0WyiFwp9}oeVsBAGr z@>vtYskE75K2797;j9!DQEYTmT) zS9lGx&g?<4W6RO3)MFUwR3B^c@d7*%Mq{#dehZO-k!{Hrw{@vbTwYHmwE6;FQ6l%X zGYzFYb7KZMqo7wgxvE*-nj8x#b6kB6r>mLM+~;u!?DiC7O8=IW;-%Nmu(1so)0&iR zkk9*nJ)50-)8mecJ_8`emR%RrD$^RJ9*XB)nfts9gU)RLQC|N zT_cvW*sO-7p9us427_tqt0j^Mbas8ccdB!BBDaoa_ge>rLmVA_Y|W0a6gExMQcF`9 z1}f=Jecr^x!)McjkM)=DeWCYT2_5;uC-VN4`66ozYU0}XZ@qLa$rdo((v$GgdDEj2 zp|h{s-644RgG!}RDwUsE%kn%llgT7o(qt1$h-%qAmz%%HX|*lseCjJ5TI28H9LZNj z3e`7OYLnTK!@25xGFj1!S9y9{>{ZB&l;x*OyL&s{r|t%Wo1?Gscs$v)KeB2Y%$pK4 z51Cj6BTVH~R8$Q4yfR-`lmC8|t8yt|hrwa|^(o?TUZ?BsO>N%r@NkyIc5rY2{O@A^ z2@L@NH}L+;^2;ZHhy!3Waz0MT=YDu7L9>0DoC7*?=+jcl!UOmq?zs1GBMQcD&+nd_ z9vA_?dKyv|%0ClRS^HXaI=@LNjb+E4aWgliALYKmOOoUo>t@ywr;ww&kOInjTHp1V z_;i5{WH@?`6o)&zBfK0H-t)1Lbp_H`lcg61Sm69)??jA&6VYM%@4;zF?_E$jk~wb| z$@beTTH#HcQ(4fMXRWi}NwJas+wCEckZAbaT_y#Oc^&j7C@n?+!2tjm`IcMNGlXD5 zV-G*V;HNJh1Hwmeb&v!UGw$8%5?E;<`~%?jh@wloh5|B9M#Q6_(9CEcA{1={Qs;cVa-`O-)UGeSIS%BRxI6w6ruyNl9mC=fJ=~ zPft%TFE2kozXb~xI5|1R#lCM;KZNsid`k~7vcH0R+GQ`3-TSkfuNsIOok$!;Uezo~;)TSb)3(Lu;m ZRmW~$I};K|Q&3Q#si|pWW0RAUYb|NsAg z#h)yU3=H-RIt)Mn@)HAFz=8P%9y(I}CsIBJOV143<9YPpr#Vx+;`5(Z8JO+jF5{WB zCu)mpQrqcBr{oltNrzYj*qasB3T+qod>GuoRN`HP*C9J=2lWt;_2yWZf+hP z9?s3pZEI_5VqzjECueMItf{G~qM~AHX=!I?=j!U}?d`3tt36B7~=qNk@97#Nt7lOrf7`2YWZ z#h)yU3=H-RIt)Mn@)HAF;DPxC9y(I}CsHOZJorUVCx%@OK zRI<9B_VMABAm&X*#np{vtlbQX=5|tQoF*c|+AM5#TD2a^DvFHk#&Qfs-P7zH8LR<_ CmQcC? literal 0 HcmV?d00001 diff --git a/editor/default/images/blank.gif b/editor/default/images/blank.gif new file mode 100644 index 0000000000000000000000000000000000000000..35d42e808f0a8017b8d52a06be2f8fec0b466a66 GIT binary patch literal 43 scmZ?wbhEHbWMp7uXkcLY|NlP&1B2pE7Dgb&paUX6G7L;iE{qJ;0LZEa`2YX_ literal 0 HcmV?d00001 diff --git a/editor/default/images/bold.gif b/editor/default/images/bold.gif new file mode 100644 index 0000000000000000000000000000000000000000..db1da7d03cec33f9395963f00b224428f94bdbc5 GIT binary patch literal 323 zcmZ?wbhEHb6krfwxN6OinVI?J%a`TLmuF>VJ$Ue7+qP}fr%!itbIZucC@(Mf^Ybey zDT$AdU$$)7)~#E+y1E=39Fmff)YQ}(8ynZGStBDO6C4~|SXdYt8R_WgSXo&qCnpyh z8@qGo&WRHzrlzKzIddi~EX>!}ck|}WDk>_UK7Go`$MGhg@wiJ*|QffUOaW`)R>r;uq7OrTi~H1)qi4%;FHJ;vj8vpq+*r8IFEh6S-8 zPzU*3rl#u|a8E^;Lc=s59FM{@4);|0#-#pnDP@$xy;WLOCT@9xnHz9RBce+Kwt5Qb zqYyQ)OPrlt!dwerX$aVWRYEw_LEKN++p+$2-Vq_ND}cSk{7Q(=mYSMUf%PgeFUMh- zU(E@Q?x%lsBa@1tqlI?2gCE5q5)F|{CHLDms}r zpvZ8(mr;gd3VDeeMYvgIsb^B&cld1KGL5=ENP(rEn1Akd%q$J1*c#X2mKu+i=N}a! zIzFZ20PAJv=OT}GuV*mBKYq?XUWl8ELZlm*FDwU_0#m1mxi=o|o_sGRp(TI-?SD zd_1P_E+vPUG^)|4guz9X4_1bQC}udj@QOM00K(0eNM}Vrep{LA(CAf1ZG%rXYUwMqy`xmLrb1n7{Y@H|SQKCe5bZ zI#RxVclM#=q^R4<%{%B{(Wo|py*si?&%0Imetp(Shgg2Be0+^u6+a<~YuMSqXI?vX zq)d>|9Dk!es(M8hBQBMdp5B%)QL%}Y>*D5%1!ZOI9QO8@=>rkbTdJV8Rbo-3VvAtq zSVC!|_2@OkvBN#2DV)Je$ZmQJY?!yml_3`JN*4 pXs=1!w6*;4O*Y(i#hMt=av_Y`E1{|lD@K$fdT=<{|z>5yMX`z literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn001.gif b/editor/default/images/emoticon/msn001.gif new file mode 100644 index 0000000000000000000000000000000000000000..cdbd99eab299c55044f5f67635fa986f0e0e2f39 GIT binary patch literal 1056 zcmW+#Uuf4=9R2hlq~>V-q@s+kD7Eb-W(%sV;F?tC{zN3F5Q^Ju^bkEXlpbRESwRKT zLpn+&#$7`SKQ%Hd`Ul-T%vCZ1;T8nqjf&6}v4<>6;&itUT+X>4INT5CbME#X_uttw z)RLC`ElV}Fe8!extlq|!YUa$$+ou+tH|ObsxBwT-1v(X{aB5EJqPPeb%|*H-F2N;p ziLQt%aK&7qqd3CR90?H!AO;~CK?5{~hVTLpc!MW`AOOJ-2o)%x1|^~(0?`nOBuGFq zB%%lkPz;5jfB+4oifC1fsZbly2HKc5R4?kG-qcfrXn+ROKvhwNs;N?=XoN=7NKK*% znoJY5h!$uuEmTS!N@+@(hzU&0gw}{Pu*R&Rc`*<3W}X(r0xXz?s;Oha)T-E`ScFBh zNK0Y~mdp~Zh!t2dD>RA`Ml&*tWI-0o!rVx1kQ>VlvzP3Vy=BiFBnRYRIWVhaMOMqo z93@BOXgM+`$q6}GPRvDeK`xdHGbIz5mdPbM>&uO>0h>xlFZ7@{dNK$D7>t3{ZYro& zePI+vFd8G7gb7T>L>6HIi?NWbE3)}{a-O%5PmxEKX!W$N4Wd@fl_(M+(IirmNP;Aj zL@6Q#QcMbKj;iHO#0i{KLf43E;2Lucofqf9ON*0}M{A^6b6yq8P_eRFn`*QEgqFzV zwX<^F1MiJ*?)##*{lhzszqNJu;eBh~ymnP<)lIYOy6-uCtaWl|;_%Un->ux)@k-kK zT<_e$pJ#_s_r&PA4_f;Vt?zmHx?fk1cfQcxbK>r+-P&>O-1pMI7gm4kcXu6l{@&ZK zIC=BYEj|BDZM5;z?+*424sY0a+4xYu-k4uM@%!LZ*TOgb3%^~{5k@-KJUO-g><>d< zJ=1+`*C)d_ytd)dKSsL_{Bp~{NbiovUfpy4;ps1jw~c&5rKZtI_WW7Dp^@8q@>`(NC- f{m>%=M}8c>>g1Ns|2#NyZtsep&OZLcR=MkcM%xUK literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn002.gif b/editor/default/images/emoticon/msn002.gif new file mode 100644 index 0000000000000000000000000000000000000000..1cb28dfa532485afb8ce13f818d12bb6e3d582c8 GIT binary patch literal 1040 zcmW+#Z)g`p7=D{87vx%O20?Weg>dwxBFYw>PMAn!LVF9Ab%hnuhaidyBHrH&9DRtW zIU%U-S6Ew5Lx&WBIc`K2*g%Eriv=hB0Y6l%`k+$ublU^R^V}T|_wu~&ZQDM2*QO^1 zWl+w`3OcK+vr3(|>#Sh$$Hk9NEc*Z-=%e_kKEg+O6L0Db-sqF~q&~qX`Yb-H&+wVP zim&P`e5I#&swX_DA}Xo^6{-_;st)R?K{TiaXrM;Xs2ZV>YNDoUP@^W%q?(|Knnkl} zhGuFNt*RATsT8Fup`?jea|=vpPRyw}n4<-;pcY_(7R91kghiT(nVP|jmc)`;f+boO z%W4^xX;rMMRam7_T2V$A2@!}w03n>fDIDO4AP9;81R@HeA_B2_T3HH1Gb0I-A_0lW zf~?3uCaRz+Do_aus31TVks?|IMOd5^r^TT-mLMf)2`GUjN{Lz`N@Ou9ro~Wb-7D}NOqL3?bwwImIDP0p}5C&xc0~v);8NtXFH%)11xiATn zGJ%QA!mP|-CabV2D_BXk7GY_LT;lEI)8soVvSr%ZrebK}N)kyb36dyTB&%ddrc{xt zQX!RXj#}hi#EW`qg5HUD>K(kJ58{LJpXF}%U>j++Id6_tYTQ)A4HtVaSvkI?UA7-F zDAM=4@bZ5r&%VFmwewdj9JzD;gUwq{Kem1Uo|6MTlWVT(8+rWj?rqQDkA<%;oIEu; zb=jrY-1frR8%MX6{}x6%oioQDUfcWD*v)-sHov*IzweG;2DWr}iRrbY z{X=D@9C_-akzfD(dF*=}Shr3eeQ|DRcE_vl`rhH4b2|6lU)L`GU9Nv*VsFp%-TT%L zZ9MeAb4R}(zIyzV9jE(e@4x3lUBIdNqbH^wIydpk8&{tDd~*Hx#>Mf0*$=zd`eDH@}Y6%d1~rxaNcTKp(|N_-H=Tt9XT1^Gct@C-`JO(P!})KAX?< zReXi7<|{qL6Q1Tth(G`_2;l?{a0W*NK>&gw5K$0;Xo!Rg6i|Z_NsxeKNJJK7AR97K z1r?}D(622w?|xy4kdPSio2siOwb01c*r8bu>CnntRMDpXCCnnV*cnI>u$&CqO` zsa3Q>t7)ZDT2V?<(nL&PVkR^v=3vgu(Slfj1+zelVi6Y2V)L}JU~0{5Ni4yVS)ygJ z49jMjR>dl;npGOb2%{NUM2et@6=88w9E!8zSb~&*608K4C?%pqE0IN|D2iH9mLw&i zBrAy}OUWqNN@l52DoV9dStx}lv_h`O*$uFZYrqOa$yoC zFc}k>g&EAoOjcn9tFe-7EwbT|9P&}}b#i%KwoF^wAZjgKNg@f7OcEuFWJos2lqymo z)ugh`QH$J*c!8HD=$&{6@60>;AU=RMul4(bHqvZ!-W(g$xT%Kme@8m&$9vjk`w?A{ z(LaTo?s@K1|LiBDU4QtO-s}m#FnRYw=f8R>eLA?M^Ys_UUfn(Q@ju7k#oIF{ruL5f zbga`~d!)B=eD{F|F5Y*hw`<$j`#bMn9G}~MbKjxGi824g?f;#dduL+n_j7AYSC^Lk zrF`Ur)6<>R>sKB-`0K=$u|M|oULI__`uowdZ!8awd}QaI!j6S;tW9+$SBA@br+z;D z_ol(px2torGk3gr{)cJjXL|czc>2BmH&Y9}Hy^%r@@W6H-!^v#cRje%rUw&vvhP3t zuD7^(*Qrsz#fUlRy5oIK1<=5qbQ7H-q~` literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn004.gif b/editor/default/images/emoticon/msn004.gif new file mode 100644 index 0000000000000000000000000000000000000000..4d28cddb713fe3446475193aac9c24f33ea4f0ff GIT binary patch literal 1027 zcmW+#O=uoO6r4lA)FN0TdT4bk5?WR%)gq)uS(;!q7$l+(4?V0YS}61)N-rMXhkqbN zsZwYon2kka`wG%SRgB0+6imZ+sC1LVhqBg#+MJ>U#h);4GO)bah2cHs%|1GIaA^PJ z00!_EHqhBToz2o|x6TIUf0&ibb>7G;J&~wI;R%OJd0^ z(K0NHWwT7Huqsx~DvdCT(TprWffQH)i$ifzoE66sP=b_TC9p)4C?#5nEQ+F1)QYks zlq4ltNh}#9OUYI;OGT+ts+Gz@6iT5La>LHn*?~^z8X*H1guxid2u5KvMmD>tLbc`# z6PSd_n8*xfVK!#6f>l_Jm1J9yb-QGj`^Y2Y)CO&ywzUb=nz=|o5+p++GLQw?kckRZ zK{Zsi95u^5;2|E3&^vf1-kEpw0X_)-U7eZvutl0J=S{I$T5YW1-uBpj!T`|!8@Of1 zV;5(>ezpGwTlseHDgVmWYvuad#IqkyelxVb`1F%Ydk%g1()GpHeoDKa>yE7du{3t_ zt0!JKHhK2ag@M7q-S=-_KKjwlzI{m8aEdSlPrIl6V~&BMK=lNa9k%$E0e=BLk14C@2ygXi8`7@zxjZQI&P z`f*}m~H99LK*JHCG<(P|-=GE1Vx$x3u^$&U=##@J{`TV~AKm~CeBwYfcgSjuH`-f$(z4;^AK9tZCl9v&uQoD|AFumYV=5sDF3 zA|Fc@i#0Pd!yaQ(dwUlb7nOq)KA*2rsl;M&_8*6GZX8Yzvgn~u(7zuv_kZ4w`;}Jb zP3`Sz!d(~|8e)?}DAYkhmRoC%y_^?`3E54+1r!%%mKJ5!S6;}Dbg0J#HsFF9oT-MDz7Io{5|)4AJs*&NX_AiR zGGZ3^q3COFoWb(SCn?1#0eap=py1-7AZ)vBy5Rl89!gJkg#B<=qEyPmB%!!`;X7(` zUgDXibU2H0s{tD%l}cs&rbTgUb9l&gEqpukj(2wn`8LJ3CtEIAMKMYIgXK6ErOPx`#s6Z0=uO zl68&Kk3~m2rUhBIyvkB8v@u>k5->BSrno^POPjHI8do^x#mT7l?=&91f6hRnobNb9)*wyEWTZ~)n%hyOEgmfYafStBFureAVE#FoIi>IP&c2f~VT z2j(qEZO6}W8NMgAoONtSgDtryLe(>WDGe)w!MgNuULFkfX`)*KbUQAl>CS;8_Y1sF zOIS}|c9M6P+x%=1Y4qSI+!~rfbd@ALG&@^dwdp(-aSnn&Z{@`7-QA_r$-;%87l`6+D2Zmbw_rZ9k>nk(ci0{TfHe3Rxoh@m+%O_nauK? z#HOa8f}q*CQHKX@{hM9}K=;*Jq`R;4@`S80G5F0U$$E58q&6Hvw{h7$B1!i&+ldcw z)zH6Mi*WuFvF2*TYXLPt9e}Jv3ut6*a@j^WWvaU&ja*wwN;PtOVBl3( zM#(fimazf)S$@sR*V(YzmoWfV-^ACTh;c$&ay)2MNc>Y~NN7f;G9kA%T8{N@fqkt} zyH#;md>rH>)LeH9r@bv&o2-TOTy?QSPjWD>C#)Xi9HBVhmEw`(H2 literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn006.gif b/editor/default/images/emoticon/msn006.gif new file mode 100644 index 0000000000000000000000000000000000000000..4147ae7fcee167eb83b4f6af294135792d5e96a9 GIT binary patch literal 1022 zcmW+#O=uoO6nt%}NgKh&q)MQ$tzP0r#aM(&mDSePZ%~x)mHGNwu*?TjGGKBZ+2mLk9o8A%I3frF5DbBcf(S%IBvhb)8k9(a1SCTuvLFN5kcld& zKs8i?0s=IUDxys-rb2b14(d!DHHZdiFb&iw8lllNQdLx;YO2&EnxM%vQL|`tpjz{VNtnQ7 zOk@^jFdH*jg%zyEO0uoUR#wOr?jRo~UsjWyiR9@|eC6&bo9+_-i6 zgN6RH>wo)x*Q0lC-o0mdeADjk551-5r!K$c#N0@K?}quY&pRX69Y3Xm8#aA=|3h;p z2Zm=(|9j16=O&*X+If8J%-Q{43{3s{-_qmvZJB@W_B+m9n4X&WvNLoL$2t>7hM&6h zz_!lJA8**e(1G#a&%WM2_QL#Y^CxE?JHLGORp-Ax>|c6&a&hp?dnb;3bl32w6W3pR z^Ap>SZr?LF+gloZfA77gW)F=&(pmm_`bB(laO2@WdvlAMx7>7K^49*L#eE|$|McXQ r{rv6~5AJy9^oKv*{muIL_t=fI`@eeivR}4uop|QsOGnqOlU@G& z^^o-ttio$8ERI6dGzcbFiXy~V#En|Tt`XK)L=I#YJ)Ew7;BwCWz~O#4pK~8N^kDb? zC)%Z5)@7p_o2Rh}jdE*j)WRI}~4g1DeAzy-P}E~<-g zkuHnN>M~rWqd2M~9H}BIssa^iC0eOg(281%)~YqMrg~AY>Y<)$qNZw4qXyBS8lZt1 zMWbqjMrsz#su`N86s0Pmq={Hj3ruL0Sfy6MDq1a8tJScY=Ec04hk2TbnVP|j7Q}*D zfCX99G?3aB7JCXpnX1WA}GNtLDwsbZ=n)tYLgn#oJ@nmm$cGD)V% zkc=rv3Yr2^V2YBWric`ovZSmjBV{H^q9!7d8+MkLD`BOq3L$G@t*pVC^g^%npl7k0 zrZf~^7=%F?z(7V}R7Nn8S(ud>%p}W-u(U)jaW8qCJh4HGr)6y_hGMP+k)RSFff7Zc zN`yp87Rf3Zl38+8EO#PK)JY+9mAFb>1y|A4;%eo8tCN%Omq@eZyeKxIU}2>?OSAlh zc9E^6bNP<$S9g!TIM#B*HD8badh0-H>*#yx;ql3_tG0K1IN(MO9$0U=Yj%Bc+uY;q z>AmT*^Ap#1UD^E8-nGSv`-d+bpPTt(<=n{IAGP(JI<)%zbW_*q&Yp#}YV?g$jo%*_ z{Nnt`@Ez|Ap5FiG&e5iOukO0y!paA3aH?lz?Ufxz=XZ5II@G`W`IFOcJ=XeT_wvn` z%?{sp0Edt5`+54Awl8m6ymY4TNbj|OcYXKo;fwEWdGfEbx2OJh4}SjUo;{zOSZ++t zu=Cs_-wwV0)seg7Ed$Rzd+bb8|Iu%5oci?RoxRO{tu0GGJbiZj&X-#Eb^LZ=eqz_$ d>_0DG4D-v)*z(%;lP?U7ZFR0`=DKZi&;RhN3@ZQt literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn008.gif b/editor/default/images/emoticon/msn008.gif new file mode 100644 index 0000000000000000000000000000000000000000..c20b32598de5e37835b4961037633d578ded9048 GIT binary patch literal 1015 zcmW+#OK6@&6g`SE~)StNCe2*DA=;-W&tg$u#sBnO6jX5ery=bm}$nI|84 z^raqp_y?<)TsxC%WwPETS24dl|M|6*(0XVUI)sj)^Ux_6f-#r}Q-}zWA$o`k2_Z2g z4@sdQ6o%rVCN(WN{Wzph!6-1FWjy23Z4ZXpLJVYhf*|b!%lEtfO^qoy=fHGdGh(SfoX_C`+(J zOKwS4V1-uPicF|OncO4?9CWxt-oP7r>vY6#rTD7xwZlH#0Dv?^KrCL`jbx=oju1?i%8D(C5 zQG_BDT~SIH009iBM4>@w7#a_aLW|H+|E|o=p0ANs&3RRfs+3rw%{+{*Dt{ew$yi z=PztuJlDHCwRQN98}Hux#_OjCr;qHsacut1rLV^x`0mQd>l=?v-1YbP@~88MZXce$ z_4AeSKL$Jb`|?Adx`-52vSLvy>I lezAA)=J}0>cPyUa53hZ=;pn#On_l>R{M^vK^>^U${{gNd@caM( literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn009.gif b/editor/default/images/emoticon/msn009.gif new file mode 100644 index 0000000000000000000000000000000000000000..0b843dd1e4cbd74b4ceff17a36ffb9eb0f580838 GIT binary patch literal 1031 zcmW+#UuYLp82uI`DTLWJ5K^ufwY9g342lTsrHF5{Lez(f zTz|m0Gc?)v5SXi{l3_>`81DwGTK@fmo2t*V_AQ~c}0tM8dL=q$*84{5N8OVlA zR6zx*p%N4jpn+5oZE7(UsuOikXX>ayG(dxCphnRMji!;Rq6$@0r6$n?O{R&OMKd&; zW@;6!&}v$#ls1&olr#|&n3xI8i8+`vbF?59V8JZVqF97Qv)D9kESOpoTM|pKWR_@I zEW@%{rd6>Dt7er(F~Vp@7Lg(-VntY-6o=xhIF=wKpad&{B}$1X(Mn`dDT<<2lqE?? zD9K7<$x<>(wvt(@l!{WVR2E7h3ayY!cDBw==s?#98H520#z0141fwys*-Zu2nlDVk z1SVr5voM3%n8_-vU^P~fZACUaOV09cazFXr5^bKgwL#RHxspT@B$*^i7Riuok||ZB zLaIq+%Tcr3i+F*TM(CY*2k*=~`XD}l|1C~Vo@$Y1%Xw2QmsT5VxT8I`pU^9E-GXrC zx&y0!{J8V=TpI6=K74%b*}eX;>rXzraNF}6FL%1@cD(Y# zzzx$!zUy4OYU`V2_~?~uRxVt+t9$W*e$GE}>)F>g^ld&iv}WtyyEh%!II!ZzFJ3*< z>AN~M_|WO2d%k_`k<Jd_F|}Ae-}%Qge)OY-sh8hAe0+NJ;O~bn{<`bTaA)Ap?w8;1dT#yslf$c? zTJiYqpU;iI(=$5P#isKwe)GY7Glv&1>(q|F9=+w=&W5?n2jAMVv;WYso*udXe;5G) AF8}}l literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn010.gif b/editor/default/images/emoticon/msn010.gif new file mode 100644 index 0000000000000000000000000000000000000000..0188685b9b275e7ca9ea41aced813bdec0ffd7d9 GIT binary patch literal 3531 zcmbW3X;{)}+r|Mw!4=okw9wGhP|?hBp%hV)bj*FL47bwKDa#tIrbKf|EteLpsSz>F zZHiGVTLsO+W!xFp64X@8Jva0ZJlONR$273t#Qf1Qp+;_Ox=JrovE4)7ep4*QHbqV8&B4 z;gner=I6Sf4)G-~|9{Gki92sQJ?P%RPc2BEQ$}bB&pZ>jI2> z4Zb}um<_DTJ2Lym@XK4`Z0mV|=bdrv1b?hnZ)*G2kd%A}`O6FLyiimz(g{faQfL_9J5vhY;#>f2qypkLx(W z7)h`g1Wft7u3-Z_-;F`1Sf9&+CGyh@gSl5`(LqK0Ire17L4dul|CY&0FOkPC|JsRX zC0kVAKDaUNy7<;?rupZY+MR->qk@H?R+`P~J9EJo_sW2Mz@I+|KD&%OvtO7Q*%%?N z4Upax1`EeXW!GKiS+>BG-_i&3x&D&5M#quP3igMRrUIL^b6JxwokpJSo9X#=xcT0P zk6)+yx&$+UOHAzge6MgRl)t*zSE4`6ej^&)ztmvCXWIfJ9t-cS*PC`1T`?ReH*BZw z9HZ+C#}5D#E)(r;Lyt|%6Ft{wql7}?z+E$7F+%t`V3l+D(`&olx{S));Dv$6wl|NP zDvtu=9`&WTm1c{LA(z%FeAf#iv*PmH)X+jF<;yd@$u`%{=QlS#IxRGq3EF;WFEE_$ zs{jC@aNJYCaRcTLEr01;?XW6JFj{T0-k9|rZ`v;$_xSS4lvjnGuiG_MgWhPd6fA{u zm=_8tH^w?>W9_t)K3RE}uC8_4uxc{9$|7D}4=BIkBKmf8L^5tp-d+T}yOX&IRsswH zfpqv#m&lsa+)p=<`rr$)9=0`Chwj*QDe3s~;^6>xtt$Ef~BEPlR0@JmqK#BSq$fO&85f^g`g1nz zR$T0(8^8BHL-oYC?_gPb>@e9l5zNd<8h&!+BEv}wp%fi>CVwP{C(j+0Z+6am49isu z)cdrybq{sA(|n@-wQB{fI8)7-Vg!F^cFJG<)QcuRohPuM8)~+BYKRyZN!59PLD*(Y zslk3ASoEEhwyFU}+*ICn7KSxs)B!uI`T!`BTb3B{(NMNmDfZTWrNMQBS{K{8M= z^iGno(&4picRBTLCPK@A;Vi2P#mYE}p#LBb69-#f9PQg6F?jsbMr{T{s~f3^E*P5dwDR(9FZ70T=RzR{KK?f9Te=D)GBy zYqPcdKiu&!gtV+J9p?={wzCxRPL%c()KN~zj!1aql;J}~vi^8~c2{ANMu|Vzte#_* ze_Y`w?9BvHV@i@5hWhiCV9DJh>$3^wSy_^YnewonkFN= z(;OCMMi{0?@5J&`OQdlbq9Egd-1pgqr?P1YKvk*hU5MxyV;)u&Ug0ajL{4+Tv|<8u zD`1O7an15lV}+xu69smv=#*p~7Aje@SR{+#>}bokRzktdHNuE)Ns^ZJ!olo>th(wG zuw4EYNeKMVEm+Yl(W6^h{-t_yyvON1^)eQxin)4*OrK-t-k z?5;>K)u*|I+`1CUO}jybJ}#;9>t6T}fAypfK_z<)HeC+d+8o)zAO>9(t_hvgzcY6e zto%1~1h~A zlK}bBch697?AxGpt1cW9(_5ghB6uBk629u&8sg!uDTcoGnb^(LVMUhtBnG;OftOM1 z__}VIq!AM)`ak~3?-x-WMTDlJ&OO?y4@El0wOFLTuS7zOpt#zL8$hd&cF{8#-_`%ujX{>D<1=wJca7G2RlkfRd&m4_*qO!*N#5 z`B(|B7uvObH-ER;gPTMy|HLV>MMmRGN2$c@voxYNW%WriY`=WSpv^tyylAv@O=MGW z`u-AIys+`S`}onjqk*VM#kKL_Qm`m@%HXU?>no$c=7@kGW`UjN*OX-ZLW$-@)#*Ua z=ZMa3+bmttV^kT0v=uj919_T1`o>P~;-dsYi|MQ**F|2>y90kkcD=~KP?|$=Lm20G zX*q(y-^cME>;1d!BVO-^?l~sh{NnO(?|u7tYx-v$Ir#twrCJVAfs!3iyGNzA(LoIY zatq3yK+DKtuvO?>6#bemhy{W_Kuk97!W;o)ZMj**tA1ANq(*$~uRWJlx^gCwE}hAj z9|JGeWAS&k(nB^13(rDe)&T+_e4%$PQJEAou@Z{9nw06D&~XDcHkQG;yg)SY4|U9< zSJb0_$*G#1%F-aK8wRgVHOi1oo8RPirLv%?6q9143PFOl*Yn+LC4y#4t%7|bwy#*< z4d(DNjm)ct%H+fxNf|qa%u-Uf1V_a2%(zL*2trql**hFeUFX3uzL)KMg8~v2-c?~b zs_lCt5YvFb6Sm7Go!aebmD*SWIhc6uU5pEkUrbHWB+F(KV4*lP6M^n9OF+@#N>W=N z^ehe>4a~Qqou@0t}os;coxGaxQg9$`#kB_)cnwn6rh&-!&>wT%#290;=+{3m`B= z?U_Svgh6&nCI$k%ioS+=D4`JG9E&XFwz2Xd5wut;K}y?K=$+jh>Tsm)k-~v}Gmj() zuSk~eL-Ax<0jTsg68C$j0zv&~<*lBy6At!0xy;1qa5WvKg2aExk6S6Jy0`NN_AjAsISu=YdO9Jfp!jzxXleEm@w)F+(LVMxIow325=-$Ot_Qs9yD(1{4HF>!jC4pG O)vI1n6+J0NZ2K=@_G7C6 literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn011.gif b/editor/default/images/emoticon/msn011.gif new file mode 100644 index 0000000000000000000000000000000000000000..e3548aeb19451e9e55f740d60ae803341e234711 GIT binary patch literal 1047 zcmW+#UuYLp82uU|ie`T{Uk39+lWDhJ%pPn7H~h0mbk){DeY%)?6Dy3QX`BXDRG}7xKBc>9@d}?5>9tJaQV)?aQHsXckWY95AAyFShsY` zZCSy@>X}$A6YVy!f`wlfW`A7r!F-^P;v;-CAL&)R!mD|uPvR4NGN0(P_za)TXZk9> z!dLT^p5h5l^CUzdfEa{u0tYyQBZ43R!4QZjh(I(%LInz_L5Ut38!U#rVWV4$Jsx@Djgb7T> zL}p;U7^j>wl;`bGgp#Gf+Ukf$s!q&O){m5R7f?c zY&mL{dl4`2(g?j1@8F$zM<2uo@V})C7cR9(v*o-gR!ggmH9XuN+fV2gS$9XczBBs6 z)WWH*#qp7Mmg2TullMN_Gw+ADobLJK=<=zrrv2b2Yx+8)>xZ|DcJtQt7w_voKRE6m zyfgDq_w4W++i!KQE+v2d#GBJkez*1c`Qg3KmFvgHw)S0|dH3$)k8J$@^6=T;_C7K8 z`=R+`Ls$3rt$nZm%Eh6%*^hc(8JqiH-M78_{<<-RZ}{xB#UpPWIy~^tK+j9dH`aC^ zIC#$s`#;+~d1mg+wwtH>myZry9$CEf@8E}<-X9*nf5XPVH~d+rM|SSmH}5|_e5LD) zpLe`{b87p6Ja}^E)y+TMwdc#;UuIwbdKBkQKG1t^%sXd;K7i^!?)ReFud=~@MRvK_vX2Mdv{D6 z8rZ;Y+Dc5XuIbe@-FDL}vGC`@xr^6B&(JGG3lSkQL=p)ynjSrCF4B$&YfBTVQF9ncY-&>MQ7Cwd_oA`povxWNG@Tu6olBq9mfkbz8O zp&BYsi7Ln-K!oIG-rPnvd1v0iJ9;PY&3kxH@8!`v!XrJ(-Q3|$cX={T@I+7YY@Xqn zp5@iN!YjSXWvwU|U7{HcG}6S**nu6{iM_E0d$Jd!F@lkd&C|*Poz2W-Okg6Dn2j0C zWEQKjf|abIi~>bU#jF^Lv6xC{r9 zqlP?~1w*hV6gmqXLdVc4^cH&P*7dVz=h{fC&3SXIrk0y(v1NJaww2?D+hzL^1GAAv zcI}_AOe1CNFBl~~<^{$_1-hKYa`e#}8%zXXX=2sqgeDuAK*DRkN z`|;bd?-QN6XWKhVliis$JFjdXUiZzy#<^$y`)9BiPYyqM?~VCmZy!84Hud8Cy1}^< zckh`!`ohHC*ALE&9Xj^K(v@pRPK|9idSJuxzuq`AJ~Db^WUzJDZ<}y_`B`jo>qqSA{{bry@OA(I literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn013.gif b/editor/default/images/emoticon/msn013.gif new file mode 100644 index 0000000000000000000000000000000000000000..baf46d2580a731b7af7246d778ca121be141d825 GIT binary patch literal 1078 zcmW+#TZj-u6upsID_X&>3nDT2BRVM&=GH1Wm8&8N<+8^VgGo#)`w2-RbiG^9CKB4m zDi+1;<^#L6VHn{@F!s@dZNok$XiXSD@~^-Mu~0kBdSEzbW;o2{+&k;muYIg{Tc>o& zb(zM{?KO0phT3ju8s{&aKQ(dH2lIhGijVNoe56cEZffmIgESkmUX=TCGn%RQ>MGqQ*jK@ls$;-okfXT`AuDFG!|2`o`cM2S`+i%L-xwW2IZNfHQl(UsYNfJJ3Q=fQL;#eWRpy(A{A0i zD%%{j$i0Xccxi&(iFfeMyrU1|19;===;(eW_`S9`I!YzEPS(n>E5+}ZCTv4=(*mTuitmE@8t`RZ<;*2Vf*Tr zPR<+}=^1}|^kDbc@_pS0)~ELd{}{WxdgIix{yWpP1wY*V!l-t@YvhK=SttP ziQzdn=3YGW;NDLTjgN2cIr7EVqkYS|4(yueSDZio^Tw|}dv)=S!TV?Tt>3rB@0j>t v7j{mKecFF||Fi4XQ)`Y5Twk^I(Vo{%+Tj}m3+Kt14@VuqS_uKIOKlf7O);x1 zD)^}godB(i>Qk(j*}c1?wNtZy_|dI>1X%vee|^< z8Iu2G9kUx}cB9O;+w3}4ep@-Sdff-}fj)|l@X>svSMdt3=9NB)Pw>fnqR-+pd^Vry ztN03E%~yJgCp^uQ5P<+<5W)!@;0%rkf&c_VAfg}w(GUq0D4+%udhRj8UOHHju@GELMhnxWY= zQ>$o&R?|wQw4s!yq=}fo#7t;T%)y+QqXn@53ub{9#Ud=4#inUv!PJ`Al30QzvqZ~c z8J5j5t%_AxHLEm=5k@nzh!jB)E5hQWI232au>>grC0Ge8QA$LKRw9c^Q53bJEJ;d2 zNmdd|mXcAjmCRD5RFrC^vQP?9XoXz2vvqbt2f9YcAPitI1~LjG7>$w5ZYrqOd|?tM zFc}k>g&EAoOjcn9tFe-7E3$r{>~jzK2KmW4ZJxHZLDZVLl0*_DnIuXU$&hT4DOIFG zs!3(bQM25Oc!8Hj=$&{6@60>;AU=RMulIV3Ez)c`Z;Fl5YGVz%+GG0(Ln2$R2|M>a z^L6jX6Z5xq_Px_RzH|E5GfU?$zWu;0)7^CL=={R)lLP(J&mWt=amo(gKR7(T`O=kd zUb=W{Y4_NRCm)~Nd1Twd)rk*(8K3LEe8=MI>7PH{|KP;nzVYrO_;TUi_vS~3=O(AR zPYvz8u(oUF?xmTrlfPg2Vq|dhwxj>7u6;f*`PsQ2&X>!h4}Uv#_}JLlH`l)E?AZF; z%_CNW~{{tH;^#1?= literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn015.gif b/editor/default/images/emoticon/msn015.gif new file mode 100644 index 0000000000000000000000000000000000000000..0813a4f2bf02bef01adb07e398f42459b12afd90 GIT binary patch literal 1026 zcmW+#Ply*p7=2;(+d|7)GKr;0=uo31Qim-M)6b3mkf4I!Wrc=1C>UL$L)#v{pPquY zSSU#moNbH9?~t$*bl7!%g?lJB2pT~o8a<_w>`E+KR=j5S!SKBqczhr4d-LMUFAP8P z+8_q8f>rd^PH(OB+O4;W{;&Nneq8dwe4vl;QG7HX=@nkZt9hkQ@JW0!pXf7u7N5;$ z`U+pgSM!yg@Dxw;qyPdDn1JFSPQ;lwN`M5BU=k=15=Ej(q$os1)I=!>l0=e8qGU)G z$tIanAyuTBR0<&!p$VygHZ@E^bx`f)Ci5D(KJ#Os-kMD)C5hU$uvc}_Os&u=T1_jJXhSJYNdpXGFayoOoR~9nv;YfY!7R`sEQ&?5*feb{F|{VP1WRJc zEYUJ7i)FJ+tFS6o%_@yBiqVWLK!Frk0gFR%Qk)gX5>SGaU?s3blqe-yi7bkuQq+pF zB$Om2SxGDzB}>UxGD}6NQmU28LKI4&6>`?I#QZ1HXfJ z5B;@xdTV!O!2f&r+HZ5~j&1t#_Tk0;?xQPz{5SIGwch3(k8FGL!19fH^qtPovwOz& zPJTZ=Fg=fb^OK)$>AZDr=B1@qC$rezIH--o9|??=xdx r@57xN<%d%<_gzo>@9m!({`r;To0ms%>8J54b63y5zl{%V!mj@TOjrZ5 literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn016.gif b/editor/default/images/emoticon/msn016.gif new file mode 100644 index 0000000000000000000000000000000000000000..f187c63dd583ff48b8469e927684daaa695024d5 GIT binary patch literal 953 zcmW+#O=y@!6dY?si$#LDG#dI?}7(^4lgK*P*Id3 zdXSA!ROTe&RW_F()}lGAP$aO$W4+{}qJrZl1Ix_rGVEjC+eaUN|!?!nzU#K z5W@`x91~(n6B8Cj7Xfe1z@!ch=~Q53~d5tUID)zJ~1(G}fcjH1E{ zTYx}8f;B-CHA#~-Lo+o?vz4JtWhoEOD2oaWvkFwGA{DDbm8w#;I@GByb<2<`OLhYq z*q{ct32kDV)F!tXZDyO*X19!%*|J)83$$PhwQwtFg{`O+w~AKTs#=>12RhM(?lDIr@&qI>VF;%QX=0j`CZ`!` zrvKepUq3%a+GEa#V~++8HE_${`>)zPzI$AbAF&8r_c456`LVCpAAalD4a>)0-8ywH z9eZy3g=e=;9X|cq<;~UA508BI&?{KJeCg!+!8=c$*}m zf3y9zarWwKR}S5J=*s5xKfm$L!lBn+{NT*lcmFuZ#Y^WtKXP>C{cp~Hb^Gs6Ui182 zhoAW6%bzZMwD0Yur%rso@awl)c>2JPJ9oVK%>DhpoBug_Q~vHxUAbpz0T2EU(E8J> literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn017.gif b/editor/default/images/emoticon/msn017.gif new file mode 100644 index 0000000000000000000000000000000000000000..ccbb0758a98d66cade28466f891c285f9707053d GIT binary patch literal 1031 zcmW+#O=uoO6r85Tv^GUFnkF{MT1zn98h;QzqJnD+YI>1C`=EMok(ypCdQpfL`%=5gJ9KX{0JtMb%WP37SNcX`*Im z7R{!aTA@|6npP^&hEkf61{lO(2AYF8F=ysz0T#r9S)fH&6pLoDY1&v~YE5hjmc)`- zqGebX%VwEYVO6Y}RT^OwqZwI%0x7Tp7Kh@bI4h1NpadzwN??g7QA)HDSrkR3s1;>N zC`n4Pl2|fImXfVxmWooPR4bK*D3n4g96YtDB`T!q<|E_ks=USxMa^4ghrPan7?ro3lC-ehbe+Rb> zPfdS&YV(b){_x5AKQ}u5>hR?B zU4t+8OgwUNa`o;X-aEQ~{*Kw9_m`G;PIQK+Mtb2OB=(oK+15VEqnB@nl447W+S=Sn znsi?L$*b-bwKb;f!=;qEFFe=>tx_xx$DKKKJLlfp>3*H>yGI^B{J_Ci7O{xGv4@TQ zwXshdW4Ez~v%j3(-np2vQg)h=W~Nzbb_%3m3Z-x=NQJ2=6{m_+nW|EC>PVfbD|II$ znaN5v0fK}Ga{?!F5+^f*napA~XK*HGaW(@CGQ=`LNO{(i7Hg11D)tX_n4y*c>)rcFoe^DG%-y|lT${@ z^nVw(wmuyr?J?)Wu}_1C8aQz2ip%zn?;e-qM=Syhr{Jqr9{XZz^{vf+S6=$(^B=xk z-@Ik%>zhyf{ME6AJ8yXC{J9sV)#WRfcRsjq^zf;LlfOQ)ar=>L?|FOarxR=6p5Ixy z=8x5P){Y(c{-c9$JbLe|cWr;Sbl>}LUVZ7Qcb9H`?!A*Y{?&eec>Cy?<3GOs^e4}( sE}VH{{j=Xb*7MJvyY0yruiN})>9s?5tbO?BO_v{f`SgYLvvE`=}lVgfz%2>ONE#kzP6O+>yLi7+7dW4>#_s}aCf-#r}Q%DGjA$dp&86h)d4_Toi zREFxIDhNRg@*oi)NH`&OU`KY&PK;nAqce&<*pt1p7Y#JhoF*nPk;$3F3}!Mrvsl4O zR%aCjij-3_z?vFvkae(**12`E2#d7n7G*uGr}b{V%wR?{H~A-pM08(xZEn_wb(HyZ24g#-f`yu_t(s5mgps_^e8<`@1<8U6k{F2Ub0F>sVvn?RS}9<lD3_hP2 z8uoKvj_e8JSNvS&F7DcRc+(em&rffeF00p1y)ZZZ>c+vUEi-H87ruIZ*@4}AcD{J< z*WdOYx2yJV{r98ySKhS#(~L8tM`x2o_b;xcP`v` z@x5CPzkKEKg=4!`+&cO8$LAO3Km2aVq08=n?Vd=ne;|o6y zulr`h^UH?9=*Aw{PwHb8vR=Guuy&zjW^VPrm;9 g_MaZvcYei=M@JrC`NPqrHw@mKy6)MDB};J6|H`uk5dZ)H literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn020.gif b/editor/default/images/emoticon/msn020.gif new file mode 100644 index 0000000000000000000000000000000000000000..4808bb4c0ae00f26e5d73d1b9925e220ad5e2e14 GIT binary patch literal 975 zcmW+#O=uoO6dWXAS`i9K6+v8tN?;YWrU$Ljt;L@z5d(2fQkNboIeKUW>ET6+^x#Q? zU`5%WCF&EkR6U4?ZBRVOchdEsD0@**kP<9KsK~g|ky8tnHSyaa-HLrC%;>ezzTy$E27MGh_Cc6%ElC&7&z6#KKrS7R8EK8LP*t*bzHp z_t+JMC`Ngd2oNNk5Ca&<;0$5{6PcVz%wQ(7Gm8cqX-*RhSjgfmVg)N%omK2$C%dzY z0!7Lx8DK*VH^>4k(1Kf#C0L>*w2S(284;Ram7}w<_zfPU~)6 zCXAs>Zju8II@}=-@IVjlL7w1=p4^i>!!td*=b;&6(ane03%t;ady!XorC0YV@9<9V z?p-dp=yI1D(7*<7Pzz{*EqDuR2`#ZDZ%HkqWwz`ss~MWHnKx4_XoanKD{2+3vQ=+Y zt)q3e?yai{O>FWe?btaw2PjZs5Gg^4O0FbjC{x*$HSCsA=ED~is8GdKqzYB4x~kNn zPIXt8G*;x3i8Rr?^n!G5hYnB2+6ePuE(%bH;wVA|Dp4I(=s+jBqif`7SRR20Mhv1D z5CdcI7!(s?qW<09*f>8Tt&#Jg*e#Ku3f$O!@Z}c-@Wm@sYA<~4{P7_ z-e*sp=jpGPp8xCAk)^GrL#zKi`r$`^JoL!E8{Yc++@3o&7p}j2%h8o*W{)qfUjB9Y fi>3WP9e!o|?%88czj6E2%X9YjKPZ2tYg80)M1Vt|j8ujr0MDXBO zDN@i&H;2;0Lr_FPuw@hQix3dY9t2x9mts*cRV+b-j++cDGrP;Mk9lv8Jn`854?H)C zNo-&fqpdaCqEX+CHnDVJ>CDQNm^>!M0dZg)JPwM6XpH936fAK#3}kQyF@cFp&Lj@tKn~79G|)(MnwY^%W@i=)SjgfmVgno5 zoJ|xcQclSL>u$I~7GQxE+=48@5-qtU*#H}8gWDi8n97 zgEx9}Z*sv!m%CJf3RZZ9YCsLF!D~=WsEIXsO{xRxz&dyxR1MWw&8w+q)XbW_X4QgP zSc})9+E5#7^V(E}Dpq-wHskCs2PjaX3n@W~O0Fag&_E5YK|O96W!`g9hBB31St?MW zimONsYE*MINxenBx+<;ep!B@-$)@a?_O=n`JzQiU6WNi40u-V+iqL>YG)GgPqaJw# zA{fzyVn7Ux!DCQNh>7~|%HrbbKGN!Q-W^-ixvP#l{vF%4d3;a5>_1`>7+-~U-TL_F zi_35CxZ$?5udgjGPW?48H8Zh3dUR~JzWQZ;oy*&&*Ixeg&=)(-y?N}u8)s&ZKQl9b z;P>TM_x?RvIk|J};y1rN`E1^E^~(!4kFTG4@U7{6yWc-?^yI_9*dyF`@SSfLuKu~} zrEN=RJWkJz-}&RwKUPj`tX;ZmerfJ{Okdmk?$3Kp&n`TD%lEVM_g;5)e)`3a?>_w6 z;yK&6{N2}w{s{})4~*S@?a0Qd{l|Cydj5muWAE)B`{<@uK78uZXm)jcho67rrxz~Q N&*px3Xleq7{|A&y@JIjv literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn022.gif b/editor/default/images/emoticon/msn022.gif new file mode 100644 index 0000000000000000000000000000000000000000..834ca31d3d832f1ba1fa139abd2fa54fe3ee28f4 GIT binary patch literal 1016 zcmW+#O=y@!6nttM1F5z)YJ(I$>8;ybL=S37mZ~(^R0Lr>NcF>CEP{e3rPP<86paW0 zkszWQYmIfpgW4WS(XGW(jQF<)6Vw$fcoGW5Y7{zdGO)bah2cHs%}(6C_tx7U9=2io z+tx6(ex}yTRJ%>B;mprx78cKk$Pg8J3q3;5&?~qFM{ovLNEQ-8Vn_L;X*PbAQ4H(h74pP3)N78 zN>o7x0U{(f^QJbs$vg87-qAaGG>`B|kMiEUhxhbe?&c16y33P!f+u>CXY<^enID z6<+C8E^9-%=n~Cnpphna#t!VrPK?F~Mly=Mu?KsyZ<;n1=xkypV*(SI#B9u9CbL+L z6|7_xWfUkHMblua4R zRFU}n?KAF%V~!y^NWtIw`1zOi@X^5l$7kL|hr?eUWz@aR|? zn7rrpg_8>$KXPe#^rt_TZ<*btQ`|9l^o|XO@B8z_w&ROqr{gu-x9t9S^Mf0{f8o-j zBljPx(-#MhKl0X1pUjV3dG%LY&RrON>`>YI>*=}Q9vZsysgJHdaOm5~%fC5z-L5a@ aPVE_b^;2K@di(FsJiUy|wrv`;-TwpDvG~XU literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn023.gif b/editor/default/images/emoticon/msn023.gif new file mode 100644 index 0000000000000000000000000000000000000000..1c75a640a2e6b9c39502b919c68912520d7bf482 GIT binary patch literal 977 zcmW+#J%}De6r5Z>Gzk_-4x)v)hzhbs8v{`+HiC%>YN0sBB4iOfV|hdj$_ekhLIfLa z1RM7wniNkIVj;o5{i2S*+LJ*pg9Y3sK~f?1Ix_rGVEjC+lP-Gx$pjG<}r^A zY+`w9EpO5C*e!2jc6oOGoAsDHCdG`H8MDW%Xo$vW9!;?z7RKVSC|1PESUpz7j@TKy z$F3+uG0LMvfFR+77{EXVXAl#Z$mC371~ZwRSv1f{bDCJdLKbHcD_F_utYQZ{*_~Y! zC{j+z02^+&K^9uzZa&Oj;Duh?i@d@sy}DOCfBW@XGK5|ik3RPT1s!*k>t4bZ} zRCjerqeZ^DDy`~X={f10O*t|hZ6nM_xF|p&ilYb>s6=&Cp#z=hj;=9BBk~ADFk%SB zfEXBq$Do)H6ZP- zzTZ9f+REg`Pfz_k+xFIheD0OCwY3kHuD@aD-Opcr_ld)MK6&}i(}#AiyfJt6jzhEQ zgKzus3%efu?c8-wUzmhjF5bBB_u27dKkZvRGyU+gE$(^fv%40bI`QR8SLTl3$FnCU d`}4vJcW(Up_0r1c7ax0ldU|0x**=E{{s-{&#cHG68Gr~4cxSF z69n@i(a(v%g$p5NEECHN62^^KQ<%_7UMq$ENtOlG1<4){=m4tanF^FR;s1W)FPp5z&x%`-jA9q#5%cX@#q^FlB33a{psUgaI$ z%{#rzg)x+iE)gJ%ARz`Y7y}u^1SVr5lbFG5%w!&#F_zIe#4KPj7P5#Htj0=Kv4h>% z$u0_%QKZy>25Vr0T0jfd0$Wf^Xvtb)OKKS{Tgz-&&C%SNv$<=K*1CSkrI?liAqw2vMEzp!*03BIebxpim6aVs!%mms!AQ| zrcQN9V@14pQM#zdq_?F{R_O3_tj*vY=Ar<_P>3Q_pc*Psg${H>C%Q(ChUF26u!unv z17ffk7=vO$Os4;qCzH=cq&0Fr6t~K#gAF`59>-6Z0oHyGP2DqheDdAFgQvDWGr#T6 zuXne-n~$I0HJKc~v}W_{a@=$7$i1iUe&2rCbZ%+y_UCp^eRJ&G;oGNwyY}~nHy_{F z-Z-`Wr)}5I7T&o0+P@2TJ+UzL;iIeHJ9>pX4&FGuWqy7#S-pPWmXlw+b!>M3)byu2 z@B8wdbq{U0dZ#!`QKs&K@?&F(Bet&+?^t*p; v-2H1gyL58XuIrcocwon&=^sAYH@kk-!ozxD|Bsg*xwdrwD>LiX;_3eZI8*97 literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn025.gif b/editor/default/images/emoticon/msn025.gif new file mode 100644 index 0000000000000000000000000000000000000000..0da3b10f5789e2eeba10e6fbc11933a88ddd84aa GIT binary patch literal 980 zcmW+#L5LPa7=4w3mBi|r?#9AY5X6)jWne^%%WtdQ3VIPG49OPKxuCjy%hsi>g@S^D zXhcHt3$hMff*1{i_}N3koFba&<{>abqoQ83`(Su)W_ZlU`@T8)_|l<=pP$7n{=_C$ zw${oPt&H8uCeHtK{>=1BOdgYBM$C-aV^%aoV>FMZSP%iCNYDV%+4$tXrwt!EMOsvvxpU}WOY`tgPrWoE(#PW zr(}Q)H{2i#us{oLL6%^NmfVso!!j+qWtqW@W^N`cutFp+sDMOjcuB;Kaj4~g&s6d4(t|C>aQq@(Z4t1)# zx}?z}-`J2g^q};j^wFjqnU1y*<|AAbpb*7TgbGxmI;zltPIO1tn4=MS1R@wQgknGp zjKO12Oo)m4=gO&5pN^5%nDgP-qQOHA-0|18>o$+?9hc)r%mO>Uf^J+m_Qbn8_g~u) zkAHUYu}A06?Y?h$ZgOF9+w8s{zx?ΠHi~Z-431iOJH<`{pKV?apIwufDqa)E5We zJiNGb@_^P4?)mNKZ{Lq!KeKDk@BDsp=#}aH%jYg1Ik5Wd^uycUIJtD-^Z%awGjvI9>06;wO_FM g&GoxJ{`c>z$RAvqIkLWX`|0VKYimoBg&92ZKk6mi%K!iX literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn026.gif b/editor/default/images/emoticon/msn026.gif new file mode 100644 index 0000000000000000000000000000000000000000..160f6a22f374f4aa923a41f52dcd44d2b0f44b05 GIT binary patch literal 1055 zcmW+#PiWpn6nvCK(h6!w&>n?Pll3;aQS-mfU;6R3^X5EV5EtNrxj?7l6i&@4T@)ALqPa+y#3i_7 zF3}Zn1+JJYbQDK8nj;|s0mL9gBWQre&=6kW0dMd`5Ck9?0-*v0)SyHZL?9X>kpu}y zhC~!W0g9mz6cC_+R1vLeF%@bf+CUrAhU!H<)SG&05Dm~^8mKC&P&HL*6phem8mUP% zL6d2s7SRGNriDtWLn%#36ET5_na~=s2G*E0G%x01-ptd2SbznyP&IWdm|7KE6pOHE z7HLT=!ID{`6|n*4hHjMo$J|0E02G+D!%3 zsxOSf2u5QhlQ4nFn8+e5U@;bwbw#$gNG@_W`6hW`gH})L+8}DxT!|tP5=|l{i6lre zNt7Z|AjPDx=BQfkM4Z4$C3KCr2CgyJ(0Oql{P%XdJzXQsn)9mIgo>5b8m!Iw6Z%AY zYG><%YF`}$|5yZ7&S{^r8ymjnNu zymNWF^YH_(bh{aM@!(rOudf|`@7>?h=$)>kAAEcLX#3pKmaVI2mXCHm9p+!Z@A_eU z*ZAOxbE^;CDu>TZobOpVIeg>U>E-qI_P75$a)1A!e+KV9yR!48ohOzqt?X`}o!#5{ z@amz3M@}zX-Tuk7Yp2#$kBoLcdvs)Ixb^huvEIHv4jg~SUc9o}{r*HRV%OK}uRVj~ z18#X~{k!$C{?_cCD|hXmyR~}ZjXiU0y*xBBV?Uj09osk1`sP?`%g9H=Gne~6ADkH8 W(X;K zAZBCqgjUg=fd;oZE` zyIdGUx#$uB!Uz�E01*K}=vWCNhZ`%*IUSp&4TtokPq57GoicSix$nWEDHujh*bG zKp90!4QQ|iHmC)(U@fo(wS<k6|`cluobn6R;^XGs@BoE zwa(VngeGfZleX;~odXn1VGt=n$&{!hWhk36l{M^^o1DWJ6{wgBRip}4Q>CiZp>FC_ zmo!$y%}r@jd!^T;kGJXYbga$b9Oj|`#ZZVMRG=CvQH2h4LnpdMj)vtCh_Hx36a!+g z7#M?MLQJOrwpLbFN2E1!J`_7;)WHV!jK}d4Ccw-k=$q#j;;D6?nZ(0i#8dYl-_)w#!h`RRw_SN5#ka{ko?u3q({$4+lt`|iW(M=xXUjyImU zF@2B!{xMzp?ZVX;kM860&B^)oTbIs!{??n9cE7uN_ow$gI{W?g2cCHQ(AtSlZa=+u z|2yY)PyhZaUYuV&aOmvo*PeZUer?}pC$2v<{c--mT{A!be%HyB$4}mN&yjDB%)YdI VbN0(8x0b(N_`oi{aOVsj`5!iRacyO7BdV9LKyiP98x0Kh5QA0hGYcVn zv53;AtFl^rFtW9WF=BVK$;Y{5vmjcnHSpRRxQ-J0{}JY5Y}i>uAmbPA{9)SS`}Kii_qV zU53lzvbju0IEte=QUHMnOhBn1l}Ke$Q9Q(pcoR>lA+<3N<%B-S!m>2VAo>s$ZvD&OInlhG{S`k}- z1+icjXb~30qFJP6SQg7>nMN4JXhtR=K@u#1sY0qGRhB9ykK`qJOP;AlswLHyY9>We zNoq-%0#c9^ECr^B6eUGVktri(N!e0nA`&Ih61iz-dAR~BVO0p}K`-=1Pu5^9tc^8` z-Bh7k@r3~l!e9(!1fwt-BbmW0%*ITztjHD@$wlrbPm)ucw0K(9CQvKpA^<@U41tJ1 z6huQLGLQw?kXdq6EO&r|I21xx!Byfaa}}M3^TL1Erl-%BNVDX;D7K(rVWsw!X88%N zKvU`L*mGoV`o_E4r&i`~?ri_6e{%Top|Kq+kMuV^+_nG2vE|;AO%uN#KK;_J?T!CT z46dFy*3tdp-5;#1_MTdP^7*U7Q-|-rIDKE|!Qp*Ny+@a42PQB7@YplAwvE0rKKp3j z+40+7eBQU`>y}@8CO#gVId^BZV|{sUaBSy+xsC6i8ts~SW3ca|Hf!H~t-IsMFPAS) zHqM;+`O@Gw;|&iUcX$4p|Kxl_=jr$NUb*n{tp^6KE({Hxb|uf4*d_8pb9wv literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn029.gif b/editor/default/images/emoticon/msn029.gif new file mode 100644 index 0000000000000000000000000000000000000000..cc4cec40a862e7fc838bf4cd075af3900d6cbb7f GIT binary patch literal 968 zcmW+#-HR7Q6g{>`DiqW&q%@q09%9hGg>9pzrQEdFI95-?N(p^I6o$~l-Bk$t2Ow@MeJg6;8WxFQM0)8#`r%6-`*51w1H(NtaJZLq&%AnUY5uw82`2a(TUgmX zE8Asd+*Y=*_WRnUpJy?7Oo|yXGiHxj(GZQ%Jep!bER4ltQLKoSv3jhE9kDZZk6lrS zVw6XT071eDF@S*#&LAc*k;$3F3}!MrvuL1^<}|T@g)Gh@Rhr!Whcr zCOP1s!yWPf5A@(3zze;&7kPzOdUdbz4)65t-sOUe zE_bN`4Q%iRwSX4bg14ZS&=Onnmeev@X3O5PnxPq+c{8fC3c;krI@sCf!)_U6K73Ju3RPT1s!*k>t4bZ}RCjer zV@1BcF0Jbs>7;aiiw;l6+6ePuE(%bH;wVA|Dp4I(=s+jBqif`7SRR20Mhv1D5CdcI z7!(s?qBdvK>BSLgjhqj~b{TcBfrI05{DcXx>k72{!J}8Fi)Ze<`;YmLW;a&fn%jT< z{rTD2wKwK&9hp9M^|dcQo9x^;{mv81iwmb_ZS|9fE?(Pr&xwusl^glneBtTkeaA0f zdg<$@-g|cTz@FDHFP~pHb^G7%KVRamb2ktE_Qm8^dpRH3e}DY*$!}iRy>af-!}lFn zsJEwY|99`=(bWsbAO30X@CUD4*?H`TN8bJG!(YC;V{^~rU!8sQ$1{iS3J2c&=hjU- SwE5!R>!&|nI=f>Bp8p@{>fJQ} literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn030.gif b/editor/default/images/emoticon/msn030.gif new file mode 100644 index 0000000000000000000000000000000000000000..4beeeb88c4c5b0c586c5939f0ae44331d337eeff GIT binary patch literal 1040 zcmW+#QHT{p6up&8Cd#H;ZBQ^3g>Pq*BK@!gM~jTzVnN%J719tSfX^Aw+DuEW`@ID&b{;0*p~H=zC0vD z@{jZ}v$$p!X{POF`Z#m`Oz*qPK9~>mQGA4t<|Dm|S9mqA^htbzPv#SS7N6m>`AlEM zSNLka(o;O)X`X}#1Q3G|PT&A%a6}LUAQ%D>1rdmbNT@&oH7Jn;2}p)SWI+b9Arnc}VG(w|kq^hVw)l{iTG(nSTqGr(y&8C@J zMJu$LRw|_xr8Ff?!~`a0LUUpc=FA)|hy_?M3$!Q}VbLr$Pb&+i*36c~5-gb|S{BQ& zY?f(Ntiq~UrBRG9nvq4M2#Qz{7AM7_I4h1NNC_yxN??gnB1*IpSyYOms1;>NQW8qC zl322ojFPQnmMW#9R4bK*Qiwt;WIxXKvJ*PcH9-bp0E01*Q5eB!jBIgJLA90(lQ4nF zn8+;5U^Zs53M*KRm1Jv?&CiqbTuZ)29_`DPX=@uqt%WN|Bteo%qGXW_$tIanMJlA4 zRJJ*4k$Vv@@X`dm6Yt=ic}E|_2k_eEZufW_X|_3UjzwzRRKvYjm)y`lez0A(A2B4d z^iSa}cTWxed}{Lh?oW4pd+@^PR~L?tO<#E!U+uFa-A!9}9-Eu&th1d<-y5?7o%_ar z{rCO-qwlPq-F&F?#)sqYE{w0aKD_IN?#6u+Tb>!1TR8PLFReLr?zac#Hm*tod;jnU zPj6%Q$>o0!ejQG(ymtMSzaIKwGj2V)ZN+VGUJOg#Iy|y=!>9Oha;5uk`QCL?FCEyr z`j;KO`4i{z`k~S3=Z+lqv-@`~>pg$x2NTnKMkac{U+P?#+%a(M?AVFjuXlET^zn;# zT%6rB^~qy{SI+Ob{|U@48+{sA?@8aR81DJczI;GT8QLLOWKa4$Spd1EYS5S1Eq1difn;6B6x2`WP9>9z-s=eau`?&W#kdtvbTC!XBb zAszCMtYLh8jjz*q-Hor|%r9r=&tG-koTm%o0$eZ`=v17-sX3*K;v!r$7wM9?1eeSu zx+1Q?6?27-;s{4`Bt#&97=&m94bT`G!V5g$4W0;s00cuIRG@$wl!$@|L_;K!AOXpc zh$1LJF%*IV0yK~+qSY;?LTyAFXk*$?y{LzJQ%?<|0UAsLRYeu5rb>;X5gJV+HHju@ zGELMXTA;LAZj&Si6RjaO(G?UBuFwz zlp<0f#iX##QH|V*IDwNY=o)biTw|`G^Wr>s?dt68TpelFIj@d&s$5mYmVY<2tQ~Ky zm-R<xq}#uA5Gbesu1& z-xfv|yXJrIXj?ja&~_i1+kR+yVH;Qfn&^38@!S5+-jzMKZC~`W9oM>A@BE_kk%{Y$ zw=LZ=~MgXMlL<~<>P$=BV%@8@5Y|)vn_8;4ej~rmHwHXZ*2O+J$my# zYZ=>dGlr%&#DbMnZu;}7EJ;j!H}Zhma__K&w&*V5}ae{%0rqhoh>tn?oH=E#OW gwmkFM*7lj5>CffUJ&W&K|1w(NdFcDTd*tc=0dbEDI{*Lx literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn032.gif b/editor/default/images/emoticon/msn032.gif new file mode 100644 index 0000000000000000000000000000000000000000..6a8a26e9c82b76018c51f682fdbdab4889a7b925 GIT binary patch literal 987 zcmW+#L5L7U6n$+5MqYFaq=YF#h^ajpQDjV_uB?|tdxdnEx+K*l!kft7HHDxk2{-7{ z7_@<(VAqJiLyQzexPk}ALt8MBw@yN^xwY_`-3P;eGw}GI_um|vnSS=UHzqNOf3Shs z%`>}MX2)%I16O~)`t`LtF?mdi88I_vk6F7g;#oYuksG>^zPo} zf{QM9sR0da@CLPj7TAKfpq9`QTk@9FGFoQK-m;pZ8Jl@CwSrdIinpRx(JEW@R@FLM zXY1a&n$W~1Z_U0K6!8D&0vQGp6oTt%u-rK+n+9qLqf zbxC7Ie*L<1U3;WArO!9$@N}$=Fdyck0EH-yB2=If)lr2GbfP=DMvjK%5r|;KAc_Go zFb0o7F(D@EzdIK%el;Skk@KP0ETaxK@YHx5KVcHsdKJ3=BoEKOFt>FwuD|;B@kif( z;PI6w@0+^y(+Ar*_1hD_JT!gIkM2A5{WpIcI=ebCb?o4`?chhNFVFvZ`@Q4KFYe@} zU01fP{QT*{;f15;j@-I@V(-k#`jyKMPRyO2UR}F%;jNkd6Ki{K-~9VTTwMNm{>N)e zFD);=VxR4J`d$C^yGK4*c=*Hf?{Mk#-Cd{FZd`b6>C1n&>^OO&9Xq?nR`1z;_lvmY meBOQFNL+k<-;u6da+TwFiq)saE_-QLt+QS{17SHwCp(luBVd6m{*vnv(_bAVPQ{dJ^@d z5|O$+G(umCttlQn=tjf}?GF)L4~n=57K)<8ON|JQn+z;(c42srd9(W-ePqx5hsH35 zzp;+FjWf4V=K5`J9m_v0e{_B|L=RCRAtZ+6At@MwF_;Ha$OxGsd&mj}p)eE=MWG=y zhUTFu2tf?;AQ2!)I3W(;Kn~79j9?_AGl~gJWO63aKqJj*Vg@sromnhkA&aw!4Qym{ zHc_BRIVA(EtKkOO02^q7+aQauNQ-V!mSBmN+>*>-Ml&~)Wmu+Vw=65LLMv`X)?kg+ z+?q`2Lz&zp2OM;`Lq5O<`rtmuBRtZhdz2@5q9^y%HGM3)c^7+zXL@$e@&YgP;$Gwp z-ssJ}$psf(?otIRSm70_1M0v!cpX$DYGjRGqiRA;tjTLqHB@6Yucn$&Gi&ymRSRli zEnbUiLv5_hYf}}fSmjk(x3hO1pn)1Xks=hS=!#N;5|vy@-EJ9W-hEMqGL>CfDo~+{ zt4IxMRC6^+eMLSRNh94Y9hTl-r`^-OHp0A{iwtBUJF-xKLKH_48qkR5XzDrYmIok! z0i7re2m{05VNi$&k@|P_*sgYC-Zy*sleHt4zWZSE;dA%gdgi*v zPp+KWIkD?W?s((bBmT$O^w#g~^ww<;Z2$C{{NU`ST@!m&Z+T{6_VAyd&+O-k<#TWU zb;bGBoqNwNPS3yk`zt%<4;-KVdCS3n?mD=1bn}bjx6K@ynSbfZe8aZ4o}0qt|0T5U A$N&HU literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn034.gif b/editor/default/images/emoticon/msn034.gif new file mode 100644 index 0000000000000000000000000000000000000000..9283363c5e4b3656f08769592dda68e866399852 GIT binary patch literal 1057 zcmW+#U1$(g82xZ5>!n3QK?`m{MBR+kj529Aj1tA3+0amEW)B$Y??L}Os$D6i6vMvOSCMO zVc9Ixs#t|pvr3~FVKgI)ND&mVA}mgdLvdCdOOO&!f|bA$r9_lyC9(y=+sjVqK-UNvgaHi3Kt^E%qcO7CO$F7OFHFJ& zCSxMAFoW5c$ttX1HCB>sMRw^Dd5O=EyUAmVw0YXr22pF~N)kzsWRfUZBtx=Erc{v% zsV0>zN6m6C;sstBp?BgPyfg3UgZKdccWZQXyhWNV=S{H$4I68{x?qbEbG`da`=;X zwj7!rUB2b)_}JNFJC?op%@aMrZ4|EL;y!_c0clJCzw{h>uJJ;X$>wW57 zzq9Y|^j~A=`hI?N&Bo8S&rN>0H}?#$`uob%u8Z3@4If=t*!uNjV{adrUb}l${|7cc zG_bDA^}l|7#fD8E&z^eao7?}aKC)-#h7R0klk?Bb$wWEv{hD`Yf1BI&(MbP};d8h- zZ^%O{ YQ!5XT?>~6CclnBiv1^-u9F)!f1Ek>BXF(TM+CfW+Q@430x4|TLc?H-ATdL z54|Uo^o4Ma5qV#APQL0*+&e@Z6x>15uQ$68(T^8h10f<}-TfW);mhH9`#f->Cr3kr zlWyP!KLId48%}7)dRY7EeNCZ*M3QQ8nw16cECsJ%WsZR4);&C>P zGjWuO)3Zs+CuuZ}6UpspKM^2FL!5?YC};+)pxF)0c4+#b>4Jt2g8%-R3mp8#?E;_? z^wl=5{R!aw13b?CF-9Uco7OHlMV@#a-1YRusgz+4a0mGJdmcv$-m!TF4QY8#v&Zp0 zcg63RYwN#YlrGzv+`D`0CR~p?MrVD8&uYw!Gqy%_NMhhjNU rc-YaBD@5F literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn036.gif b/editor/default/images/emoticon/msn036.gif new file mode 100644 index 0000000000000000000000000000000000000000..ddb0aa0406c40dce0dbe6eed67bcaac8bbcbfa6a GIT binary patch literal 1004 zcmW+#Uue)(7(I)`6v1kZBBD!wsmmlngNEp@2-1N;23!u-?PMME@3^Jt0*F)=2ONiid4#_TaGR>aC! zJyt~_icuaV0t5*s!~g~|ID^=M9oacMu?KsyclM%zMw-*a1ST>$lbFFwW@i>FSjp0Y1u8yDy-6~ zTa^iID3hDyfP)Tq$OAmkgL{y7@Q&WOck&+I(|h;6Y1&wH^CtELPxR!TRg@FLp{~IdNsRclzH<-2})FQB`HIh z%C0O`s8ZEcCAAg#;-a*u?b5h3y+)g-ZEb{kGZzU+L~vOZt;BVI#WjVT3oMO)0FXn@Q%DptF4mGrCqR?bYnX7T=5>#0Vr? zP(gQr4f_@dMN|)RM}@>1`f^_i;r2s;l*8RiP@Xrbc8s#u8I&VoR_jmdp|@ z!?IX5%d`rsV%4nD2%{Ly$O05dffcYg6eq=5aV!BPNC{Q~OGJrMqLs*^C@Mv*C`&>~ zQj(R#l2NjhY$dZ)lq#iKsVqdH6j~uy?QAbQ&D2&F)W;a!+)_h?C zlQ0<*nZYc~#!ObQ3ahb_Y%8+GMRJkb$QQ_WS84OKtxcfT%tZo{AQ=*ofh@>|OjMu> zs-d#ws9Ej-5AkS(-oZQZ&b*@!@ImY^>Fm)@(na8|Z4C8*b~m zY23!nZMgaAFPDD!^zg0yv*Q;}|FrYP%Y(Zn-&yF{d8Bvf)RpfxzW2zEp{96yWc-eY z{nh3E&-e6hKGBJ9r#klzOl`V*|Gypk&R-7bJbK;slYc(*#&P_!<)w>velYhT_6>it zVP<4*;`>8qUt2eG*qt1dmC4yXy*BacqjI&c>$w^K(18a&8Ma&O&AwrOaOJ)pcVuDr zTgRR{Gr0N5^=bL%ZHJEj_VMc*Z~x=h<^JgdWz*;@_u|^YiH~+q_nkXFf7gl0kqeK# zeB<=iOC6)rU!NIRx%T51GIVU<{iUtXfA+**qZ8+U$zwLWABx8@vHqkr}n0? LF28m5k88K<|Dnrt9Ui9^a(zRPv#SShR@=&`AlEo ztN3cZ(i5KIX`U27AOaIm9K?w@6GsVH_2sEC>-zYKCUf zY?`SRT1BgAr4nr@r73BEK@4V~IhYf3W{wtMK`fXBT7*ThXcn8MjU}em#Fk)5ESV)* zhGnsAmT47M#j07Q5k@hZkp(D_0xMu~C{BvA;#dMokP@r}mWUFiL@SX+QB;arQI>>~ zq$DeeC8K01*-B=qC{;?eQdx*XDYQba+1WZf&D2&F)W;a!+)_h?C zlQ0<*nZYc~#!ObQ3ahb_Y%8+mWpbIj$>+)U*J$&!txcfT%tZo{AQ=*ofh@>|OjMu> zs-d#ws9Ej-5AkS(-oZQZ&b*@!@IiQWrPrHlk!H(zQ>>R(8*A9r9@|go2R2>?uirkt z`IpZ+=X*cjeD1`>g(KhII`qi2T^v5P<>`lh*mkA&(QDt`JNfS5_lNxWruRPIf8oOe z{`marnP*0h_Vx}9POrSU^YS4#Fu1z?aI-_M{n}tZ@ccs)y}1_hR)BPyyuHg58U!*|AucaO`g1c^vve7vwhFqaQEoM(%2mz z%rEWm$3HnZHT(5+=f}ml|9X4J|K9fd@Ttcx%)GPb&nI7<+wscdXO~|ZeBgBGn;7v^ wza4vGYG!iYX6_t2{N>U=PxW>NF!K0`{_YtD3@Ze$g64Bf`c+uz(R`8tN2gCPf;PHLD@6Bt6UVZVUv4s#8bmOkJrv z8OcmmvI!6*M3@sek&`%?8O&rBvpIt^Ig7IyV2~k(S-?UTv6vOCWEHE~!A^Fun+8o< zv;&Bth60WWF)=2^=k53GOB-}}I@U&nhPfy}A&O9p3RI#B)#yMcy3jpxG%Qa*0uu&tnvf=@NojJ* zNSXfc?v*Q7N2EP+J`|f})WHV!j>qv67J+S-;Rlyq|L)52xib$u^Z&|?KbFs}-M)42 z;wL*UuPkhR?(g-JyRRMj;^@1N{=E0C8;3tQ@Wk$W-!6W2WNrWX6OY|qdG_$7^Xtcc zdF05Cubkfg*V4&_<aUCZm~OYdnP?c8$qhYMRzwND>j`{~w&eNVpd{@o9+ zzIpKNg{3!6-Pw8Wn|Gf2`ssh~;J4lTjvha82FqIx9=iDF>CYbDbM)-T5AE8%4KLpZ D{#?`{ literal 0 HcmV?d00001 diff --git a/editor/default/images/emoticon/msn040.gif b/editor/default/images/emoticon/msn040.gif new file mode 100644 index 0000000000000000000000000000000000000000..d379bd7021edc83287e4aa04f4ce02edfc4e5df0 GIT binary patch literal 1034 zcmW+#OK2TL6upX+8Y*o_x+oUM4@fdpq11(1b+l-0>&8BEM5Q`NiKIagL_txw2|`i9 zPfODfMJALNKer-0o}W!+f~#VKU36U3T82;rt%%iyU-UT1f#IGRINZy*XYSv<^VZv* z7?L6RLsl@gdZt#(RJ%>BVDY=f_rAL1gZV%o#YgyPKGLgrg;(=RpTsBlWIoYn@fkjw z&-7J%g|Fr-J;f8A=1GV^05J&R1P*WpM+89tf*}x55P@ijgbEZ;gAz%QfMiHS7GxkB zGEoH;sD?^VK!65PMYO5KRH#nWL7l0i2GIZwrhytoBQ%;us){O9O_iEN6EvA7Y8K7V zY?`T6v_h+CrBd2ZN>kEAOkiRrG$-a@&dkw*SbznyK#O7#7R_SQw6S1nO>9Xl!ID{` zWw8v)W|>ySDy*7S8pQ~s8CgV%pokS=aZ((Lv*K8Slz3aDmqzHFcn9yyJNh6#fd5>YpYOIvv*o-gR!ggmHEd~*?I#S0to=oJ z<>ra?-}c8&&7Zycn64^1wISEsL7^W}llkI#>P(D}DN+k12IuFbFi_tS-^9vPjuF8z8>@5qIs zVfIjGW^(_=8%O@!wRHK>^$(7R?Y|uw9YngLd-SrO&sg{TD_>u8?ATvpXV0G)oE?2< zZu0mS9}oU`WXHz6n?^g&jT|2M{jcnSpf|KiT%~?avOs{Pyk_ zuIez;d*R7T9{{yh8 B0$l(A literal 0 HcmV?d00001 diff --git a/editor/default/images/font_bg_color.gif b/editor/default/images/font_bg_color.gif new file mode 100644 index 0000000000000000000000000000000000000000..e1f4a8fe9ac6a857eced37eb20b88f6f0d29f865 GIT binary patch literal 595 zcmV-Z0<8T<+1c6a>+Adb z`_a+S(9qD3kdWKk+uGXN)6>)C<>lVq-qh68#nj*X{Qh;J!#i!QCs(0Nhr@G%kMZ{T ziK@cG!^8CV`>d?2UX#46yU3)y(x0E7+TP)`w6vOM*PN=rxXPC6D*x1<8($YV7xAF1u@bK^~U8R1e(nf&3N`=F}zrU)u&b++5?d|Q=+vIYk%2<%Q zz`(%i>FKq_(!a*g%Gv76%geU5wl{6Cx3{;cw#>1yvAMaqf0w)6-QCU2&48=Y^!WSK z)z?&xx@@M=JZ`V|`uv!su))#gsmA1AhrjOb?lfbm&d$z#m%aA+`sC!~Oo6@n{Qae~ z$lB=g|Ns900000000000000000000000000000000000000000A^8LW0049VEC2ui z01yBW000NDfOLX_XcW3QWS290|5kWQ!;N%W;8D%F=ceM1P^jtSrGzBIvgr2H?>0r2n7iO1p!-F8Z#Cf z5)e@mT?7dT6AM-i2Q6bgbQ4uXYCb?g3{W`+03c6ug1mG{;a~v_1||*wpd-dfA{0An hKzP7|pCB8NmS~Ca!Qv@8B}Oz*@Np0ul9&Pk06WppJs1E0 literal 0 HcmV?d00001 diff --git a/editor/default/images/font_color.gif b/editor/default/images/font_color.gif new file mode 100644 index 0000000000000000000000000000000000000000..92e6ca4f71c3d212b829e27d5436584fcdd71ba3 GIT binary patch literal 549 zcmZ?wbhEHb6krfwcoxm@<3-(_Bh^1XKl=Ig`L#q*6``+fzL1Z{rUU%=hqKsuHU?K^Wvp-4)=~VHcVae=GLTr zJ6CL3w{SM&*()|}S~L67rl1$E-yN9gdvT53i(C65s@8n}@%_{Dz2Dy7YFl~i z;B=$Ym+n+fT2ndqn!GUfXBq&Kd49NeQ}o-L`IcQ$X{JyFNq_g;RNPCYqq z|C`*ocNQOd+rQ;m!qnSp!3jNkQdb^(Z;_?Yv-!DH!il8mxBvY8xBbGWpzfRV_rLl4 z{crV(hlLC81^3C5-OA#H8# zyAnj~c6zqnc>U>Dqbtvn=$itc>j$xC*S8!jsN)d&$};ws+T{SxUO;Al{r4uhWjpmkcd3ey(_7I zcUInlN6szRgl)EWZg|qZGog9yBOEQ%B?KM2W~_Q4?=gE_*m**Q@kd zcfNf8GiCb=sic#ATb^${|7pwFciD6AzWw~WVb!AtuYX*7@@?bg2@|$HpRwn4`}!xz z({C+0^e(2|+|z%Y?P2V@>7PcU%YVNm9j@z}87U^9m> zU(JyX3wt!fODtYYTGT1X*3XdP@-UfELQ^(F;>F{Ky{$b;+YD|^SaE!glJE(Z9S$eX zD?22I@CZ$4X;^IU{z$@zQIU57E9(~yg+PW=Jr1mkj{Hz^XOz}e58E^2fVzW#I@5|b z4hl!QnzdLq@H}vQ;I3$5eu!t|!Xv%h%*>xU1Wg#++GNT)9z+~wb&+;4{$6t+nAvf$ zvxh?K1cAoJMd~^VTOK?}y(nos!AX8af}?Y%b)?9Jg9lPtW~oki5a1Wl?$pH0sWBz+ P#{$PzHhv{m76xkoMZA5- literal 0 HcmV?d00001 diff --git a/editor/default/images/icon_align_article.gif b/editor/default/images/icon_align_article.gif new file mode 100644 index 0000000000000000000000000000000000000000..f16697d91a260fdb90951372750a05db74b614c2 GIT binary patch literal 379 zcmZ?wbhEHb6l0KLxXQrr|NsB{_wS!Nbt-7Bp3PFJ`i1KP*65_~w`siS6dTsef;IWM(fO*pZC7}pLl6u;2OQFZ~i+k zmt1yz$-_6F7{~&OKUu)~bU-A?PYi4`92yHebfj7vmK2>#QJQ_>nX$v#sP&Ccj8C!p ztY^px)qYX7KgsasnY&C}A9l=fh}gxgc3Pu2urNTXq%75oRYX@sT~0_zQB=Ovt6W$| zR$5h)Swca3Vzw6xhX6MhKc65wFXz0t7SDx?mo8tqy4jnBdFQU3Y&>i7cI@7@cmKK^ hzn09*`NvOqo=Qwudp79gsfaUIZr*agd)JY{8UU4=m|p+@ literal 0 HcmV?d00001 diff --git a/editor/default/images/icon_align_left.gif b/editor/default/images/icon_align_left.gif new file mode 100644 index 0000000000000000000000000000000000000000..247324f2222ba255147cd3cd884988933a273e2c GIT binary patch literal 366 zcmZ?wbhEHb6l0KLxXQo~v{tWv;kw3)J`PJHomWWa9&jqY>Y9DrDPWCG`hJ_3-A0ky zjl$QP#qBk{{O13ux0n6bXsx@k>FS&R7hZmIUM~6i$A9nj%7JV2{I}RnytMGlo1af# z{U|*b6tTs~W~tQu`}a?sI`#kme+HTX#h)x-vvoiu$WIJx-3}89JanX57cMC}nW8lN z!ZTxswQM%?E~KCK^)nUjRBk@#=6u;#^-xBEPUO2V%UTD$hI37mdhKkP*w|S)xmXH| z~~vg=Duy}cZ{-Dus7 zO&4B%^IoqUxJK{Ho1fw9%`U(BfAQtVV=v#Ie);y{n@^?Zg6@6!U%zmj%~GkLwR-pO z-#>Ng)c^ng8OQ>PKUu)~bU-A?PYi6c9i|m{=t#A$T~c&1MQQehXU3hYqSmjxQgq9y z)=fq5xX>z_P0`ncj%v92P2fF|_$p&+ObA=?!~h#DVJY5n&lpV>24*H!MlMcvj#l0F z&hFm+iIdy4=FXeT%{DvBOLPAGg^L4MS1ef*7_;7QiT2iQ+jnTUt=qKObLTeQoxAr2 n_#Zg2Ys#LZM-Cl4f8yNPwfnbv?YMYqY9DrDPWCG`hJ_3-A0ky zjl$QP#qBk{{O13ux0n6bXsx@k>FS&R7hZmIUM~6i$A9nj%7JV2{I}RnytMGlo1af# z{U|*b6tTs~W~tQu`}a?sI`#kme+HTX#h)x-vvoiu$WIJxy$%x!JanX57cMC}nW8lN z!n4oLYulJ^c6g{LH{*UKPuOCaenZXxXq~>DqN!8x=R^ kmap03y?*D;&3pH4JFqKk_hG+1r&b<5x7YpBB}WEp0I(v1SpWb4 literal 0 HcmV?d00001 diff --git a/editor/default/images/icon_drag_down.gif b/editor/default/images/icon_drag_down.gif new file mode 100644 index 0000000000000000000000000000000000000000..101b5a3986d9d0e331661fbb1c052386fe8bd287 GIT binary patch literal 53 zcmZ?wbhEHbiIJ0s!)qba uhR!A}p$5?}1`*rlb00p{X|ZjVXX0#&iZ$FU$7U@oVQE}jx1X1Z!5RPqxk{D* literal 0 HcmV?d00001 diff --git a/editor/default/images/list_bullet.gif b/editor/default/images/list_bullet.gif new file mode 100644 index 0000000000000000000000000000000000000000..029a2cfbaeac80201d5ca920e833188ac47ed97a GIT binary patch literal 302 zcmZ?wbhEHb6krfwxT?)iwD{4!tDhGgdb@J}>$OMTu3Wh?GBPqaI5;pcaQf~y5fKqv z&wt!<=7WieNos1UxVX5pvojA5kBW-Q(j#w=9XqD0tGoNsr?w3*w6(QMN=nq!)TZuy z)w=Fkc6N6EwwDPB30_`an@+#qy?eKuoLqT%c|k#ejg5_vkPtgN`>F%4nVFgY|NqZG z0Z{zO!pOj&&7cD^1LP+LHtz#d3p{kB`j0j!H0W@NHHo%P(JYmbKb*KC#ccnB4HqUQ ybeK;*?X|?AL1CGjt1(X@$D=)UGnjaeFvu}zvq}gl^Q#MLXgM?2RVO+!SOWltX#>~uYV`CE;85tZLEF>iK{N1ne^74|B zlI-m4h=>R;FRx?Aj`ePNId}itgoK2)_0JpEJmulx2@DL>)zvL1D3FtrQ&CYVU-r0j z)AQ8S)LDC8o0yoaT)9$PTf1h}Q*m+e(xs1Ief+(9_ilD}_C*KZIXgSg*z#i0;dlT4 z|7RcGXsNGb%rB@H2~nI BVetR} literal 0 HcmV?d00001 diff --git a/editor/default/images/multimedia_icon.gif b/editor/default/images/multimedia_icon.gif new file mode 100644 index 0000000000000000000000000000000000000000..d5309d362bd99fde813837d20a745b9beb86fd55 GIT binary patch literal 2531 zcmV<92^{uENk%w1VJ-kI0QUd@+OY&oamxOFUFO9%$=I*{T{Hdu{-?`m*RBF3bJ*p_ zN6pR5S%m^nQZH3iSrksjD~01_n*r~&rv?TFx6O{6oSb*I0cU4s@t1_c!@=-H8sOmI zZfG~-za?v=0vSfTdxfUEySwyLE9%c+v9Yj|lav2#N8aAvBPfkHI5-|y#pTIS7-iAs z<>lGg*{Z6l*~r7`&06EV9N6aZYmCtC?d^h{N>h6S|EG}Z>gu?d5{Rcs`uh5Tfr0ny z=7!V(agZ;Auq<#*8KPC^6~MaqM=4-0p{1# zS8FQ&m3)n{=7Ec7ii(Sj$ny5;wB5TW?ZLMD_1)If+d5JKgK{X_*w4kY|(+r z0WCO?>g(jt(9j}d%vpZVrLU6hrj+Q+Q4}YlKU)O#+trt!gY8Qpo0_8ZOd{~xgJo!a z+r6|&RFfJ#vT&>cESmGayu#qM0{2!eD~;;>Sukyy5&8cA_WS$(porzU0_|BetE{DQ zq7x}9E$)hQV37i6juyki$^QHDPI3bObWrB(?d)E%vWAsToN0b3?iwvwzuxU z0bG0?b8>sg-R;Vy4UUeF3mK!>*VygL!iI&1^78W`f#jmc@BaMw^-w2pm>*(SDGoHX z;K4X>acwW5_%D?1tB)S_)Liw>Mn$9XS6n{a+uWz8rzw5ip64T$)GX`k>|S7LZ?pmK zZcgxYRr2@v$H&H^t+=wgq)MIZ;oju%@bDTY znCR%}NlHwbp|DR+P?n>>+S=RkLKfED-N~M_>|Aa1YJN(f>&^ zrlhN)yzlkpqC7*0`1tr-Zl^FYGxPNH^7i-l?ZNfu;ra2-i^(5%cX&NOO$#fr?(*Z{ zx)S5#b3kO8t!5VAm#|a-L$dDH080%) zFi^{?PE5;(D6eGj&jy*@DyaY%fFe$f{)F&K4?PHRfdeVXa{)83%#+Q9w&%n<2I$_BZR~1nj_ByMqID}Jn#@f1Uy|}B9;xO@Ucb6 zxx63^3?-p_A~ZADxIqmhTyV?<>K>7TB}Po(bv`b@!-F(%IKqGpL>o=*F~aymh)=X| zE2#uCfC|eC>UzVC*76wt(Y4n&_pr@B{1l3I(MLBRikXSTk-#tzFtQ6Gx|jjSmMzTl z0ypLyVb0cE0}i-63mCA3FCFv}3N8pBpa?IE`(uXVkV{T^750p}4G&F395L5_1D?Vv zO85iI>8Y>Yx+J_fVCL+PM?SeORrrv@HaSSs1lPa^KY=_{)Nw)`b!?MG2OW%{JOYwX z<3I&1FcSw0!_+=`8Qaw0?mrd$?Y%s0V8#hv)BbFu*$a!+`&og&_K&hZwAYfrn>eOMX5o$jEc2BsV4W;!=>R~K4oxHg1RFk}f_iR~ z1uVFOH#f5X2`h}ik<1Lm>YykINpQgut9U_Q2I7wvffU*y z1}nHj5PIl<3elm`WOcZl30*zP+}EmxP>8V`T>gG0jEXCY7uZT06nzum7z#yEQ^W&Tgama zP1pcOwo!pspkW_rFoawoN>LhI^{TGSs|$zPIz^bGtd{6O1zK7YC9I+cg-8Qj<;qw# zpdkPOK*I=Jr~q7C!3$%Rgei2;03v=zoE-thIC?OMG>~EsX-KVVQ)>t>^ur6VZ5>J_ zF^v?!q@V}m0MBJwQGqs~q7Zvv#cB6ITy5+@8<>@?>&|cn9hg-guNcPyK>L(!yr2!a z7{oiY!HVv(Vie#7fOwy23IOPU0};DG37P5die0+j~_oCJb3KauRpbQ zn_s{AboA)aPoF-uw(ofN?(5sPZ(qH7m6Nyf<;$0|XK#;+ng8th$ClRZ&!0bEy6nV@ z7w=cCI<N2@9XbP$DI64|ziB6d4q$RV{(c$n;MKNh-CtF852V1!d=g-<0o>p>XXR$M9VZUvs zZKijc|HwJnBS-Cc__|L_us#$j-AineVx1G>dR06ww%2G`_JD8Z~qm{IQ04ZukSzq zbgnvk{l(v$sRtgt`?vDot=AvFpS$yF^2UqZYtG$%_4nDwf6qSr`|$1Gv}sII?oEHE}UAh_i^wD;kNII%+F73Gg~`VR#qk_Cud<{5gQwul$2y-WTdI7>Ehy&o}L~Y9PH`onUj-a zV`F1tVxpj+pscKHYHC_gP!JRp6c-mKA|g^)SQs82{@~>gdwY9dUtd8%K^+~PjEoF^ zetr)RkC}Tv6fJ!m9UUzuCZ?jIqNb+i=jZ3_?CkIFU$*k4lao{3x>pl-zLk`eEGa2@ z^yXJ+XlTju$F8ofJUl#JUS4{7dUkep{X1SpMn+m$SxHMv>+9>cZ+RIJ5n*d<`}pmz zO^W*JTxzyVtWA23W)2E7oWu>Zn&vZ$2}yFXw`w#Q qN?7oku<F=NKGY10-jUVQZE(KBbxEM2U zk&%&*khpg3+V<_+KYskkz`*eT|9>D!3{d>Z!pOj2#GnIG4Du5LTad%d0uLRj{u3%i zM=bVuFsG_3i?B=*3`nf-+@&Mm?xq&VXVKWwo)p7)@BOirqN|Uaxn2#}=%6@3N!Ue4 c&4Y=>z*$1kLsONJUqF=2YwEP=?v4!B018rYZ~y=R literal 0 HcmV?d00001 diff --git a/editor/default/images/underline.gif b/editor/default/images/underline.gif new file mode 100644 index 0000000000000000000000000000000000000000..7a44f82e75a48d867d9982bdea63a2d6540e8f92 GIT binary patch literal 306 zcmZ?wbhEHb6krfwxN5)<85w!v#EJ6qa&K>MW@cs~A)$tbhUDbrjEsykXU-HB7WVe` zK7IQ1*|TSl9zCkBuivs|OH)%*adB~DW8=)3Gv(yu+}+)Icz9mCc+t_(k(HIDt*tFC zEK^L+O%ofv}x?@>?I{7d3kv%Dk_H$AC8TUt*xyM3=E8kiAhXMjE;_; zG-=YDIdd*wzWo3He+E*3;!hSv1_lEL9grrFpBUKu9cC1G=t%V+Z*gRhDvOw)oa*w$ zV}fE(U_*{#7uS=d&?^eY4UZTlJw-!3t{*Vr@tH8=U?(GYgp7v)uZBDWzkXwjOV^aCjttfSis@zy literal 0 HcmV?d00001 diff --git a/editor/default/lang/ko.lang.php b/editor/default/lang/ko.lang.php new file mode 100644 index 000000000..238925b51 --- /dev/null +++ b/editor/default/lang/ko.lang.php @@ -0,0 +1,60 @@ + + * @desc : 한국어 언어팩 (기본적인 내용만 수록) + **/ + + $lang->edit->fontname = '폰트'; + $lang->edit->fontsize = '크기'; + $lang->edit->use_paragraph = '문단기능'; + $lang->edit->fontlist = array( + "굴림", + "돋움", + "바탕", + "궁서", + "times", + "Courier", + "Tahoma", + "Arial", + ); + + $lang->edit->image_url = '이미지 경로'; + + $lang->edit->multimedia_url = '멀티미디어 경로'; + $lang->edit->multimedia_width = '가로크기'; + $lang->edit->multimedia_height = '세로크기'; + + $lang->edit->submit = '확인'; + + $lang->edit->help_fontcolor = "글자의 색상을 지정합니다"; + $lang->edit->help_fontbgcolor = "글자의 배경색상을 지정합니다"; + $lang->edit->help_bold = "글자를 진하게 합니다"; + $lang->edit->help_italic = "글자를 기울이게 합니다"; + $lang->edit->help_underline = "밑줄을 긋습니다"; + $lang->edit->help_strike = "취소선을 긋습니다"; + $lang->edit->help_add_url= "link를 만듭니다"; + $lang->edit->help_add_image = "이미지를 추가합니다"; + $lang->edit->help_add_multimedia = "동영상/플래쉬등을 추가합니다"; + $lang->edit->help_add_emoticon = "이모티콘을 추가합니다"; + $lang->edit->help_add_quotation = "글박스를 만들거나 글숨김 기능을 추가합니다"; + $lang->edit->help_add_html = "html 코드를 직접 입력합니다"; + $lang->edit->help_add_html = "html 코드를 직접 입력합니다"; + $lang->edit->help_align_left = "왼쪽 정렬을 합니다"; + $lang->edit->help_align_center = "가운데 정렬을 합니다"; + $lang->edit->help_align_right = "오른쪽 정렬을 합니다"; + $lang->edit->help_add_indent = "들여쓰기를 합니다"; + $lang->edit->help_remove_indent = "들여쓰기를 제거합니다"; + $lang->edit->help_use_paragrapth = "정렬, 들여쓰기등의 문단 꾸미기 기능을 사용합니다.\n문단구분자로 P태그가 적용됩니다.\nShift+엔터를 이용하시면 + BR태그가 적용됩니다."; + + $lang->edit->upload = '첨부'; + $lang->edit->link_selected = '다운로드 링크 추가'; + $lang->edit->delete_selected = '선택파일 삭제'; + + $lang->edit->icon_align_article = '한 문단을 차지'; + $lang->edit->icon_align_left = '글의 왼쪽으로'; + $lang->edit->icon_align_middle = '가운데 정렬'; + $lang->edit->icon_align_right = '글의 우측으로'; + +?> diff --git a/editor/default/popup/add_emoticon.php b/editor/default/popup/add_emoticon.php new file mode 100644 index 000000000..0c300ea6d --- /dev/null +++ b/editor/default/popup/add_emoticon.php @@ -0,0 +1,35 @@ + + + + + add Emoticon + + + + + + + + + diff --git a/editor/default/popup/add_html.php b/editor/default/popup/add_html.php new file mode 100755 index 000000000..c108206cb --- /dev/null +++ b/editor/default/popup/add_html.php @@ -0,0 +1,39 @@ + + + + + Edit Html + + + + + + +
+
+
+
+
+
+ + + diff --git a/editor/default/popup/add_image.php b/editor/default/popup/add_image.php new file mode 100644 index 000000000..30dfb8a3d --- /dev/null +++ b/editor/default/popup/add_image.php @@ -0,0 +1,55 @@ + + + + + add Image + + + + + + +
+
+ + + + + + + + + + + + + + +
url'/>
type + +
+ +
+
+
+ + + diff --git a/editor/default/popup/add_multi.php b/editor/default/popup/add_multi.php new file mode 100644 index 000000000..85dab24b5 --- /dev/null +++ b/editor/default/popup/add_multi.php @@ -0,0 +1,51 @@ + + + + + add Multimedia + + + + + + +
+
+ + + + + + + + + + + + + + + + + + +
url
width
height
+
+
+ + + diff --git a/editor/default/popup/add_quotation.php b/editor/default/popup/add_quotation.php new file mode 100644 index 000000000..066a31631 --- /dev/null +++ b/editor/default/popup/add_quotation.php @@ -0,0 +1,216 @@ + + + + + add Quotation + + + + + + +
+
+
+ quotation + fold +
+ +
+ + + + + + + + + + + + + + + +
bg color
border type + +
border color
+
+ +
+
+ + + + + + + +
+ + + + + + + +
+ +
+
+
+
+ + + diff --git a/editor/default/popup/add_url.php b/editor/default/popup/add_url.php new file mode 100644 index 000000000..9705bceb0 --- /dev/null +++ b/editor/default/popup/add_url.php @@ -0,0 +1,75 @@ + + + + + add Url + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + +
text
url"/>
bold
type + +
+ +
+
+
+ + + diff --git a/editor/default/popup/color_box.php b/editor/default/popup/color_box.php new file mode 100644 index 000000000..82df6f561 --- /dev/null +++ b/editor/default/popup/color_box.php @@ -0,0 +1,39 @@ + + + + + change Color + + + + + + + + + diff --git a/index.php b/index.php new file mode 100644 index 000000000..98d941df2 --- /dev/null +++ b/index.php @@ -0,0 +1,23 @@ + + * @desc : 모든 요청(request)의 관문으로 main() 역할을 함 + * Main class의 instance를 생성하여 constructor 실행하는 역할만 수행 + **/ + + // 필요한 설정 파일들을 include + require_once("./config/config.inc.php"); + + // Request Method와 설정값들을 세팅 + $oContext = &Context::getInstance(); + $oContext->init(); + + // ModuleHandler 호출하여 content 출력 + $oModuleHandler = new ModuleHandler(); + $oModule = $oModuleHandler->proc(); + + // DisplayHandler로 컨텐츠 출력 + $oDisplayHandler = new DisplayHandler(); + $oDisplayHandler->printContent($oModule); +?> diff --git a/layouts/test/test.layout.php b/layouts/test/test.layout.php new file mode 100644 index 000000000..7b898228d --- /dev/null +++ b/layouts/test/test.layout.php @@ -0,0 +1,13 @@ + + * @desc : test 레이아웃 + **/ + + class test { + function proc(&$oModule, $oModuleInfo) { + $oModule->setHtml('레이아웃'); + } + } diff --git a/modules/admin/admin.module.php b/modules/admin/admin.module.php new file mode 100644 index 000000000..3c9eb1523 --- /dev/null +++ b/modules/admin/admin.module.php @@ -0,0 +1,148 @@ + + * @desc : 기본 모듈중의 하나인 admin module + * Module class에서 상속을 받아서 사용 + * action 의 경우 disp/proc 2가지만 존재하며 이는 action명세서에 + * 미리 기록을 하여야 함 + **/ + + class admin extends Module { + + /** + * 모듈의 정보 + **/ + var $cur_version = "20070130_0.01"; + + /** + * 기본 action 지정 + * $act값이 없거나 잘못된 값이 들어올 경우 $default_act 값으로 진행 + **/ + var $default_act = ''; + + // 모듈에서 사용할 변수들 + var $skin = "default"; + + /** + * 현재 모듈의 초기화를 위한 작업을 지정해 놓은 method + * css/js파일의 load라든지 lang파일 load등을 미리 선언 + * + * Init() => 공통 + * dispInit() => disp시에 + * procInit() => proc시에 + * + * $this->module_path는 현재 이 모듈파일의 위치를 나타낸다 + * (ex: $this->module_path = "./modules/admin/"; + **/ + + // 초기화 + function init() {/*{{{*/ + // admin 모듈의 언어 로드 + Context::loadLang($this->module_path.'lang'); + + // 관리자 모듈 목록을 세팅 + $module_list = module_manager::getAdminModuleList(); + Context::set('module_list', $module_list); + }/*}}}*/ + + // disp 초기화 + function dispInit() {/*{{{*/ + // 접속 사용자에 대한 체크 + $oMember = getModule('member'); + $logged_info = $oMember->getLoggedInfo(); + + // 로그인 하지 않았다면 로그인 폼 출력 + if(!$oMember->isLogged()) return $this->act = 'dispLogin'; + + // 로그인되었는데 관리자(member->is_admin!=1)가 아니면 오류 표시 + if($logged_info->is_admin != 'Y') { + Context::set('msg_code', 'msg_is_not_administrator'); + return $this->act = 'dispError'; + } + + // 관리자용 레이아웃으로 변경 + $this->setLayoutPath($this->getLayoutPath()); + $this->setLayoutTpl($this->getLayoutTpl()); + + return true; + }/*}}}*/ + + // proc 초기화 + function procInit() {/*{{{*/ + // 로그인/로그아웃 act의 경우는 패스~ + if(in_array($this->act, array('procLogin', 'procLogout'))) return true; + + // 접속 사용자에 대한 체크 + $oMember = getModule('member'); + $logged_info = $oMember->getLoggedInfo(); + + // 로그인되었는데 관리자(member->is_admin!=1)가 아니면 오류 표시 + if($logged_info->is_admin != 'Y') { + $this->setError(-1); + $this->setMessage('msg_is_not_administrator'); + return false; + } + + return true; + }/*}}}*/ + + /** + * 여기서부터는 action의 구현 + * request parameter의 경우 각 method의 첫번째 인자로 넘어온다 + * + * dispXXXX : 출력을 위한 method, output에 tpl file이 지정되어야 한다 + * procXXXX : 처리를 위한 method, output에는 error, message가 지정되어야 한다 + * + * 변수의 사용은 Context::get('이름')으로 얻어오면 된다 + **/ + + // 출력부분 + function dispAdminIndex() {/*{{{*/ + $this->setTemplateFile('index'); + }/*}}}*/ + + function dispLogin() {/*{{{*/ + if(Context::get('is_logged')) return $this->dispAdminIndex(); + $this->setTemplateFile('login_form'); + }/*}}}*/ + + function dispLogout() {/*{{{*/ + if(!Context::get('is_logged')) return $this->dispAdminIndex(); + $this->setTemplateFile('logout'); + }/*}}}*/ + + function dispError() {/*{{{*/ + Context::set('error_msg', Context::getLang( Context::get('msg_code') ) ); + $this->setTemplateFile('error'); + }/*}}}*/ + + // 실행부분 + function procLogin() {/*{{{*/ + // 아이디, 비밀번호를 받음 + $user_id = Context::get('user_id'); + $password = Context::get('password'); + // member모듈 객체 생성 + $oMember = getModule('member'); + return $oMember->doLogin($user_id, $password); + }/*}}}*/ + + function procLogout() {/*{{{*/ + // member모듈 객체 생성 + $oMember = getModule('member'); + return $oMember->doLogout(); + }/*}}}*/ + + /** + * 여기부터는 이 모듈과 관련된 라이브러리 개념의 method들 + **/ + + function getLayoutPath() {/*{{{*/ + return $this->template_path; + }/*}}}*/ + + function getLayoutTpl() {/*{{{*/ + return "layout.html"; + }/*}}}*/ + } +?> diff --git a/modules/admin/lang/ko.lang.php b/modules/admin/lang/ko.lang.php new file mode 100644 index 000000000..c257e9fe9 --- /dev/null +++ b/modules/admin/lang/ko.lang.php @@ -0,0 +1,9 @@ + + * @desc : 한국어 언어팩 (기본적인 내용만 수록) + **/ + + $lang->msg_is_not_administrator = '관리자만 접속이 가능합니다'; +?> diff --git a/modules/admin/module.xml b/modules/admin/module.xml new file mode 100644 index 000000000..4a62a35d3 --- /dev/null +++ b/modules/admin/module.xml @@ -0,0 +1,11 @@ + + + 관리자 툴 + Admin tool + + 제로 + zero + 모듈 관리 툴 + Admin tool + + diff --git a/modules/admin/skins/default/css/admin.css b/modules/admin/skins/default/css/admin.css new file mode 100644 index 000000000..e1bd94a38 --- /dev/null +++ b/modules/admin/skins/default/css/admin.css @@ -0,0 +1,22 @@ +#admin_title { + font-weight:bold; + float:left; + height:30px; +} + +#admin_info { + float:right; + height:30px; +} + +#admin_module_list { + clear:both; + float:left; +} + +#admin_module_content { + position:relative; + margin-left:150px; + left:0px; + top:30px; +} diff --git a/modules/admin/skins/default/error.html b/modules/admin/skins/default/error.html new file mode 100644 index 000000000..fbdcbcd39 --- /dev/null +++ b/modules/admin/skins/default/error.html @@ -0,0 +1 @@ +{$error_msg} diff --git a/modules/admin/skins/default/filter/filter.login.xml b/modules/admin/skins/default/filter/filter.login.xml new file mode 100644 index 000000000..26ec5aab1 --- /dev/null +++ b/modules/admin/skins/default/filter/filter.login.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/modules/admin/skins/default/filter/filter.logout.xml b/modules/admin/skins/default/filter/filter.logout.xml new file mode 100644 index 000000000..3c1f3a9f1 --- /dev/null +++ b/modules/admin/skins/default/filter/filter.logout.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/modules/admin/skins/default/index.html b/modules/admin/skins/default/index.html new file mode 100644 index 000000000..5ad28e227 --- /dev/null +++ b/modules/admin/skins/default/index.html @@ -0,0 +1 @@ +haha diff --git a/modules/admin/skins/default/js/admin.js b/modules/admin/skins/default/js/admin.js new file mode 100644 index 000000000..109f9c9e7 --- /dev/null +++ b/modules/admin/skins/default/js/admin.js @@ -0,0 +1,27 @@ +/** + * @file : modules/admin/js/admin.js + * @author : zero + * @desc : admin 모듈의 javascript + **/ + +// 현재 페이지 reload +function procReload(ret_obj, response_tags) { + var error = ret_obj['error']; + var message = ret_obj['message']; + + location.href = location.href; +} + +// 로그아웃 +function procLogout(ret_obj, response_tags) { + var error = ret_obj['error']; + var message = ret_obj['message']; + + location.href = "./admin.php"; +} + +// 로그인폼에서 아이디 포커스 +function procAdminLoginFocus() { + var fo = xGetElementById('user_id'); + if(fo) fo.focus(); +} diff --git a/modules/admin/skins/default/layout.html b/modules/admin/skins/default/layout.html new file mode 100644 index 000000000..b58a6776c --- /dev/null +++ b/modules/admin/skins/default/layout.html @@ -0,0 +1,21 @@ + + + + + + + +
+ +
style="font-weight:bold;"> + {$module_title} +
+ +
+
+ {$content} +
+ + diff --git a/modules/admin/skins/default/login_form.html b/modules/admin/skins/default/login_form.html new file mode 100644 index 000000000..fe228544b --- /dev/null +++ b/modules/admin/skins/default/login_form.html @@ -0,0 +1,30 @@ + + + +
+ + + + + + + + + + + + + + + + +
{$lang->user_id}
{$lang->password}
+ + +
+ +
+ + diff --git a/modules/admin/skins/default/logout.html b/modules/admin/skins/default/logout.html new file mode 100644 index 000000000..9c271b427 --- /dev/null +++ b/modules/admin/skins/default/logout.html @@ -0,0 +1,21 @@ + + + +
+ + + + + + + + + + + +
{$lang->cmd_logout}
{$lang->confirm_logout}
+ + +
+ +
diff --git a/modules/board/admin/category_list.html b/modules/board/admin/category_list.html new file mode 100644 index 000000000..837a4e4f3 --- /dev/null +++ b/modules/board/admin/category_list.html @@ -0,0 +1,57 @@ + + + + + + +
+ + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
{$lang->category_title}{$lang->document_count}{$lang->last_update}{$lang->cmd_modify}{$lang->cmd_move}{$lang->cmd_delete}
{$lang->msg_category_is_null}
{$category_info->title}{number_format($category_info->document_count)}{zdate($category_info->last_update,"Y-m-d H:i:s")}{$lang->cmd_modify}{$lang->cmd_move_up}{$lang->cmd_move_down}{$lang->cmd_delete}
+
+ + +
+ + + + + + +
+ {$lang->category_title} : + + +
+ +
diff --git a/modules/board/admin/category_update_form.html b/modules/board/admin/category_update_form.html new file mode 100644 index 000000000..0c45b09fb --- /dev/null +++ b/modules/board/admin/category_update_form.html @@ -0,0 +1,21 @@ + + + + + + +
+ + + + + +
+ {$lang->category_title} : + + + +
+ +
+ diff --git a/modules/board/admin/delete_form.html b/modules/board/admin/delete_form.html new file mode 100644 index 000000000..02136ac7c --- /dev/null +++ b/modules/board/admin/delete_form.html @@ -0,0 +1,34 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + +
{$lang->confirm_delete}
{$lang->module_name}{$module_info->mid}
{$lang->module}{$module_info->module}
{$lang->document_count}{$module_info->document_count}
+ + +
+ +
+ diff --git a/modules/board/admin/filter/filter.delete_module.xml b/modules/board/admin/filter/filter.delete_module.xml new file mode 100644 index 000000000..ce7bba07c --- /dev/null +++ b/modules/board/admin/filter/filter.delete_module.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/modules/board/admin/filter/filter.insert.xml b/modules/board/admin/filter/filter.insert.xml new file mode 100644 index 000000000..6152deb8d --- /dev/null +++ b/modules/board/admin/filter/filter.insert.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/modules/board/admin/filter/filter.insert_category.xml b/modules/board/admin/filter/filter.insert_category.xml new file mode 100644 index 000000000..2f67d5148 --- /dev/null +++ b/modules/board/admin/filter/filter.insert_category.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/modules/board/admin/filter/filter.insert_grant.xml b/modules/board/admin/filter/filter.insert_grant.xml new file mode 100644 index 000000000..7b1abcf77 --- /dev/null +++ b/modules/board/admin/filter/filter.insert_grant.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/modules/board/admin/filter/filter.update_category.xml b/modules/board/admin/filter/filter.update_category.xml new file mode 100644 index 000000000..ed18f9b9d --- /dev/null +++ b/modules/board/admin/filter/filter.update_category.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/modules/board/admin/grant_list.html b/modules/board/admin/grant_list.html new file mode 100644 index 000000000..ee9990736 --- /dev/null +++ b/modules/board/admin/grant_list.html @@ -0,0 +1,45 @@ + + + +
+ + + + + +
+ {$lang->about_grant} +
+ + + + + + + + + + + + + + + +
{$lang->grant}{$lang->target}
{$lang->grant_title[$val]} +
+ + + grant)&&in_array($v->group_srl,$module_info->grant[$val]))-->checked="true"/> + + + +
+
+ + +
+
+ +
+ +
diff --git a/modules/board/admin/header.html b/modules/board/admin/header.html new file mode 100644 index 000000000..8c64bd215 --- /dev/null +++ b/modules/board/admin/header.html @@ -0,0 +1,14 @@ + + +
+ [{$lang->cmd_list}] + style="font-weight:bold">[{$lang->cmd_view_info}] + style="font-weight:bold">[{$lang->cmd_manage_category}] + style="font-weight:bold">[{$lang->cmd_manage_grant}] + style="font-weight:bold">[{$lang->cmd_manage_skin}] +
+
+ {$lang->mid} : {$module_info->mid} + ({$lang->cmd_move}) + [{$lang->is_default}] +
diff --git a/modules/board/admin/info.html b/modules/board/admin/info.html new file mode 100644 index 000000000..6cdb08b7c --- /dev/null +++ b/modules/board/admin/info.html @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{$lang->skin}{$module_info->skin}
{$lang->use_category}{$lang->use}{$lang->notuse}
{$lang->browser_title}{$module_info->browser_title}
{$lang->description}{nl2br($module_info->description)}
{$lang->header_text}{$module_info->header_text}
{$lang->footer_text}{$module_info->footer_text}
{$lang->admin_id}{$module_info->admin_id}
+ +
diff --git a/modules/board/admin/insert_form.html b/modules/board/admin/insert_form.html new file mode 100644 index 000000000..d9ddb0ce3 --- /dev/null +++ b/modules/board/admin/insert_form.html @@ -0,0 +1,99 @@ + + + +
+ + {$lang->msg_new_module} + + {$lang->msg_update_module} + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{$lang->mid}
{$lang->about_mid}
{$lang->skin} + +
{$lang->about_skin}
{$lang->use_category}use_category=='Y')-->checked="true" />
{$lang->about_use_category}
{$lang->browser_title}
{$lang->about_browser_title}
{$lang->is_default}is_default=='Y')-->checked="true"/>
{$lang->about_default}
{$lang->description}
{$lang->about_description}
{$lang->header_text}
{$lang->about_header_text}
{$lang->footer_text}
{$lang->about_footer_text}
{$lang->admin_id}
{$lang->about_admin_id}
+ + +
+
diff --git a/modules/board/admin/js/admin.js b/modules/board/admin/js/admin.js new file mode 100644 index 000000000..6a53ad5ca --- /dev/null +++ b/modules/board/admin/js/admin.js @@ -0,0 +1,95 @@ +/** + * @file : modules/board/js/admin.js + * @author : zero + * @desc : board 모듈의 관리자용 javascript + **/ + +/* 모듈 생성 후 */ +function procInsert(ret_obj, response_tags) { + var error = ret_obj['error']; + var message = ret_obj['message']; + var sid = ret_obj['sid']; + var act = ret_obj['act']; + var page = ret_obj['page']; + var module_srl = ret_obj['module_srl']; + alert(message); + + url = "./admin.php?sid="+sid+"&module_srl="+module_srl+"&page="+page+"&act="+act; + location.href = url; +} + +/* 모듈 삭제 후 */ +function procDelete(ret_obj, response_tags) { + var error = ret_obj['error']; + var message = ret_obj['message']; + var sid = ret_obj['sid']; + var act = ret_obj['act']; + var page = ret_obj['page']; + alert(message); + + url = "./admin.php?sid="+sid+"&page="+page+"&act="+act; + location.href = url; +} + +/* 카테고리 관련 작업들 */ +function doUpdateCategory(category_srl, mode, message) { + if(typeof(message)!='undefined'&&!confirm(message)) return; + + var fo_obj = xGetElementById('fo_category_info'); + fo_obj.category_srl.value = category_srl; + fo_obj.mode.value = mode; + + procFormFilter(fo_obj, update_category, procReload); +} + +/* 카테고리 정보 수정 후 */ +function procUpdateCategory(ret_obj, response_tags) { + var error = ret_obj['error']; + var message = ret_obj['message']; + var module_srl = ret_obj['module_srl']; + alert(message); + + var url = "./admin.php?sid=board&module_srl="+module_srl+"&act=dispCategoryInfo"; + location.href = url; +} + +/* 메세지 출력후 현페이지 리로드 */ +function procReload(ret_obj, response_tags) { + var error = ret_obj['error']; + var message = ret_obj['message']; + if(message) alert(message); + location.href = location.href; +} + +/* 권한 관련 */ +function procSelectAll(obj, key) { + var fo_obj = obj.parentNode; + while(fo_obj.nodeName != 'FORM') { fo_obj = fo_obj.parentNode; } + for(var i=0;i + + +
+ {number_format($total_count)}, + {$lang->page_count} : {number_format($page)} / {number_format($total_page)} +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
{$lang->no}{$lang->mid}{$lang->browser_title}{$lang->is_default}{$lang->skin}{$lang->admin_id}{$lang->regdate}{$lang->cmd_move}{$lang->cmd_delete}
{$no}{$val->mid}{$val->browser_title}{$val->is_default}{$val->skin}{$val->admin_id}{zdate($val->regdate,"Y-m-d")}{$lang->cmd_move}{$lang->cmd_delete}
+
+ + + + + +
+ [{$lang->first_page}] + + + + {$page_no} + + [{$page_no}] + + + + [{$lang->last_page}] +
diff --git a/modules/board/admin/skin_info.html b/modules/board/admin/skin_info.html new file mode 100644 index 000000000..eeadada40 --- /dev/null +++ b/modules/board/admin/skin_info.html @@ -0,0 +1,119 @@ + + +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{$lang->skin_default_info}
{$lang->skin}{$skin_info->title}
{$lang->skin_maker}{$skin_info->maker->name} ({$skin_info->maker->email_address})
{$lang->skin_maker_homepage}{$skin_info->maker->homepage}
{$lang->date}{$skin_info->maker->date}
{$lang->description}{nl2br($skin_info->maker->description)}
{$lang->colorset} + +
+ + {$val->title} + + colorset==$val->name)-->checked="true"/> + +
+ +
+
+ + +
+ + + + + + + + + + + + + + + + + +
{$lang->extra_vars}
description)-->rowspan="2">{$val->title} + + + + + + + + + + + + + value))-->checked="true"/> + + + + + + + + value)-->checked="true"/> + + + + + + +
+
+ + +
+ + + + +
{nl2br($val->description)}
+
+ + +
+ +
+ +
diff --git a/modules/board/board.admin.php b/modules/board/board.admin.php new file mode 100644 index 000000000..69ea95820 --- /dev/null +++ b/modules/board/board.admin.php @@ -0,0 +1,403 @@ + + * @desc : board의 관리자 파일 + * Module class에서 상속을 받아서 사용 + * action 의 경우 disp/proc 2가지만 존재하며 이는 action명세서에 + * 미리 기록을 하여야 함 + **/ + + class board_admin extends Module { + + /** + * 기본 action 지정 + * $act값이 없거나 잘못된 값이 들어올 경우 $default_act 값으로 진행 + **/ + var $default_act = 'dispContent'; + + /** + * 현재 모듈의 초기화를 위한 작업을 지정해 놓은 method + * css/js파일의 load라든지 lang파일 load등을 미리 선언 + * + * Init() => 공통 + * dispInit() => disp시에 + * procInit() => proc시에 + * + * $this->module_path는 현재 이 모듈파일의 위치를 나타낸다 + * (ex: $this->module_path = "./modules/system_install/"; + **/ + + // 초기화 + function init() {/*{{{*/ + // 기본 정보를 읽음 + Context::loadLang($this->module_path.'lang'); + + // 스킨의 종류를 읽음 + $oModule = getModule('module_manager'); + $skins = $oModule->getSkins($this->module_path); + Context::set('skins', $skins); + }/*}}}*/ + + // disp 초기화 + function dispInit() {/*{{{*/ + // module_srl이 있으면 미리 체크하여 존재하는 모듈이면 module_info 세팅 + $module_srl = Context::get('module_srl'); + if($module_srl) { + $oModule = getModule('module_manager'); + $module_info = $oModule->getModuleInfoByModuleSrl($module_srl); + if(!$module_info) { + Context::set('module_srl',''); + $this->act = 'dispContent'; + } else Context::set('module_info',$module_info); + } + + return true; + }/*}}}*/ + + // proc 초기화 + function procInit() {/*{{{*/ + return true; + }/*}}}*/ + + /** + * 여기서부터는 action의 구현 + * request parameter의 경우 각 method의 첫번째 인자로 넘어온다 + * + * dispXXXX : 출력을 위한 method, output에 tpl file이 지정되어야 한다 + * procXXXX : 처리를 위한 method, output에는 error, message가 지정되어야 한다 + **/ + + // 출력 부분 + function dispContent() {/*{{{*/ + + // 등록된 board 모듈을 불러와 세팅 + $oDB = &DB::getInstance(); + $args->sort_index = "module_srl"; + $args->page = Context::get('page'); + $args->list_count = 40; + $args->page_count = 10; + $output = $oDB->executeQuery('board.getBoardList', $args); + + // 템플릿에 쓰기 위해서 context::set + Context::set('total_count', $output->total_count); + Context::set('total_page', $output->total_page); + Context::set('page', $output->page); + Context::set('board_list', $output->data); + Context::set('page_navigation', $output->page_navigation); + + // 템플릿 파일 지정 + $this->setTemplateFile('list'); + }/*}}}*/ + + function dispInfo() {/*{{{*/ + if(!Context::get('module_srl')) return $this->dispContent(); + + // 템플릿 파일 지정 + $this->setTemplateFile('info'); + }/*}}}*/ + + function dispCategoryInfo() {/*{{{*/ + $module_srl = Context::get('module_srl'); + + // 카테고리의 목록을 구해옴 + $oDocument = getModule('document'); + $category_list = $oDocument->getCategoryList($module_srl); + Context::set('category_list', $category_list); + + // 수정하려는 카테고리가 있다면해당 카테고리의 정보를 가져옴 + $category_srl = Context::get('category_srl'); + if($category_srl) { + $selected_category = $oDocument->getCategory($category_srl); + if(!$selected_category) Context::set('category_srl',''); + else Context::set('selected_category',$selected_category); + $this->setTemplateFile('category_update_form'); + } else { + $this->setTemplateFile('category_list'); + } + }/*}}}*/ + + function dispGrantInfo() {/*{{{*/ + $module_srl = Context::get('module_srl'); + + // 현 모듈의 권한 목록을 가져옴 + $oBoard = getModule('board'); + $grant_list = $oBoard->grant_list; + + // 권한 목록 세팅 + Context::set('grant_list', $grant_list); + + // 권한 그룹의 목록을 가져온다 + $oMember = getModule('member'); + $group_list = $oMember->getGroups(); + Context::set('group_list', $group_list); + + $this->setTemplateFile('grant_list'); + }/*}}}*/ + + function dispSkinInfo() {/*{{{*/ + // 현재 선택된 모듈의 스킨의 정보 xml 파일을 읽음 + $module_info = Context::get('module_info'); + $skin = $module_info->skin; + + $oModule = getModule('module_manager'); + $skin_info = $oModule->loadSkinInfo($this->module_path, $skin); + + // skin_info에 extra_vars 값을 지정 + if(count($skin_info->extra_vars)) { + foreach($skin_info->extra_vars as $key => $val) { + $name = $val->name; + $type = $val->type; + $value = $module_info->{$name}; + if($type=="checkbox"&&!$value) $value = array(); + $skin_info->extra_vars[$key]->value= $value; + } + } + + Context::set('skin_info', $skin_info); + $this->setTemplateFile('skin_info'); + }/*}}}*/ + + function dispInsert() {/*{{{*/ + // 템플릿 파일 지정 + $this->setTemplateFile('insert_form'); + }/*}}}*/ + + function dispDeleteForm() {/*{{{*/ + if(!Context::get('module_srl')) return $this->dispContent(); + + $module_info = Context::get('module_info'); + + $oDocument = getModule('document'); + $document_count = $oDocument->getDocumentCount($module_info->module_srl); + $module_info->document_count = $document_count; + + Context::set('module_info',$module_info); + + // 템플릿 파일 지정 + $this->setTemplateFile('delete_form'); + }/*}}}*/ + + // 실행 부분 + function procInsert() {/*{{{*/ + // 일단 입력된 값들을 모두 받아서 db 입력항목과 그외 것으로 분리 + $args = Context::gets('module_srl','mid','skin','use_category','browser_title','description','is_default','header_text','footer_text','admin_id'); + $args->module = 'board'; + if($args->is_default!='Y') $args->is_default = 'N'; + if($args->use_category!='Y') $args->use_category = 'N'; + + // 기본 값외의 것들을 정리 + $extra_var = delObjectVars(Context::getRequestVars(), $args); + unset($extra_var->sid); + unset($extra_var->act); + unset($extra_var->page); + + // module_srl이 있으면 원본을 구해온다 + $oModule = getModule('module_manager'); + + // module_srl이 넘어오면 원 모듈이 있는지 확인 + if($args->module_srl) { + $module_info = $oModule->getModuleInfoByModuleSrl($args->module_srl); + // 만약 원래 모듈이 없으면 새로 입력하기 위한 처리 + if($module_info->module_srl != $args->module_srl) unset($args->module_srl); + } + + // $extra_var를 serialize + $args->extra_var = serialize($extra_var); + + // is_default=='Y' 이면 + if($args->is_default=='Y') $oModule->clearDefaultModule(); + + // module_srl의 값에 따라 insert/update + if(!$args->module_srl) { + $output = $oModule->insertModule($args); + $msg_code = 'success_registed'; + } else { + $output = $oModule->updateModule($args); + $msg_code = 'success_updated'; + } + + if(!$output->toBool()) return $output; + + $this->add('sid','board'); + $this->add('act','dispInfo'); + $this->add('page',Context::get('page')); + $this->add('module_srl',$output->get('module_srl')); + $this->setMessage($msg_code); + }/*}}}*/ + + function procDelete() {/*{{{*/ + $module_srl = Context::get('module_srl'); + + // 원본을 구해온다 + $oModule = getModule('module_manager'); + $output = $oModule->deleteModule($module_srl); + if(!$output->toBool()) return $output; + + $this->add('sid','board'); + $this->add('act','dispContent'); + $this->add('page',Context::get('page')); + $this->setMessage('success_deleted'); + }/*}}}*/ + + function procInsertCategory() {/*{{{*/ + // 일단 입력된 값들을 모두 받아서 db 입력항목과 그외 것으로 분리 + $module_srl = Context::get('module_srl'); + $category_title = Context::get('category_title'); + + // module_srl이 있으면 원본을 구해온다 + $oDocument = getModule('document'); + $output = $oDocument->insertCategory($module_srl, $category_title); + if(!$output->toBool()) return $output; + + $this->add('sid','board'); + $this->add('act','dispCategoryInfo'); + $this->add('page',Context::get('page')); + $this->add('module_srl',$module_srl); + $this->setMessage('success_registed'); + }/*}}}*/ + + function procUpdateCategory() {/*{{{*/ + $category_srl = Context::get('category_srl'); + $mode = Context::get('mode'); + + $oDocument = getModule('document'); + + switch($mode) { + case 'up' : + $output = $oDocument->moveCategoryUp($category_srl); + $msg_code = 'success_moved'; + break; + case 'down' : + $output = $oDocument->moveCategoryDown($category_srl); + $msg_code = 'success_moved'; + break; + case 'delete' : + $output = $oDocument->deleteCategory($category_srl); + $msg_code = 'success_deleted'; + break; + case 'update' : + $selected_category = $oDocument->getCategory($category_srl); + $args->category_srl = $selected_category->category_srl; + $args->title = Context::get('category_title'); + $args->list_order = $selected_category->list_order; + $output = $oDocument->updateCategory($args); + $msg_code = 'success_updated'; + break; + } + if(!$output->toBool()) return $output; + $this->add('module_srl', $selected_category->module_srl); + $this->setMessage($msg_code); + }/*}}}*/ + + function procUpdateSkinInfo() {/*{{{*/ + // module_srl에 해당하는 정보들을 가져오기 + $module_srl = Context::get('module_srl'); + $oModule = getModule('module_manager'); + $module_info = $oModule->getModuleInfoByModuleSrl($module_srl); + $skin = $module_info->skin; + + // 스킨의 정볼르 구해옴 (extra_vars를 체크하기 위해서) + $oModule = getModule('module_manager'); + $skin_info = $oModule->loadSkinInfo($this->module_path, $skin); + + // 입력받은 변수들을 체크 (sid, act, module_srl, page등 기본적인 변수들 없앰) + $obj = Context::getRequestVars(); + unset($obj->sid); + unset($obj->act); + unset($obj->module_srl); + unset($obj->page); + + // 원 skin_info에서 extra_vars의 type이 image일 경우 별도 처리를 해줌 + if($skin_info->extra_vars) { + foreach($skin_info->extra_vars as $vars) { + if($vars->type!='image') continue; + + $image_obj = $obj->{$vars->name}; + + // 삭제 요청에 대한 변수를 구함 + $del_var = $obj->{"del_".$vars->name}; + unset($obj->{"del_".$vars->name}); + if($del_var == 'Y') { + @unlink($module_info->{$vars->name}); + continue; + } + + // 업로드 되지 않았다면 이전 데이터를 그대로 사용 + if(!$image_obj['tmp_name']) { + $obj->{$vars->name} = $module_info->{$vars->name}; + continue; + } + + // 정상적으로 업로드된 파일이 아니면 무시 + if(!is_uploaded_file($image_obj['tmp_name'])) { + unset($obj->{$vars->name}); + continue; + } + + // 이미지 파일이 아니어도 무시 + if(!eregi("\.(jpg|jpeg|gif|png)$", $image_obj['name'])) { + unset($obj->{$vars->name}); + continue; + } + + // 경로를 정해서 업로드 + $path = sprintf("./files/attach/images/%s/", $module_srl); + + // 디렉토리 생성 + if(!FileHandler::makeDir($path)) return false; + + $filename = $path.$image_obj['name']; + + // 파일 이동 + if(!move_uploaded_file($image_obj['tmp_name'], $filename)) { + unset($obj->{$vars->name}); + continue; + } + + // 변수를 바꿈 + unset($obj->{$vars->name}); + $obj->{$vars->name} = $filename; + } + } + + // serialize하여 저장 + $extra_vars = serialize($obj); + + $oModule = getModule('module_manager'); + $oModule->updateModuleExtraVars($module_srl, $extra_vars); + + $url = sprintf("./admin.php?sid=%s&module_srl=%s&act=dispSkinInfo&page=%s", 'board', $module_srl, Context::get('page')); + print ""; + exit(); + }/*}}}*/ + + function procInsertGrant() {/*{{{*/ + $module_srl = Context::get('module_srl'); + + // 현 모듈의 권한 목록을 가져옴 + $oBoard = getModule('board'); + $grant_list = $oBoard->grant_list; + + if(count($grant_list)) { + foreach($grant_list as $grant) { + $arr_grant[$grant] = explode(',',Context::get($grant)); + } + $grant = serialize($arr_grant); + } + + $oModule = getModule('module_manager'); + $oModule->updateModuleGrant($module_srl, $grant); + + $this->add('sid','board'); + $this->add('act','dispGrantInfo'); + $this->add('page',Context::get('page')); + $this->add('module_srl',Context::get('module_srl')); + $this->setMessage('success_registed'); + }/*}}}*/ + + /** + * 여기부터는 이 모듈과 관련된 라이브러리 개념의 method들 + **/ + } +?> diff --git a/modules/board/board.module.php b/modules/board/board.module.php new file mode 100644 index 000000000..059ea10c0 --- /dev/null +++ b/modules/board/board.module.php @@ -0,0 +1,667 @@ + + * @desc : 기본 모듈중의 하나인 board module + * Module class에서 상속을 받아서 사용 + * action 의 경우 disp/proc 2가지만 존재하며 이는 action명세서에 + * 미리 기록을 하여야 함 + **/ + + class board extends Module { + + /** + * 기본 action 지정 + * $act값이 없거나 잘못된 값이 들어올 경우 $default_act 값으로 진행 + **/ + var $default_act = 'dispContent'; + + // 검색 옵션 + var $search_option = array('title','content','title_content','user_name'); + + // 모듈에서 사용할 변수들 + var $skin = "default"; + var $list_count = 3; + var $page_count = 10; + var $category_list = NULL; + + // 권한의 종류를 미리 설정 + var $grant_list = array( + 'list', + 'view', + 'write_document', + 'write_comment', + 'fileupload', + 'management', + ); + + // 에디터 + var $editor = 'default'; + + /** + * 현재 모듈의 초기화를 위한 작업을 지정해 놓은 method + * css/js파일의 load라든지 lang파일 load등을 미리 선언 + * + * Init() => 공통 + * dispInit() => disp시에 + * procInit() => proc시에 + * + * $this->module_path는 현재 이 모듈파일의 위치를 나타낸다 + * (ex: $this->module_path = "./modules/system_install/"; + **/ + + // 초기화 + function init() {/*{{{*/ + }/*}}}*/ + + // disp 초기화 + function dispInit() {/*{{{*/ + // lang + Context::loadLang($this->template_path.'lang/'); + + // 카테고리를 사용한다면 카테고리 목록을 구해옴 + if($this->module_info->use_category=='Y') { + $oDocument = getModule('document'); + $this->category_list = $oDocument->getCategoryList($this->module_srl); + Context::set('category_list', $this->category_list); + } + + // 에디터 세팅 + Context::set('editor', $this->editor); + $editor_path = sprintf("./editor/%s/", $this->editor); + Context::set('editor_path', $editor_path); + Context::loadLang($editor_path); + + return true; + }/*}}}*/ + + // proc 초기화 + function procInit() {/*{{{*/ + // lang + Context::loadLang($this->template_path.'lang/'); + + // 파일 업로드일 경우 $act값을 procUploadFile() 로 변경 + if(Context::isUploaded()) $this->act = 'procUploadFile'; + + return true; + }/*}}}*/ + + /** + * 여기서부터는 action의 구현 + * request parameter의 경우 각 method의 첫번째 인자로 넘어온다 + * + * dispXXXX : 출력을 위한 method, output에 tpl file이 지정되어야 한다 + * procXXXX : 처리를 위한 method, output에는 error, message가 지정되어야 한다 + **/ + + // 출력 부분 + function dispContent() {/*{{{*/ + // 목록 구현에 필요한 변수들을 가져온다 + $document_srl = Context::get('document_srl'); + $page = Context::get('page'); + + // document 객체를 생성. 기본 데이터 구조의 경우 document모듈만 쓰면 만사 해결.. -_-; + $oDocument = getModule('document'); + + // document_srl이 있다면 해당 글을 구해오자 + if($document_srl) { + $document = $oDocument->getDocument($document_srl); + + // 글이 찾아지지 않으면 무효화 + if(!$document) { + Context::set('document_srl',''); + $document_srl = NULL; + unset($document); + } + } + + // 글이 찾아지면 조회수 업데이트 및 기타 등등 + if($document) { + + // 비밀글이고 권한이 없을 경우 인증페이지로 + if($document->is_secret=='Y' && !$document->is_granted) return $this->setTemplateFile('input_password_form'); + + // 조회수 업데이트 + if($oDocument->updateReadedCount($document_srl)) $document->readed_count++; + + // 댓글 가져오기 + if($document->comment_count && $document->allow_comment == 'Y') { + $oComment = getModule('comment'); + $comment_list = $oComment->getCommentList($document_srl); + Context::set('comment_list', $comment_list); + } + + // 트랙백 가져오기 + if($document->trackback_count && $document->allow_trackback == 'Y') { + $oTrackback = getModule('trackback'); + $trackback_list = $oTrackback->getTrackbackList($document_srl); + Context::set('trackback_list', $trackback_list); + } + + // 첨부파일 가져오기 + if($document->uploaded_count) { + $file_list = $oDocument->getFiles($document_srl); + $document->uploaded_list = $file_list; + } + + Context::set('document', $document); + } + + // 만약 document_srl은 있는데 page가 없다면 글만 호출된 경우, + // 그럼 page를 구해서 세팅해주자.. + if($document_srl && !$page) { + $page = $oDocument->getDocumentPage($document_srl, $this->module_srl, $this->list_count); + Context::set('page', $page); + } + + // 검색옵션 + $search_target = Context::get('search_target'); + $keyword = Context::get('keyword'); + if($search_target && $keyword) { + $keyword = str_replace(' ','%',$keyword); + switch($search_target) { + case 'title' : + $search_obj->s_title = $keyword; + break; + case 'content' : + $search_obj->s_content = $keyword; + break; + case 'title_content' : + $search_obj->s_title = $keyword; + $search_obj->s_content = $keyword; + break; + case 'user_name' : + $search_obj->s_user_name = $keyword; + break; + } + } + + // 카테고리 + $category = Context::get('category'); + if($category) $search_obj->category_srl = $category; + + // 목록의 경우 document->getDocumentList 에서 걍 알아서 다 해버리는 구조이다... (아.. 이거 나쁜 버릇인데.. ㅡ.ㅜ 어쩔수 없다) + $output = $oDocument->getDocumentList($this->module_srl, 'list_order', $page, $this->list_count, $this->page_count, $search_obj); + + // 템플릿에 쓰기 위해서 context::set + Context::set('total_count', $output->total_count); + Context::set('total_page', $output->total_page); + Context::set('page', $output->page); + Context::set('document_list', $output->data); + Context::set('page_navigation', $output->page_navigation); + + // 템플릿에서 사용할 검색옵션 세팅 + $count_search_option = count($this->search_option); + for($i=0;$i<$count_search_option;$i++) { + $search_option[$this->search_option[$i]] = Context::getLang($this->search_option[$i]); + } + Context::set('search_option', $search_option); + + $this->setTemplateFile('list'); + }/*}}}*/ + + function dispWriteForm() {/*{{{*/ + // 목록 구현에 필요한 변수들을 가져온다 + $document_srl = Context::get('document_srl'); + + // document 모듈 객체 생성 + $oDocument = getModule('document'); + + // 지정된 글이 없다면 (신규) 새로운 번호를 만든다 + if(!$document_srl) { + $oDB = &DB::getInstance(); + $document_srl = $oDB->getNextSequence(); + + // 글의 수정일 경우 원본 글을 가져와서 확인을 한다 + } else { + $document = $oDocument->getDocument($document_srl); + if(!$document) { + $oDB = &DB::getInstance(); + $document_srl = $oDB->getNextSequence(); + } + } + + // 글을 수정하려고 할 경우 권한이 없는 경우 비밀번호 입력화면으로 + if($document&&!$document->is_granted) return $this->setTemplateFile('input_password_form'); + + Context::set('document_srl',$document_srl); + Context::set('document', $document); + + $this->setTemplateFile('write_form'); + }/*}}}*/ + + function dispDeleteForm() {/*{{{*/ + // 삭제할 문서번호를 가져온다 + $document_srl = Context::get('document_srl'); + + // 지정된 글이 있는지 확인 + if($document_srl) { + $oDocument = getModule('document'); + $document = $oDocument->getDocument($document_srl); + } + + // 삭제하려는 글이 없으면 에러 + if(!$document) return $this->dispContent(); + + // 권한이 없는 경우 비밀번호 입력화면으로 + if($document&&!$document->is_granted) return $this->setTemplateFile('input_password_form'); + + Context::set('document',$document); + + $this->setTemplateFile('delete_form'); + }/*}}}*/ + + function dispCommentModifyForm() {/*{{{*/ + // 목록 구현에 필요한 변수들을 가져온다 + $document_srl = Context::get('document_srl'); + $comment_srl = Context::get('comment_srl'); + + // 지정된 댓글이 없다면 오류 + if(!$comment_srl) return new Output(-1, 'msg_invalid_request'); + + // 해당 댓글를 찾아본다 + $oComment = getModule('comment'); + $comment = $oComment->getComment($comment_srl); + + // 댓글이 없다면 오류 + if(!$comment) return new Output(-1, 'msg_invalid_request'); + + // 글을 수정하려고 할 경우 권한이 없는 경우 비밀번호 입력화면으로 + if($comment_srl&&$comment&&!$_SESSION['own_comment'][$comment_srl]) return $this->setTemplateFile('input_password_form'); + + // 필요한 정보들 세팅 + Context::set('document_srl',$document_srl); + Context::set('comment_srl',$comment_srl); + Context::set('comment', $comment); + + $this->setTemplateFile('comment_form'); + }/*}}}*/ + + function dispCommentDeleteForm() {/*{{{*/ + // 삭제할 댓글번호를 가져온다 + $comment_srl = Context::get('comment_srl'); + + // 삭제하려는 댓글가 있는지 확인 + if($comment_srl) { + $oComment = getModule('comment'); + $comment = $oComment->getComment($comment_srl); + } + + // 삭제하려는 글이 없으면 에러 + if(!$comment) return $this->dispContent(); + + // 권한이 없는 경우 비밀번호 입력화면으로 + if($comment_srl&&$comment&&!$_SESSION['own_comment'][$comment_srl]) return $this->setTemplateFile('input_password_form'); + + Context::set('comment',$comment); + + $this->setTemplateFile('delete_comment_form'); + }/*}}}*/ + + function dispCommentReplyForm() {/*{{{*/ + // 목록 구현에 필요한 변수들을 가져온다 + $document_srl = Context::get('document_srl'); + $parent_srl = Context::get('comment_srl'); + + // 지정된 원 댓글이 없다면 오류 + if(!$parent_srl) return new Output(-1, 'msg_invalid_request'); + + // 해당 댓글를 찾아본다 + $oComment = getModule('comment'); + $source_comment = $oComment->getComment($parent_srl); + + // 댓글이 없다면 오류 + if(!$source_comment) return new Output(-1, 'msg_invalid_request'); + + // 필요한 정보들 세팅 + Context::set('document_srl',$document_srl); + Context::set('parent_srl',$parent_srl); + Context::set('comment_srl',NULL); + Context::set('source_comment',$source_comment); + + $this->setTemplateFile('comment_form'); + }/*}}}*/ + + function dispTrackbackDeleteForm() {/*{{{*/ + // 삭제할 댓글번호를 가져온다 + $trackback_srl = Context::get('trackback_srl'); + + // 삭제하려는 댓글가 있는지 확인 + $oTrackback = getModule('trackback'); + $output = $oTrackback->getTrackback($trackback_srl); + $trackback = $output->data; + + // 삭제하려는 글이 없으면 에러 + if(!$trackback) return $this->dispContent(); + + Context::set('trackback',$trackback); + + $this->setTemplateFile('delete_trackback_form'); + }/*}}}*/ + + function dispLogin() {/*{{{*/ + if(Context::get('is_logged')) return $this->dispContent(); + $this->setTemplateFile('login_form'); + }/*}}}*/ + + function dispLogout() {/*{{{*/ + if(!Context::get('is_logged')) return $this->dispContent(); + $this->setTemplateFile('logout'); + }/*}}}*/ + + function dispError() {/*{{{*/ + }/*}}}*/ + + function dispRss() {/*{{{*/ + $page = Context::get('page'); + + // rss 제목 및 정보등을 추출 + $info->title = Context::getBrowserTitle(); + $info->description = $this->module_info->description; + $info->language = Context::getLangType(); + $info->date = gmdate("D, d M Y H:i:s"); + $info->link = sprintf("%s?mid=%s", Context::getRequestUri(), Context::get('mid')); + + // 컨텐츠 추출 + $oDocument = getModule('document'); + $output = $oDocument->getDocumentList($this->module_srl, 'update_order', $page, 20, 20, NULL); + $document_list = $output->data; + + // 출력하고 끝내기 + $oRss = getModule('rss'); + $oRss->printRssDocument($info, $document_list); + exit(); + }/*}}}*/ + + function dispAdminIndex() {/*{{{*/ + $this->setTemplateFile('module_list'); + }/*}}}*/ + + // 실행 부분 + function procInsertDocument() {/*{{{*/ + // 글작성시 필요한 변수를 가져옴 + $obj = Context::getRequestVars(); + //$obj = Context::gets('document_srl','user_name','email_address','homepage','tags','title','content','password','allow_comment','lock_comment','allow_trackback','category_srl','is_notice','is_secret'); + $obj->module_srl = $this->module_srl; + if($obj->is_notice!='Y') $obj->is_notice = 'N'; + if($obj->is_secret!='Y') $obj->is_secret = 'N'; + if($obj->allow_comment!='Y') $obj->allow_comment = 'N'; + if($obj->lock_comment!='Y') $obj->lock_comment = 'N'; + if($obj->allow_trackback!='Y') $obj->allow_trackback = 'N'; + + // document module 객체 생성 + $oDocument = getModule('document'); + + // 첨부 파일의 갯수를 구함 + $obj->uploaded_count = $oDocument->getFilesCount($obj->document_srl); + + // 이미 존재하는 글인지 체크 + $document = $oDocument->getDocument($obj->document_srl); + + // 이미 존재하는 경우 수정 + if($document->document_srl == $obj->document_srl) { + $output = $oDocument->updateDocument($document, $obj); + $msg_code = 'success_updated'; + + // 그렇지 않으면 신규 등록 + } else { + $output = $oDocument->insertDocument($obj); + $msg_code = 'success_registed'; + $obj->document_srl = $output->get('document_srl'); + } + + // 트랙백 발송 + $trackback_url = Context::get('trackback_url'); + $trackback_charset = Context::get('trackback_charset'); + if($trackback_url) { + $oTrackback = getModule('trackback'); + $oTrackback->sendTrackback($obj, $trackback_url, $trackback_charset); + } + + if(!$output->toBool()) return $output; + $this->setMessage($msg_code); + $this->add('mid', Context::get('mid')); + $this->add('document_srl', $output->get('document_srl')); + }/*}}}*/ + + function procDeleteDocument() {/*{{{*/ + // 문서 번호 확인 + $document_srl = Context::get('document_srl'); + if(!$document_srl) return $this->doError('msg_invalid_document'); + + // 문서 있는지 확인 + $oDocument = getModule('document'); + $document = $oDocument->getDocument($document_srl); + if($document->document_srl!=$document_srl) return $this->doError('msg_invalid_document'); + + // 글 삭제 + $output = $oDocument->deleteDocument($document); + if(!$output->toBool()) return $output; + + $this->add('mid', Context::get('mid')); + $this->add('page', $output->get('page')); + $this->setMessage('success_deleted'); + }/*}}}*/ + + function procVoteDocument() {/*{{{*/ + $oDocument = getModule('document'); + $document_srl = Context::get('document_srl'); + return $oDocument->updateVotedCount($document_srl); + }/*}}}*/ + + function procInsertComment() {/*{{{*/ + // 댓글 입력에 필요한 데이터 추출 + $obj = Context::gets('document_srl','comment_srl','parent_srl','content','password','nick_name','user_name','member_srl','email_address','homepage'); + $obj->module_srl = $this->module_srl; + + // comment 객체 생성 + $oComment = getModule('comment'); + + // comment_srl이 없을 경우 신규 입력 + if(!$obj->comment_srl) { + // parent_srl이 있으면 답변으로 + if($obj->parent_srl) { + $comment = $oComment->getComment($obj->parent_srl); + if(!$comment) return new Output(-1, 'msg_invalid_request'); + $output = $oComment->insertComment($obj); + $comment_srl = $output->get('comment_srl'); + // 없으면 신규 + } else { + $output = $oComment->insertComment($obj); + } + + // comment_srl이 있으면 수정으로 + } else { + $comment = $oComment->getComment($obj->comment_srl); + if(!$comment) return new Output(-1, 'msg_invalid_request'); + + $obj->parent_srl = $comment->parent_srl; + $output = $oComment->updateComment($obj); + $comment_srl = $obj->comment_srl; + } + + if(!$output->toBool()) return $output; + $this->setMessage('success_registed'); + $this->add('mid', Context::get('mid')); + $this->add('document_srl', $obj->document_srl); + $this->add('comment_srl', $comment_srl); + }/*}}}*/ + + function procDeleteComment() {/*{{{*/ + // 댓글 번호 확인 + $comment_srl = Context::get('comment_srl'); + if(!$comment_srl) return $this->doError('msg_invalid_request'); + + // 삭제 + $oComment = getModule('comment'); + $output = $oComment->deleteComment($comment_srl); + if(!$output->toBool()) return $output; + + $this->add('mid', Context::get('mid')); + $this->add('page', Context::get('page')); + $this->add('document_srl', $output->get('document_srl')); + $this->setMessage('success_deleted'); + }/*}}}*/ + + function procReceiveTrackback() {/*{{{*/ + $obj = Context::gets('document_srl','url','title','excerpt'); + $oTrackback = getModule('trackback'); + $oTrackback->insertTrackback($obj); + }/*}}}*/ + + function procDeleteTrackback() {/*{{{*/ + $trackback_srl = Context::get('trackback_srl'); + $oTrackback = getModule('trackback'); + $output = $oTrackback->deleteTrackback($trackback_srl); + + $this->add('mid', Context::get('mid')); + $this->add('page', Context::get('page')); + $this->add('document_srl', $output->get('document_srl')); + $this->setMessage('success_deleted'); + }/*}}}*/ + + function procLogin() {/*{{{*/ + // 아이디, 비밀번호를 받음 + $user_id = Context::get('user_id'); + $password = Context::get('password'); + + // member모듈 객체 생성 + $oMember = getModule('member'); + return $oMember->doLogin($user_id, $password); + }/*}}}*/ + + function procLogout() {/*{{{*/ + // member모듈 객체 생성 + $oMember = getModule('member'); + return $oMember->doLogout(); + }/*}}}*/ + + function procVerificationPassword() {/*{{{*/ + // 비밀번호와 문서 번호를 받음 + $password = md5(Context::get('password')); + $document_srl = Context::get('document_srl'); + $comment_srl = Context::get('comment_srl'); + + // comment_srl이 있을 경우 댓글이 대상 + if($comment_srl) { + // 문서번호에 해당하는 글이 있는지 확인 + $oComment = getModule('comment'); + $data = $oComment->getComment($comment_srl); + // comment_srl이 없으면 문서가 대상 + } else { + // 문서번호에 해당하는 글이 있는지 확인 + $oDocument = getModule('document'); + $data = $oDocument->getDocument($document_srl); + } + + // 글이 없을 경우 에러 + if(!$data) return $this->doError('msg_invalid_request'); + + // 문서의 비밀번호와 입력한 비밀번호의 비교 + if($data->password != $password) return $this->doError('msg_invalid_password'); + + // 해당 글에 대한 권한 부여 + if($comment_srl) $_SESSION['own_comment'][$comment_srl] = true; + else $_SESSION['own_document'][$document_srl] = true; + }/*}}}*/ + + function procUploadFile() {/*{{{*/ + // 기본적으로 필요한 변수인 document_srl, module_srl을 설정 + $document_srl = Context::get('document_srl'); + $module_srl = $this->module_srl; + + // document모듈 객체 생성후 걍 넘겨버림 + $oDocument = getModule('document'); + $output = $oDocument->insertFile($module_srl, $document_srl); + print $this->printUploadedFileList($document_srl); + exit(); + }/*}}}*/ + + function procDeleteFile() {/*{{{*/ + // 기본적으로 필요한 변수인 document_srl, module_srl을 설정 + $document_srl = Context::get('document_srl'); + $module_srl = $this->module_srl; + $file_srl = Context::get('file_srl'); + + // document모듈 객체 생성후 걍 넘겨버림 + $oDocument = getModule('document'); + $output = $oDocument->deleteFile($file_srl); + print $this->printUploadedFileList($document_srl); + exit(); + }/*}}}*/ + + function procDownload() {/*{{{*/ + // 다운로드에 필요한 변수 체크 + $file_srl = Context::get('file_srl'); + $sid = Context::get('sid'); + + // document module 객체 생성후 해당 파일의 정보를 체크 + $oDocument = getModule('document'); + $file_obj = $oDocument->getFile($file_srl); + if($file_obj->file_srl!=$file_srl||$file_obj->sid!=$sid) exit(); + + // 이상이 없으면 download_count 증가 + $args->file_srl = $file_srl; + $oDB = &DB::getInstance(); + $oDB->executeQuery('document.updateFileDownloadCount', $args); + + // 파일 출력 + $filename = $file_obj->source_filename; + + if(strstr($_SERVER['HTTP_USER_AGENT'], "MSIE")) { + $filename = urlencode($filename); + $filename = preg_replace('/\./', '%2e', $filename, substr_count($filename, '.') - 1); + } + + $uploaded_filename = $file_obj->uploaded_filename; + if(!file_exists($uploaded_filename)) exit(); + + $fp = fopen($uploaded_filename, 'rb'); + if(!$fp) exit(); + + header("Cache-Control: "); + header("Pragma: "); + header("Content-Type: application/octet-stream"); + + header("Content-Length: " .(string)($file_obj->file_size)); + header('Content-Disposition: attachment; filename="'.$filename.'"'); + header("Content-Transfer-Encoding: binary\n"); + + fpassthru($fp); + exit(); + }/*}}}*/ + + function procClearFile() {/*{{{*/ + $document_srl = Context::get('document_srl'); + + // document_srl의 글이 등록되어 있다면 pass + $oDocument = getModule('document'); + $data = $oDocument->getDocument($document_srl); + if($data) exit(); + + // 등록되어 있지 않다면 첨부파일 삭제 + $oDocument->deleteFiles($this->module_srl, $document_srl); + }/*}}}*/ + + /** + * 여기부터는 이 모듈과 관련된 라이브러리 개념의 method들 + **/ + function printUploadedFileList($document_srl) {/*{{{*/ + // 첨부파일들의 정보를 취합해서 return + $oDocument = getModule('document'); + $file_list = $oDocument->getFiles($document_srl); + $file_count = count($file_list); + $buff = ""; + for($i=0;$i<$file_count;$i++) { + $file_info = $file_list[$i]; + if(!$file_info->file_srl) continue; + + $buff .= sprintf("parent.editor_insert_uploaded_file(\"%d\", \"%d\",\"%s\", \"%d\", \"%s\", \"%s\", \"%s\");\n", $document_srl, $file_info->file_srl, $file_info->source_filename, $file_info->file_size, FileHandler::filesize($file_info->file_size), $file_info->direct_download=='Y'?$file_info->uploaded_filename:'', $file_info->sid); + } + + $buff = sprintf("", $document_srl, $buff); + return $buff; + }/*}}}*/ + } + +?> diff --git a/modules/board/lang/ko.lang.php b/modules/board/lang/ko.lang.php new file mode 100644 index 000000000..59221ce43 --- /dev/null +++ b/modules/board/lang/ko.lang.php @@ -0,0 +1,56 @@ + + * @desc : 게시판(board) 모듈의 기본 언어팩 + **/ + + // 버튼에 사용되는 언어 + $lang->cmd_view_info = "모듈정보"; + $lang->cmd_manage_category = "분류관리"; + $lang->cmd_manage_grant = "권한관리"; + $lang->cmd_manage_skin = "스킨관리"; + + // 항목 + $lang->mid = "모듈이름"; + $lang->header_text = "상단 내용"; + $lang->footer_text = "하단 내용"; + $lang->skin = "스킨"; + $lang->use_category = "분류 사용"; + $lang->category_title = "분류명"; + $lang->module = "모듈"; + + $lang->skin_default_info = "기본정보"; + $lang->skin_maker = "스킨제작자"; + $lang->skin_maker_homepage = "홈페이지"; + + $lang->colorset = "컬러셋"; + $lang->extra_vars = "확장변수"; + + // 권한의 명칭 + $lang->grant_title = array( + 'list' => "목록 접근 권한", + 'view' => "내용 접근 권한", + 'write_document' => "게시물 작성 권한", + 'write_comment' => "코멘트 작성 권한", + 'fileupload' => "파일첨부 권한", + 'management' => "관리 권한", + ); + + // 주절 주절.. + $lang->about_mid = "모듈이름은 http://주소/?mid=모듈이름 처럼 직접 호출할 수 있는 값입니다. (영문+숫자만 가능)"; + $lang->about_browser_title = "브라우저의 제목에 나타나는 값입니다. RSS/Trackback에서도 사용됩니다."; + $lang->about_description= "관리용으로 사용되는 설명입니다"; + $lang->about_default = "선택하시면 사이트에 mid값 없이 접속하였을 경우 기본으로 보여줍니다"; + $lang->about_header_text = "모듈의 상단에 표시되는 내용입니다 (html 태그 사용 가능)"; + $lang->about_footer_text = "모듈의 하단에 표시되는 내용입니다 (html 태그 사용 가능)"; + $lang->about_skin = "모듈의 스킨을 선택하실 수 있습니다"; + $lang->about_use_category = "선택하시면 분류기능을 사용할 수 있습니다"; + $lang->about_admin_id = "해당 모듈에 대해 최고 권한을 가지는 관리자를 지정할 수 있습니다. ,(콤마)로 다수 아이디 지정이 가능합니다. (관리자페이지 접근은 불가능)"; + $lang->about_grant = "특정 권한의 대상을 모두 해제하시면 로그인하지 않은 회원까지 권한을 가질 수 있습니다"; + + $lang->msg_new_module = "모듈 생성"; + $lang->msg_update_module = "모듈 수정"; + $lang->msg_category_is_null = "등록된 분류가 없습니다"; + $lang->msg_grant_is_null = "등록된 권한 대상이 없습니다"; +?> diff --git a/modules/board/module.xml b/modules/board/module.xml new file mode 100644 index 000000000..59d96c871 --- /dev/null +++ b/modules/board/module.xml @@ -0,0 +1,11 @@ + + + 게시판 + BBS + + 제로 + zero + 게시판 모듈 + board + + diff --git a/modules/board/queries/getBoardList.xml b/modules/board/queries/getBoardList.xml new file mode 100644 index 000000000..2a8ad6131 --- /dev/null +++ b/modules/board/queries/getBoardList.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/modules/board/skins/default/comment.html b/modules/board/skins/default/comment.html new file mode 100644 index 000000000..bd706044e --- /dev/null +++ b/modules/board/skins/default/comment.html @@ -0,0 +1,53 @@ + + + +
+ {$lang->comment} : {count($comment_list)} +
+ + +
+ + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
{$lang->date}{zdate($val->regdate, "Y-m-d H:i:s")}
{$lang->user_name}{$val->user_name}
{$lang->content}{nl2br($val->content)}
ipaddress{$val->ipaddress}
+ [{$lang->cmd_modify}] + [{$lang->cmd_reply}] + [{$lang->cmd_delete}] +
+ + + + + + + + + + + diff --git a/modules/board/skins/default/comment_form.html b/modules/board/skins/default/comment_form.html new file mode 100644 index 000000000..ef9a742e5 --- /dev/null +++ b/modules/board/skins/default/comment_form.html @@ -0,0 +1,77 @@ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + +
{$lang->date}{$source_comment->regdate}
{$lang->user_name}{$source_comment->user_name}
{$lang->readed_count}{$source_comment->readed_count}
{$lang->voted_count}{$source_comment->voted_count}
{$lang->content}{nl2br($source_comment->content)}
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{$lang->user_name}
{$lang->password}
{$lang->email_address}
{$lang->homepage}
{$lang->content}
+ + + + + + + +
+
diff --git a/modules/board/skins/default/delete_comment_form.html b/modules/board/skins/default/delete_comment_form.html new file mode 100644 index 000000000..c08d194fa --- /dev/null +++ b/modules/board/skins/default/delete_comment_form.html @@ -0,0 +1,23 @@ + + + +
+ + + + + + + + + + + + +
{$lang->confirm_delete}
+ + +
+ +
+ diff --git a/modules/board/skins/default/delete_form.html b/modules/board/skins/default/delete_form.html new file mode 100644 index 000000000..02d2fa595 --- /dev/null +++ b/modules/board/skins/default/delete_form.html @@ -0,0 +1,26 @@ + + + +
+ + + + + + + + + + + + + + + +
{$lang->confirm_delete}
{$lang->title}{$document->title}
+ + +
+ +
+ diff --git a/modules/board/skins/default/delete_trackback_form.html b/modules/board/skins/default/delete_trackback_form.html new file mode 100644 index 000000000..5ad48f1ec --- /dev/null +++ b/modules/board/skins/default/delete_trackback_form.html @@ -0,0 +1,23 @@ + + + +
+ + + + + + + + + + + + +
{$lang->confirm_delete}
+ + +
+ +
+ diff --git a/modules/board/skins/default/filter/filter.delete_comment.xml b/modules/board/skins/default/filter/filter.delete_comment.xml new file mode 100644 index 000000000..7e24cf910 --- /dev/null +++ b/modules/board/skins/default/filter/filter.delete_comment.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/modules/board/skins/default/filter/filter.delete_document.xml b/modules/board/skins/default/filter/filter.delete_document.xml new file mode 100644 index 000000000..06e6d36a9 --- /dev/null +++ b/modules/board/skins/default/filter/filter.delete_document.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/modules/board/skins/default/filter/filter.delete_trackback.xml b/modules/board/skins/default/filter/filter.delete_trackback.xml new file mode 100644 index 000000000..dd7336ef1 --- /dev/null +++ b/modules/board/skins/default/filter/filter.delete_trackback.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/modules/board/skins/default/filter/filter.input_password.xml b/modules/board/skins/default/filter/filter.input_password.xml new file mode 100644 index 000000000..39603f2e3 --- /dev/null +++ b/modules/board/skins/default/filter/filter.input_password.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/modules/board/skins/default/filter/filter.insert.xml b/modules/board/skins/default/filter/filter.insert.xml new file mode 100644 index 000000000..bef2f2e83 --- /dev/null +++ b/modules/board/skins/default/filter/filter.insert.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/modules/board/skins/default/filter/filter.insert_comment.xml b/modules/board/skins/default/filter/filter.insert_comment.xml new file mode 100644 index 000000000..1c60d5057 --- /dev/null +++ b/modules/board/skins/default/filter/filter.insert_comment.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/board/skins/default/filter/filter.login.xml b/modules/board/skins/default/filter/filter.login.xml new file mode 100644 index 000000000..d6e559d75 --- /dev/null +++ b/modules/board/skins/default/filter/filter.login.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/modules/board/skins/default/filter/filter.logout.xml b/modules/board/skins/default/filter/filter.logout.xml new file mode 100644 index 000000000..d8d0344d5 --- /dev/null +++ b/modules/board/skins/default/filter/filter.logout.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/modules/board/skins/default/filter/filter.search.xml b/modules/board/skins/default/filter/filter.search.xml new file mode 100644 index 000000000..be1d9757f --- /dev/null +++ b/modules/board/skins/default/filter/filter.search.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/modules/board/skins/default/filter/filter.vote.xml b/modules/board/skins/default/filter/filter.vote.xml new file mode 100644 index 000000000..bfda2105f --- /dev/null +++ b/modules/board/skins/default/filter/filter.vote.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/modules/board/skins/default/header.html b/modules/board/skins/default/header.html new file mode 100644 index 000000000..93ce4dd87 --- /dev/null +++ b/modules/board/skins/default/header.html @@ -0,0 +1 @@ + diff --git a/modules/board/skins/default/input_password_form.html b/modules/board/skins/default/input_password_form.html new file mode 100644 index 000000000..8971d1e28 --- /dev/null +++ b/modules/board/skins/default/input_password_form.html @@ -0,0 +1,26 @@ + + + +
+ + + + + + + + + + + + + + + + +
{$lang->msg_input_password}
{$lang->password}
+ + +
+ +
diff --git a/modules/board/skins/default/js/admin.js b/modules/board/skins/default/js/admin.js new file mode 100644 index 000000000..899158ccb --- /dev/null +++ b/modules/board/skins/default/js/admin.js @@ -0,0 +1,39 @@ +/** + * @file : modules/board/js/admin.js + * @author : zero + * @desc : board 모듈의 관리자용 javascript + **/ + +/* 모듈 생성 후 */ +function procInsertModule(ret_obj, response_tags) { + var error = ret_obj['error']; + var message = ret_obj['message']; + var sid = ret_obj['sid']; + var act = ret_obj['act']; + var page = ret_obj['page']; + var module_srl = ret_obj['module_srl']; + alert(message); + + url = "./admin.php?sid="+sid+"&module_srl="+module_srl+"&page="+page+"&act="+act; + location.href = url; +} + +/* 카테고리 관련 작업들 */ +function doUpdateCategory(category_srl, mode, message) { + if(typeof(message)!='undefined'&&!confirm(message)) return; + + var fo_obj = xGetElementById('fo_module_category_info'); + fo_obj.category_srl.value = category_srl; + fo_obj.mode.value = mode; + + procFormFilter(fo_obj, update_category_info, procReload); +} + +/* 메세지 출력후 현페이지 리로드 */ +function procReload(ret_obj, response_tags) { + var error = ret_obj['error']; + var message = ret_obj['message']; + if(message) alert(message); + + location.href = location.href; +} diff --git a/modules/board/skins/default/js/board.js b/modules/board/skins/default/js/board.js new file mode 100644 index 000000000..658b77803 --- /dev/null +++ b/modules/board/skins/default/js/board.js @@ -0,0 +1,107 @@ +/** + * @file : modules/board/js/board.js + * @author : zero + * @desc : board 모듈의 javascript + **/ + +/* 글쓰기 작성후 */ +function procInsert(ret_obj, response_tags) { + var error = ret_obj['error']; + var message = ret_obj['message']; + var mid = ret_obj['mid']; + var document_srl = ret_obj['document_srl']; + var category_srl = ret_obj['category_srl']; + alert(message); + url = "./?mid="+mid+"&document_srl="+document_srl; + if(category_srl) url += '&category='+category_srl; + location.href = url; +} + +/* 글 삭제 */ +function procDeleteDocument(ret_obj, response_tags) { + var error = ret_obj['error']; + var message = ret_obj['message']; + var mid = ret_obj['mid']; + var page = ret_obj['page']; + var url = "./?mid="+mid; + if(page) url += "&page="+page; + alert(message); + location.href = url; +} + +/* 검색 실행 */ +function procSearch(fo_obj, args) { + fo_obj.submit(); +} + +/* 추천, 추천은 별도의 폼입력이 필요 없어 직접 필터 사용 */ +function doVote() { + var fo_obj = document.getElementById('fo_document_info'); + procFormFilter(fo_obj, vote, procVote) +} + +function procVote(ret_obj, response_tags) { + var error = ret_obj['error']; + var message = ret_obj['message']; + alert(message); + + location.href = location.href; +} + +// 현재 페이지 reload +function procReload(ret_obj, response_tags) { + var error = ret_obj['error']; + var message = ret_obj['message']; + + location.href = location.href; +} + +/* 댓글 글쓰기 작성후 */ +function procInsertComment(ret_obj, response_tags) { + var error = ret_obj['error']; + var message = ret_obj['message']; + var mid = ret_obj['mid']; + var document_srl = ret_obj['document_srl']; + var comment_srl = ret_obj['comment_srl']; + var url = "./?mid="+mid+"&document_srl="+document_srl; + if(comment_srl) url += "#comment_"+comment_srl; + + alert(message); + + location.href = url; +} + +/* 댓글 삭제 */ +function procDeleteComment(ret_obj, response_tags) { + var error = ret_obj['error']; + var message = ret_obj['message']; + var mid = ret_obj['mid']; + var document_srl = ret_obj['document_srl']; + var page = ret_obj['page']; + var url = "./?mid="+mid+'&document_srl='+document_srl; + if(page) url += "&page="+page; + alert(message); + + location.href = url; +} + +/* 트랙백 삭제 */ +function procDeleteTrackback(ret_obj, response_tags) { + var error = ret_obj['error']; + var message = ret_obj['message']; + var mid = ret_obj['mid']; + var document_srl = ret_obj['document_srl']; + var page = ret_obj['page']; + var url = "./?mid="+mid+'&document_srl='+document_srl; + if(page) url += "&page="+page; + alert(message); + + location.href = url; +} + +/* 카테고리 이동 */ +function procChangeCategory(sel_obj, url) { + var category_srl = sel_obj.options[sel_obj.selectedIndex].value; + if(!category_srl) location.href=url; + else location.href=url+'&category='+category_srl; +} diff --git a/modules/board/skins/default/list.html b/modules/board/skins/default/list.html new file mode 100644 index 000000000..8a4ee5a1f --- /dev/null +++ b/modules/board/skins/default/list.html @@ -0,0 +1,124 @@ + + + +{$module_info->header_text} + + + +
+ + + + + + + + + +
{$module_info->title}
{nl2br($module_info->desc)}
+
+ + + +
+ {$lang->document_count} : {number_format($total_count)}, + {$lang->page_count} : {number_format($page)} / {number_format($total_page)} + rss + + [{$lang->cmd_logout}] + + [{$lang->cmd_login}] + + + [{$lang->cmd_management}] + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
{$lang->no} +
+ +
+
{$lang->title}{$lang->user_name}{$lang->readed_count}{$lang->voted_count}{$lang->date}
{$no}{$category_list[$val->category_srl]->title} + {$val->title} + + [{$val->comment_count}] + + + [{$val->trackback_count}] + + {$val->user_name}{$val->readed_count}{$val->voted_count}{zdate($val->regdate,"Y-m-d")}
+
+ + + + + +
+
+ + + + + +
+
+ + +
+ [{$lang->first_page}] + + + + {$page_no} + + [{$page_no}] + + + + [{$lang->last_page}] +
+ +{$module_info->footer_text} diff --git a/modules/board/skins/default/login_form.html b/modules/board/skins/default/login_form.html new file mode 100644 index 000000000..efb60da06 --- /dev/null +++ b/modules/board/skins/default/login_form.html @@ -0,0 +1,26 @@ + + + +
+ + + + + + + + + + + + + + + + +
{$lang->user_id}
{$lang->password}
+ + +
+ +
diff --git a/modules/board/skins/default/logout.html b/modules/board/skins/default/logout.html new file mode 100644 index 000000000..0ba1c5ec5 --- /dev/null +++ b/modules/board/skins/default/logout.html @@ -0,0 +1,22 @@ + + + +
+ + + + + + + + + + + + +
{$lang->cmd_logout}
{$lang->confirm_logout}
+ + +
+ +
diff --git a/modules/board/skins/default/skin.xml b/modules/board/skins/default/skin.xml new file mode 100644 index 000000000..d751f33c9 --- /dev/null +++ b/modules/board/skins/default/skin.xml @@ -0,0 +1,67 @@ + + + 게시판 기본 스킨 + BBS default skin + + 제로 + zero + board모듈의 default스킨 + default skin of the board module + + + + 기본 + normal + + + 이상한거 + deep + + + + + 제목 + title + 그냥 테스트용입니다 + just for test.. + + + 제목 2 + title 2 + haha + + + 내용 + memo + 내용의 기본값 + default value of memo + + + 선택1 + select 1 + 1 + 2 + 3 + 4 + 5 + + + 다중선택 + multi select + a + b + c + + + 하나선택 + one select + A + B + C + + + 로고이미지 + logo image + + + diff --git a/modules/board/skins/default/trackback.html b/modules/board/skins/default/trackback.html new file mode 100644 index 000000000..1af1d6107 --- /dev/null +++ b/modules/board/skins/default/trackback.html @@ -0,0 +1,50 @@ + + + +
+ {$lang->trackback} : {count($trackback_list)} +
+ + +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
{$lang->title}{$val->title}
{$lang->date}{zdate($val->regdate, "Y-m-d H:i:s")}
{$lang->blog_name}{$val->blog_name}
{$lang->excerpt}{nl2br($val->excerpt)}
ipaddress{$val->ipaddress}
+ [{$lang->cmd_delete}] +
+
+ + + + +
diff --git a/modules/board/skins/default/view_document.html b/modules/board/skins/default/view_document.html new file mode 100644 index 000000000..1ed3d9942 --- /dev/null +++ b/modules/board/skins/default/view_document.html @@ -0,0 +1,108 @@ + + + + +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{$lang->category}{$category_list[$document->category_srl]->title}
{$lang->title}{$document->title}
{$lang->date}{zdate($document->regdate,"Y-m-d H:i:s")}
{$lang->user_name}{$document->user_name}
{$lang->readed_count}{$document->readed_count}
{$lang->voted_count}{$document->voted_count}
{$lang->content}{Document::transContent($document->content)}
+ {$lang->document_url} : {getUrl()}?document_srl={$document->document_srl} + +
+ {$lang->trackback_url} : {getUrl()}trackback.php?document_srl={$document->document_srl} + +
{$lang->tag}{$document->tags}
{$lang->uploaded_file} + + + +
ipaddress{$document->ipaddress}
+ + {$lang->allow_comment} + + + {$lang->lock_comment} + + + {$lang->allow_trackback} + +
+
+ + + + + + + + + + + + + + diff --git a/modules/board/skins/default/write_form.html b/modules/board/skins/default/write_form.html new file mode 100644 index 000000000..88fb36614 --- /dev/null +++ b/modules/board/skins/default/write_form.html @@ -0,0 +1,100 @@ + + + +
fileupload)-->enctype="multipart/form-data"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{$lang->category} + +
{$lang->user_name}
{$lang->password}
{$lang->email_address}
{$lang->homepage}
{$lang->title}
  + is_notice== "Y")-->checked="true" id="is_notice" /> + + + is_secret== "Y")-->checked="true" id="is_secret" /> + + + allow_comment != "N")-->checked="true" id="allow_comment" /> + + + lock_comment == "Y")-->checked="true" id="lock_comment" /> + + + allow_trackback != "N")-->checked="true" id="allow_trackback" /> + +
{$lang->content} + + +
{$lang->cmd_send_trackback} + + +
{$lang->tag} +
+ {$lang->about_tag} +
+ + +
+ +
diff --git a/modules/comment/comment.module.php b/modules/comment/comment.module.php new file mode 100644 index 000000000..bd427f839 --- /dev/null +++ b/modules/comment/comment.module.php @@ -0,0 +1,267 @@ + + * @desc : 기본 모듈중의 하나인 comment module + * Module class에서 상속을 받아서 사용 + * action 의 경우 disp/proc 2가지만 존재하며 이는 action명세서에 + * 미리 기록을 하여야 함 + **/ + + class comment extends Module { + + /** + * 모듈의 정보 + **/ + var $cur_version = "20070130_0.01"; + + /** + * 기본 action 지정 + * $act값이 없거나 잘못된 값이 들어올 경우 $default_act 값으로 진행 + **/ + var $default_act = ''; + + /** + * 현재 모듈의 초기화를 위한 작업을 지정해 놓은 method + * css/js파일의 load라든지 lang파일 load등을 미리 선언 + * + * Init() => 공통 + * dispInit() => disp시에 + * procInit() => proc시에 + * + * $this->module_path는 현재 이 모듈파일의 위치를 나타낸다 + * (ex: $this->module_path = "./modules/install/"; + **/ + + // 초기화 + function init() {/*{{{*/ + //Context::loadLang($this->module_path.'lang'); + }/*}}}*/ + + // disp 초기화 + function dispInit() {/*{{{*/ + }/*}}}*/ + + // proc 초기화 + function procInit() {/*{{{*/ + }/*}}}*/ + + /** + * 여기서부터는 action의 구현 + * request parameter의 경우 각 method의 첫번째 인자로 넘어온다 + * + * dispXXXX : 출력을 위한 method, output에 tpl file이 지정되어야 한다 + * procXXXX : 처리를 위한 method, output에는 comment, comment가 지정되어야 한다 + **/ + + /** + * 여기부터는 이 모듈과 관련된 라이브러리 개념의 method들 + **/ + + // 코멘트의 권한 부여 + // 세션값으로 현 접속상태에서만 사용 가능 + // public void addGrant($comment_srl) {/*{{{*/ + function addGrant($comment_srl) { + $_SESSION['own_comment'][$comment_srl] = true; + }/*}}}*/ + + // public void isGranted($comment_srl) {/*{{{*/ + function isGranted($comment_srl) { + return $_SESSION['own_comment'][$comment_srl]; + }/*}}}*/ + + // 코멘트 + // public boolean insertComment($obj)/*{{{*/ + // 댓글 입력 + function insertComment($obj) { + // document_srl에 해당하는 글이 있는지 확인 + $document_srl = $obj->document_srl; + if(!$document_srl) return new Output(-1,'msg_invalid_document'); + $oDocument = getModule('document'); + $document = $oDocument->getDocument($document_srl); + if(!$document_srl) return new Output(-1,'msg_invalid_document'); + if($document->lock_comment=='Y') return new Output(-1,'msg_invalid_request'); + + // 댓글를 입력 + $oDB = &DB::getInstance(); + $obj->comment_srl = $oDB->getNextSequence(); + $obj->list_order = $obj->comment_srl * -1; + if($obj->password) $obj->password = md5($obj->password); + $output = $oDB->executeQuery('comment.insertComment', $obj); + + // 입력에 이상이 없으면 해당 글의 댓글 수를 올림 + if(!$output->toBool()) return $output; + + // 해당 글의 전체 댓글 수를 구해옴 + $comment_count = $this->getCommentCount($document_srl); + + // 해당글의 댓글 수를 업데이트 + $output = $oDocument->updateCommentCount($document_srl, $comment_count); + + // 댓글의 권한을 부여 + $this->addGrant($obj->comment_srl); + $output->add('comment_srl', $obj->comment_srl); + return $output; + }/*}}}*/ + + // public boolean updateComment($obj)/*{{{*/ + // 댓글 수정 + function updateComment($obj) { + // 권한이 있는지 확인 + if(!$this->isGranted($obj->comment_srl)) return new Output(-1, 'msg_not_permitted'); + + // 업데이트 + $oDB = &DB::getInstance(); + if($obj->password) $obj->password = md5($obj->password); + $output = $oDB->executeQuery('comment.updateComment', $obj); + $output->add('comment_srl', $obj->comment_srl); + return $output; + }/*}}}*/ + + // public boolean deleteComment($comment_srl)/*{{{*/ + // 댓글 삭제 + function deleteComment($comment_srl) { + // 기존 댓글이 있는지 확인 + $comment = $this->getComment($comment_srl); + if($comment->comment_srl != $comment_srl) return new Output(-1, 'msg_invalid_request'); + $document_srl = $comment->document_srl; + + // 해당 댓글에 child가 있는지 확인 + $child_count = $this->getChildCommentCount($comment_srl); + if($child_count>0) return new Output(-1, 'fail_to_delete_have_children'); + + // 권한이 있는지 확인 + if(!$this->isGranted($comment_srl)) return new Output(-1, 'msg_not_permitted'); + + // 삭제 + $oDB = &DB::getInstance(); + $args->comment_srl = $comment_srl; + $output = $oDB->executeQuery('comment.deleteComment', $args); + if(!$output->toBool()) return new Output(-1, 'msg_error_occured'); + + // 댓글 수를 구해서 업데이트 + $comment_count = $this->getCommentCount($document_srl); + + // 해당글의 댓글 수를 업데이트 + $oDocument = getModule('document'); + $output = $oDocument->updateCommentCount($document_srl, $comment_count); + $output->add('document_srl', $document_srl); + return $output; + }/*}}}*/ + + // public boolean deleteComments($document_srl)/*{{{*/ + // 특정 글의 모든 댓글 삭제 + function deleteComments($document_srl) { + // 권한이 있는지 확인 + if(!$this->isGranted($document_srl)) return new Output(-1, 'msg_not_permitted'); + + // 삭제 + $oDB = &DB::getInstance(); + $args->document_srl = $document_srl; + $output = $oDB->executeQuery('comment.deleteComments', $args); + return $output; + }/*}}}*/ + + // public boolean deleteMoudleComments($module_srl)/*{{{*/ + // 특정 모듈의 모든 댓글 삭제 + function deleteModuleComments($module_srl) { + // 삭제 + $oDB = &DB::getInstance(); + $args->module_srl = $module_srl; + $output = $oDB->executeQuery('comment.deleteModuleComments', $args); + return $output; + }/*}}}*/ + + // public int getChildCommentCount($comment_srl)/*{{{*/ + // 자식 답글의 갯수 리턴 + function getChildCommentCount($comment_srl) { + $oDB = &DB::getInstance(); + $args->comment_srl = $comment_srl; + $output = $oDB->executeQuery('comment.getChildCommentCount', $args); + return (int)$output->data->count; + }/*}}}*/ + + // public boolean getComment($comment_srl)/*{{{*/ + // 댓글 가져오기 + function getComment($comment_srl) { + $oDB = &DB::getInstance(); + $args->comment_srl = $comment_srl; + $output = $oDB->executeQuery('comment.getComment', $args); + return $output->data; + }/*}}}*/ + + // public boolean getComments($comment_srl_list)/*{{{*/ + // 여러개의 댓글들을 가져옴 (페이징 아님) + function getComments($comment_srl_list) { + if(is_array($comment_srl_list)) $comment_srls = implode(',',$comment_srl_list); + + $oDB = &DB::getInstance(); + $args->comment_srls = $comment_srls; + $output = $oDB->executeQuery('comment.getComments', $args); + return $output->data; + }/*}}}*/ + + // public number getCommentCount($module_srl, $search_obj = NULL)/*{{{*/ + // document_srl 에 해당하는 댓글의 전체 갯수를 가져옴 + function getCommentCount($document_srl) { + $oDB = &DB::getInstance(); + $args->document_srl = $document_srl; + $output = $oDB->executeQuery('comment.getCommentCount', $args); + $total_count = $output->data->count; + return (int)$total_count; + }/*}}}*/ + + // public boolean getCommentList($document_srl)/*{{{*/ + // module_srl값을 가지는 댓글의 목록을 가져옴 + function getCommentList($document_srl) { + // 댓글 목록을 가져옴 + $oDB = &DB::getInstance(); + $args->document_srl = $document_srl; + $args->list_order = 'list_order'; + $output = $oDB->executeQuery('comment.getCommentList', $args); + if(!$output->toBool()) return $output; + $source_list= $output->data; + if(!is_array($source_list)) $source_list = array($source_list); + + // 댓글를 계층형 구조로 정렬 + $comment_count = count($source_list); + + $root = NULL; + $list = NULL; + for($i=$comment_count-1;$i>=0;$i--) { + $comment_srl = $source_list[$i]->comment_srl; + $parent_srl = $source_list[$i]->parent_srl; + if(!$comment_srl) continue; + + $list[$comment_srl] = $source_list[$i]; + + if($parent_srl) { + $list[$parent_srl]->child[] = &$list[$comment_srl]; + } else { + $root->child[] = &$list[$comment_srl]; + } + + } + $this->_arrangeComment($comment_list, $root->child, 0); + return $comment_list; + }/*}}}*/ + + // private object _arrangeComment(&$comment_list, $list, $depth)/*{{{*/ + // 댓글를 계층형으로 재배치 + function _arrangeComment(&$comment_list, $list, $depth) { + if(!count($list)) return; + foreach($list as $key => $val) { + if($val->child) { + $tmp = $val; + $tmp->depth = $depth; + $comment_list[$tmp->comment_srl] = $tmp; + $this->_arrangeComment($comment_list,$val->child,$depth+1); + } + else { + $val->depth = $depth; + $comment_list[$val->comment_srl] = $val; + } + } + }/*}}}*/ + } +?> diff --git a/modules/comment/module.xml b/modules/comment/module.xml new file mode 100644 index 000000000..b71ff20bb --- /dev/null +++ b/modules/comment/module.xml @@ -0,0 +1,11 @@ + + + 댓글 + comment + + 제로 + zero + 댓글 모듈 + comment + + diff --git a/modules/comment/queries/deleteComment.xml b/modules/comment/queries/deleteComment.xml new file mode 100644 index 000000000..ce4b80e1f --- /dev/null +++ b/modules/comment/queries/deleteComment.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/modules/comment/queries/deleteComments.xml b/modules/comment/queries/deleteComments.xml new file mode 100644 index 000000000..30894de97 --- /dev/null +++ b/modules/comment/queries/deleteComments.xml @@ -0,0 +1,8 @@ + + +
+ + + + + diff --git a/modules/comment/queries/deleteModuleComments.xml b/modules/comment/queries/deleteModuleComments.xml new file mode 100644 index 000000000..98858b815 --- /dev/null +++ b/modules/comment/queries/deleteModuleComments.xml @@ -0,0 +1,8 @@ + + +
+ + + + + diff --git a/modules/comment/queries/getChildCommentCount.xml b/modules/comment/queries/getChildCommentCount.xml new file mode 100644 index 000000000..4686c279c --- /dev/null +++ b/modules/comment/queries/getChildCommentCount.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/comment/queries/getComment.xml b/modules/comment/queries/getComment.xml new file mode 100644 index 000000000..17e595ad4 --- /dev/null +++ b/modules/comment/queries/getComment.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/comment/queries/getCommentCount.xml b/modules/comment/queries/getCommentCount.xml new file mode 100644 index 000000000..6cdc97a29 --- /dev/null +++ b/modules/comment/queries/getCommentCount.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/comment/queries/getCommentList.xml b/modules/comment/queries/getCommentList.xml new file mode 100644 index 000000000..2599b286b --- /dev/null +++ b/modules/comment/queries/getCommentList.xml @@ -0,0 +1,14 @@ + + +
+ + + + + + + + + + + diff --git a/modules/comment/queries/getComments.xml b/modules/comment/queries/getComments.xml new file mode 100644 index 000000000..171fff6a0 --- /dev/null +++ b/modules/comment/queries/getComments.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/comment/queries/insertComment.xml b/modules/comment/queries/insertComment.xml new file mode 100644 index 000000000..7ecaa5c4d --- /dev/null +++ b/modules/comment/queries/insertComment.xml @@ -0,0 +1,21 @@ + + +
+ + + + + + + + + + + + + + + + + + diff --git a/modules/comment/queries/updateComment.xml b/modules/comment/queries/updateComment.xml new file mode 100644 index 000000000..e263590ac --- /dev/null +++ b/modules/comment/queries/updateComment.xml @@ -0,0 +1,20 @@ + + +
+ + + + + + + + + + + + + + + + + diff --git a/modules/comment/schemas/comments.xml b/modules/comment/schemas/comments.xml new file mode 100644 index 000000000..46222f3d4 --- /dev/null +++ b/modules/comment/schemas/comments.xml @@ -0,0 +1,18 @@ +
+ + + + + + + + + + + + + + + + +
diff --git a/modules/document/document.module.php b/modules/document/document.module.php new file mode 100644 index 000000000..0e58ab999 --- /dev/null +++ b/modules/document/document.module.php @@ -0,0 +1,702 @@ + + * @desc : 기본 모듈중의 하나인 document module + * Module class에서 상속을 받아서 사용 + * action 의 경우 disp/proc 2가지만 존재하며 이는 action명세서에 + * 미리 기록을 하여야 함 + **/ + + class document extends Module { + + /** + * 모듈의 정보 + **/ + var $cur_version = "20070130_0.01"; + + // 공지사항의 고정된 list_order + var $notice_list_order = -1000000000; + + /** + * 기본 action 지정 + * $act값이 없거나 잘못된 값이 들어올 경우 $default_act 값으로 진행 + **/ + var $default_act = ''; + + /** + * 현재 모듈의 초기화를 위한 작업을 지정해 놓은 method + * css/js파일의 load라든지 lang파일 load등을 미리 선언 + * + * Init() => 공통 + * dispInit() => disp시에 + * procInit() => proc시에 + * + * $this->module_path는 현재 이 모듈파일의 위치를 나타낸다 + * (ex: $this->module_path = "./modules/install/"; + **/ + + // 초기화 + function init() {/*{{{*/ + //Context::loadLang($this->module_path.'lang'); + }/*}}}*/ + + // disp 초기화 + function dispInit() {/*{{{*/ + }/*}}}*/ + + // proc 초기화 + function procInit() {/*{{{*/ + }/*}}}*/ + + /** + * 여기서부터는 action의 구현 + * request parameter의 경우 각 method의 첫번째 인자로 넘어온다 + * + * dispXXXX : 출력을 위한 method, output에 tpl file이 지정되어야 한다 + * procXXXX : 처리를 위한 method, output에는 document, document가 지정되어야 한다 + **/ + + /** + * 여기부터는 이 모듈과 관련된 라이브러리 개념의 method들 + **/ + + // 문서의 권한 부여 + // 세션값으로 현 접속상태에서만 사용 가능 + // public void addGrant($document_srl) {/*{{{*/ + function addGrant($document_srl) { + $_SESSION['own_document'][$document_srl] = true; + }/*}}}*/ + + // public void isGranted($document_srl) {/*{{{*/ + function isGranted($document_srl) { + return $_SESSION['own_document'][$document_srl]; + }/*}}}*/ + + // 문서 + // public object insertDocument($obj)/*{{{*/ + // 문서 입력 + function insertDocument($obj) { + // 입력 + $oDB = &DB::getInstance(); + + // 카테고리가 있나 검사하여 없는 카테고리면 0으로 세팅 + if($obj->category_srl) { + $category_list = $this->getCategoryList($obj->module_srl); + if(!$category_list[$obj->category_srl]) $obj->category_srl = 0; + } + + // 태그 처리 + $oTag = getModule('tag'); + $obj->tags = $oTag->insertTag($obj->module_srl, $obj->document_srl, $obj->tags); + + // 글 입력 + $obj->readed_count = 0; + $obj->update_order = $obj->list_order = $obj->document_srl * -1; + if($obj->password) $obj->password = md5($obj->password); + + // 공지사항일 경우 list_order에 무지막지한 값;;을 입력 + if($obj->is_notice=='Y') $obj->list_order = $this->notice_list_order; + + // DB에 입력 + $output = $oDB->executeQuery('document.insertDocument', $obj); + + if(!$output->toBool()) return $output; + + // 성공하였을 경우 category_srl이 있으면 카테고리 update + if($obj->category_srl) $this->updateCategoryCount($obj->category_srl); + + // return + $this->addGrant($obj->document_srl); + $output->add('document_srl',$obj->document_srl); + $output->add('category_srl',$obj->category_srl); + return $output; + }/*}}}*/ + + // public object updateDocument($source_obj, $obj)/*{{{*/ + // 문서 수정 + function updateDocument($source_obj, $obj) { + // 카테고리가 변경되었으면 검사후 없는 카테고리면 0으로 세팅 + if($source_obj->category_srl!=$obj->category_srl) { + $category_list = $this->getCategoryList($obj->module_srl); + if(!$category_list[$obj->category_srl]) $obj->category_srl = 0; + } + + // 태그 처리 + $oTag = getModule('tag'); + $obj->tags = $oTag->insertTag($obj->module_srl, $obj->document_srl, $obj->tags); + + // 수정 + $oDB = &DB::getInstance(); + $obj->update_order = $oDB->getNextSequence() * -1; + + // 공지사항일 경우 list_order에 무지막지한 값을, 그렇지 않으면 document_srl*-1값을 + if($obj->is_notice=='Y') $obj->list_order = $this->notice_list_order; + else $obj->list_order = $obj->document_srl*-1; + + if($obj->password) $obj->password = md5($obj->password); + + // DB에 입력 + $output = $oDB->executeQuery('document.updateDocument', $obj); + + if(!$output->toBool()) return $output; + + // 성공하였을 경우 category_srl이 있으면 카테고리 update + if($source_obj->category_srl!=$obj->category_srl) { + if($source_obj->category_srl) $this->updateCategoryCount($source_obj->category_srl); + if($obj->category_srl) $this->updateCategoryCount($obj->category_srl); + } + + $output->add('document_srl',$obj->document_srl); + return $output; + }/*}}}*/ + + // public object deleteDocument($obj)/*{{{*/ + // 문서 삭제 + function deleteDocument($obj) { + // 변수 세팅 + $document_srl = $obj->document_srl; + $category_srl = $obj->category_srl; + + // 기존 문서가 있는지 확인 + $document = $this->getDocument($document_srl); + if($document->document_srl != $document_srl) return false; + + // 권한이 있는지 확인 + if(!$document->is_granted) return new Output(-1, 'msg_not_permitted'); + + // 글 삭제 + $oDB = &DB::getInstance(); + $args->document_srl = $document_srl; + $output = $oDB->executeQuery('document.deleteDocument', $args); + if(!$output->toBool()) return $output; + + // 댓글 삭제 + $oComment = getModule('comment'); + $output = $oComment->deleteComments($document_srl); + + // 엮인글 삭제 + $oTrackback = getModule('trackback'); + $output = $oTrackback->deleteTrackbacks($document_srl); + + // 태그 삭제 + $oTag = getModule('tag'); + $oTag->deleteTag($document_srl); + + // 첨부 파일 삭제 + if($document->uploaded_count) $this->deleteFiles($document->module_srl, $document_srl); + + // 카테고리가 있으면 카테고리 정보 변경 + if($document->category_srl) $this->updateCategoryCount($document->category_srl); + + return $output; + }/*}}}*/ + + // public object deleteModuleDocument($module_srl) /*{{{*/ + function deleteModuleDocument($module_srl) { + $args->module_srl = $module_srl; + $oDB = &DB::getInstance(); + $output = $oDB->executeQuery('document.deleteModuleDocument', $args); + return $output; + }/*}}}*/ + + // public object getDocument($document_srl)/*{{{*/ + // 문서 가져오기 + function getDocument($document_srl) { + // DB에서 가져옴 + $oDB = &DB::getInstance(); + $args->document_srl = $document_srl; + $output = $oDB->executeQuery('document.getDocument', $args); + $document = $output->data; + + // 이 문서에 대한 권한이 있는지 확인 + if($this->isGranted($document->document_srl)) { + $document->is_granted = true; + } elseif($document->member_srl) { + $oMember = getModule('member'); + $member_srl = $oMember->getMemberSrl(); + if($member_srl && $member_srl ==$document->member_srl) $document->is_granted = true; + } + return $document; + }/*}}}*/ + + // public object getDocuments($document_srl_list)/*{{{*/ + // 여러개의 문서들을 가져옴 (페이징 아님) + function getDocuments($document_srl_list) { + if(is_array($document_srl_list)) $document_srls = implode(',',$document_srl_list); + + // DB에서 가져옴 + $oDB = &DB::getInstance(); + $args->document_srls = $document_srls; + $output = $oDB->executeQuery('document.getDocuments', $args); + $document_list = $output->data; + if(!$document_list) return; + + // 권한 체크 + $oMember = getModule('member'); + $member_srl = $oMember->getMemberSrl(); + + $document_count = count($document_list); + for($i=0;$i<$document_count;$i++) { + $document = $document_list[$i]; + + $is_granted = false; + if($this->isGranted($document->document_srl)) { + $is_granted = true; + } elseif($member_srl && $member_srl == $document->member_srl) { + $is_granted = true; + } + $document_list[$i]->is_granted = $is_granted; + } + return $document_list; + }/*}}}*/ + + // public object getDocumentCount($module_srl, $search_obj = NULL)/*{{{*/ + // module_srl에 해당하는 문서의 전체 갯수를 가져옴 + function getDocumentCount($module_srl, $search_obj = NULL) { + $oDB = &DB::getInstance(); + + $args->module_srl = $module_srl; + $args->s_title = $search_obj->s_title; + $args->s_content = $search_obj->s_content; + $args->s_user_name = $search_obj->s_user_name; + $args->s_member_srl = $search_obj->s_member_srl; + $args->s_ipaddress = $search_obj->s_ipaddress; + $args->s_regdate = $search_obj->s_regdate; + $output = $oDB->executeQuery('document.getDocumentCount', $args); + $total_count = $output->data->count; + return (int)$total_count; + }/*}}}*/ + + // public object getDocumentList($module_srl, $sort_index='list_order', $page=1, $list_order=20, $page_count=10, $search_obj = NULL)/*{{{*/ + // module_srl값을 가지는 문서의 목록을 가져옴 + function getDocumentList($module_srl, $sort_index = 'list_order', $page = 1, $list_count = 20, $page_count = 10, $search_obj = NULL) { + $args->module_srl = $module_srl; + $args->s_title = $search_obj->s_title; + $args->s_content = $search_obj->s_content; + $args->s_user_name = $search_obj->s_user_name; + $args->s_member_srl = $search_obj->s_member_srl; + $args->s_ipaddress = $search_obj->s_ipaddress; + $args->s_regdate = $search_obj->s_regdate; + $args->category_srl = $search_obj->category_srl; + + $args->sort_index = $sort_index; + $args->page = $page; + $args->list_count = $list_count; + $args->page_count = $page_count; + $oDB = &DB::getInstance(); + $output = $oDB->executeQuery('document.getDocumentList', $args); + + if(!count($output->data)) return $output; + + // 권한 체크 + $oMember = getModule('member'); + $member_srl = $oMember->getMemberSrl(); + + foreach($output->data as $key => $document) { + $is_granted = false; + if($this->isGranted($document->document_srl)) $is_granted = true; + elseif($member_srl && $member_srl == $document->member_srl) $is_granted = true; + $output->data[$key]->is_granted = $is_granted; + } + return $output; + }/*}}}*/ + + // public object getDocumentPage($document_srl, $module_srl, $list_count)/*{{{*/ + // 해당 document의 page 가져오기, module_srl이 없으면 전체에서.. + function getDocumentPage($document_srl, $module_srl=0, $list_count) { + $oDB = &DB::getInstance(); + $args->document_srl = $document_srl; + $args->module_srl = $module_srl; + $output = $oDB->executeQuery('document.getDocumentPage', $args); + $count = $output->data->count; + $page = (int)(($count-1)/$list_count)+1; + return $page; + }/*}}}*/ + + // public object updateReadedCount($document_srl)/*{{{*/ + // 해당 document의 조회수 증가 + function updateReadedCount($document_srl) { + if($_SESSION['readed_document'][$document_srl]) return false; + $oDB = &DB::getInstance(); + $args->document_srl = $document_srl; + $output = $oDB->executeQuery('document.updateReadedCount', $args); + return $_SESSION['readed_document'][$document_srl] = true; + }/*}}}*/ + + // public object updateVotedCount($document_srl)/*{{{*/ + // 해당 document의 추천수 증가 + function updateVotedCount($document_srl) { + if($_SESSION['voted_document'][$document_srl]) return new Output(-1, 'failed_voted'); + $oDB = &DB::getInstance(); + $args->document_srl = $document_srl; + $output = $oDB->executeQuery('document.updateVotedCount', $args); + $_SESSION['voted_document'][$document_srl] = true; + return new Output(0, 'success_voted'); + }/*}}}*/ + + // public object updateCommentCount($document_srl, $comment_count)/*{{{*/ + // 해당 document의 댓글 수 증가 + function updateCommentCount($document_srl, $comment_count) { + $oDB = &DB::getInstance(); + $args->document_srl = $document_srl; + $args->comment_count = $comment_count; + $output = $oDB->executeQuery('document.updateCommentCount', $args); + return new Output(); + }/*}}}*/ + + // public object updateTrackbackCount($document_srl, $trackback_count)/*{{{*/ + // 해당 document의 엮인글 수증가 + function updateTrackbackCount($document_srl, $trackback_count) { + $oDB = &DB::getInstance(); + $args->document_srl = $document_srl; + $args->trackback_count = $trackback_count; + $output = $oDB->executeQuery('document.updateTrackbackCount', $args); + return new Output(); + }/*}}}*/ + + // 카테고리 관리 + // public object getCategory($category_srl) /*{{{*/ + function getCategory($category_srl) { + $args->category_srl = $category_srl; + $oDB = &DB::getInstance(); + $output = $oDB->executeQuery('document.getCategory', $args); + return $output->data; + }/*}}}*/ + + // public object getCategoryList($module_srl) /*{{{*/ + function getCategoryList($module_srl) { + $args->module_srl = $module_srl; + $args->sort_index = 'list_order'; + $oDB = &DB::getInstance(); + $output = $oDB->executeQuery('document.getCategoryList', $args); + $category_list = $output->data; + if(!$category_list) return NULL; + if(!is_array($category_list)) $category_list = array($category_list); + $category_count = count($category_list); + for($i=0;$i<$category_count;$i++) { + $category_srl = $category_list[$i]->category_srl; + $list[$category_srl] = $category_list[$i]; + } + return $list; + }/*}}}*/ + + // public object insertCategory($module_srl, $title) /*{{{*/ + function insertCategory($module_srl, $title) { + $oDB = &DB::getInstance(); + $args->list_order = $args->category_srl = $oDB->getNextSequence(); + $args->module_srl = $module_srl; + $args->title = $title; + $args->document_count = 0; + return $oDB->executeQuery('document.insertCategory', $args); + }/*}}}*/ + + // public object updateCategory($args) /*{{{*/ + function updateCategory($args) { + $oDB = &DB::getInstance(); + return $oDB->executeQuery('document.updateCategory', $args); + }/*}}}*/ + + // public object updateCategoryCount($category_srl, $document_count = 0) /*{{{*/ + function updateCategoryCount($category_srl, $document_count = 0) { + if(!$document_count) $document_count = $this->getCategoryDocumentCount($category_srl); + $args->category_srl = $category_srl; + $args->document_count = $document_count; + $oDB = &DB::getInstance(); + return $oDB->executeQuery('document.updateCategoryCount', $args); + }/*}}}*/ + + // public int getCategoryDocumentCount($category_srl) /*{{{*/ + function getCategoryDocumentCount($category_srl) { + $args->category_srl = $category_srl; + $oDB = &DB::getInstance(); + $output = $oDB->executeQuery('document.getCategoryDocumentCount', $args); + return (int)$output->data->count; + }/*}}}*/ + + // public object deleteCategory($category_srl) /*{{{*/ + function deleteCategory($category_srl) { + $args->category_srl = $category_srl; + $oDB = &DB::getInstance(); + + // 카테고리 정보를 삭제 + $output = $oDB->executeQuery('document.deleteCategory', $args); + if(!$output->toBool()) return $output; + + // 현 카테고리 값을 가지는 문서들의 category_srl을 0 으로 세팅 + unset($args); + $args->target_category_srl = 0; + $args->source_category_srl = $category_srl; + $output = $oDB->executeQuery('document.updateDocumentCategory', $args); + return $output; + }/*}}}*/ + + // public object deleteModuleCategory($module_srl) /*{{{*/ + function deleteModuleCategory($module_srl) { + $args->module_srl = $module_srl; + $oDB = &DB::getInstance(); + $output = $oDB->executeQuery('document.deleteModuleCategory', $args); + return $output; + }/*}}}*/ + + // public object moveCategoryUp($category_srl) /*{{{*/ + function moveCategoryUp($category_srl) { + // 선택된 카테고리의 정보를 구한다 + $oDB = &DB::getInstance(); + $args->category_srl = $category_srl; + $output = $oDB->executeQuery('document.getCategory', $args); + $category = $output->data; + $list_order = $category->list_order; + $module_srl = $category->module_srl; + + // 전체 카테고리 목록을 구한다 + $category_list = $this->getCategoryList($module_srl); + $category_srl_list = array_keys($category_list); + if(count($category_srl_list)<2) return new Output(); + + $prev_category = NULL; + foreach($category_list as $key => $val) { + if($key==$category_srl) break; + $prev_category = $val; + } + + // 이전 카테고리가 없으면 그냥 return + if(!$prev_category) return new Output(-1,Context::getLang('msg_category_not_moved')); + + // 선택한 카테고리가 가장 위의 카테고리이면 그냥 return + if($category_srl_list[0]==$category_srl) return new Output(-1,Context::getLang('msg_category_not_moved')); + + // 선택한 카테고리의 정보 + $cur_args->category_srl = $category_srl; + $cur_args->list_order = $prev_category->list_order; + $cur_args->title = $category->title; + $this->updateCategory($cur_args); + + // 대상 카테고리의 정보 + $prev_args->category_srl = $prev_category->category_srl; + $prev_args->list_order = $list_order; + $prev_args->title = $prev_category->title; + $this->updateCategory($prev_args); + + return new Output(); + }/*}}}*/ + + // public object moveCategoryDown($category_srl) /*{{{*/ + function moveCategoryDown($category_srl) { + // 선택된 카테고리의 정보를 구한다 + $oDB = &DB::getInstance(); + $args->category_srl = $category_srl; + $output = $oDB->executeQuery('document.getCategory', $args); + $category = $output->data; + $list_order = $category->list_order; + $module_srl = $category->module_srl; + + // 전체 카테고리 목록을 구한다 + $category_list = $this->getCategoryList($module_srl); + $category_srl_list = array_keys($category_list); + if(count($category_srl_list)<2) return new Output(); + + for($i=0;$icategory_srl = $category_srl; + $cur_args->list_order = $next_category->list_order; + $cur_args->title = $category->title; + $this->updateCategory($cur_args); + + // 대상 카테고리의 정보 + $next_args->category_srl = $next_category->category_srl; + $next_args->list_order = $list_order; + $next_args->title = $next_category->title; + $this->updateCategory($next_args); + + return new Output(); + }/*}}}*/ + + // 파일 관리 + // public int getFilesCount($document_srl) /*{{{*/ + function getFilesCount($document_srl) { + $oDB = &DB::getInstance(); + $args->document_srl = $document_srl; + $output = $oDB->executeQuery('document.getFilesCount', $args); + return (int)$output->data->count; + }/*}}}*/ + + // public object getFile($file_srl) /*{{{*/ + function getFile($file_srl) { + $oDB = &DB::getInstance(); + $args->file_srl = $file_srl; + $output = $oDB->executeQuery('document.getFile', $args); + return $output->data; + }/*}}}*/ + + // public object getFiles($document_srl) /*{{{*/ + function getFiles($document_srl) { + $oDB = &DB::getInstance(); + $args->document_srl = $document_srl; + $args->sort_index = 'file_srl'; + $output = $oDB->executeQuery('document.getFiles', $args); + $file_list = $output->data; + if($file_list && !is_array($file_list)) $file_list = array($file_list); + for($i=0;$idirect_download; + if($direct_download!='Y') continue; + $uploaded_filename = Context::getRequestUri().substr($file_list[$i]->uploaded_filename,2); + $file_list[$i]->uploaded_filename = $uploaded_filename; + } + return $file_list; + }/*}}}*/ + + // public object insertFile($module_srl, $document_sr) /*{{{*/ + function insertFile($module_srl, $document_srl) { + $oDB = &DB::getInstance(); + + $file_info = Context::get('file'); + + // 정상적으로 업로드된 파일이 아니면 오류 출력 + if(!is_uploaded_file($file_info['tmp_name'])) return false; + + // 이미지인지 기타 파일인지 체크하여 upload path 지정 + if(eregi("\.(jpg|jpeg|gif|png|wmv|mpg|mpeg|avi|swf|flv|mp3|asaf|wav|asx|midi)$", $file_info['name'])) { + $path = sprintf("./files/attach/images/%s/%s/", $module_srl,$document_srl); + $filename = $path.$file_info['name']; + $direct_download = 'Y'; + } else { + $path = sprintf("./files/attach/binaries/%s/%s/", $module_srl, $document_srl); + $filename = $path.md5(crypt(rand(1000000,900000), rand(0,100))); + $direct_download = 'N'; + } + + // 디렉토리 생성 + if(!FileHandler::makeDir($path)) return false; + + // 파일 이동 + if(!move_uploaded_file($file_info['tmp_name'], $filename)) return false; + + // 사용자 정보를 구함 + $oMember = getModule('member'); + $member_srl = $oMember->getMemberSrl(); + + // 파일 정보를 정리 + $oDB = &DB::getInstance(); + $args->file_srl = $oDB->getNextSequence(); + $args->document_srl = $document_srl; + $args->module_srl = $module_srl; + $args->direct_download = $direct_download; + $args->source_filename = $file_info['name']; + $args->uploaded_filename = $filename; + $args->file_size = filesize($filename); + $args->comment = NULL; + $args->member_srl = $member_srl; + $args->sid = md5($args->source_filename); + + $output = $oDB->executeQuery('document.insertFile', $args); + if(!$output->toBool()) return $output; + $output->add('file_srl', $args->file_srl); + $output->add('file_size', $args->file_size); + $output->add('source_filename', $args->source_filename); + return $output; + }/*}}}*/ + + // public object deleteFile($file_srl) /*{{{*/ + function deleteFile($file_srl) { + $oDB = &DB::getInstance(); + + // 파일 정보를 가져옴 + $args->file_srl = $file_srl; + $output = $oDB->executeQuery('document.getFile', $args); + if(!$output->toBool()) return $output; + $file_info = $output->data; + if(!$file_info) return new Output(-1, 'file_not_founded'); + + $source_filename = $output->data->source_filename; + $uploaded_filename = $output->data->uploaded_filename; + + // DB에서 삭제 + $output = $oDB->executeQuery('document.deleteFile', $args); + if(!$output->toBool()) return $output; + + // 삭제 성공하면 파일 삭제 + unlink($uploaded_filename); + + return $output; + }/*}}}*/ + + // public object deleteFiles($module_srl, $document_srl) /*{{{*/ + function deleteFiles($module_srl, $document_srl) { + // DB에서 삭제 + $oDB = &DB::getInstance(); + $args->document_srl = $document_srl; + $output = $oDB->executeQuery('document.deleteFiles', $args); + if(!$output->toBool()) return $output; + + // 실제 파일 삭제 + $path[0] = sprintf("./files/attach/images/%s/%s/", $module_srl, $document_srl); + $path[1] = sprintf("./files/attach/binaries/%s/%s/", $module_srl, $document_srl); + + FileHandler::removeDir($path[0]); + FileHandler::removeDir($path[1]); + + return $output; + }/*}}}*/ + + // public object deleteModuleFiles($module_srl) /*{{{*/ + function deleteModuleFiles($module_srl) { + // DB에서 삭제 + $oDB = &DB::getInstance(); + $args->module_srl = $module_srl; + $output = $oDB->executeQuery('document.deleteModuleFiles', $args); + if(!$output->toBool()) return $output; + + // 실제 파일 삭제 + $path[0] = sprintf("./files/attach/images/%s/", $module_srl); + $path[1] = sprintf("./files/attach/binaries/%s/", $module_srl); + FileHandler::removeDir($path[0]); + FileHandler::removeDir($path[1]); + + return $output; + }/*}}}*/ + + // 기타 기능 + // public string transContent($content) {/*{{{*/ + // 내용 관리 + // 내용의 플러그인이나 기타 기능에 대한 code를 실제 code로 변경 + function transContent($content) { + // 멀티미디어 코드의 변환 + $content = preg_replace_callback('!]*)editor_multimedia([^\>]*?)>!is', array('Document','_transMultimedia'), $content); + + //
코드 변환 + $content = str_replace(array("
","
","
"),"
", $content); + + // 코드를 코드로 변환 + $content = preg_replace('!!is','', $content); + + return $content; + }/*}}}*/ + + // public string _transMultimedia($matches)/*{{{*/ + // 로 되어 있는 코드를 변경 + function _transMultimedia($matches) { + preg_match("/style\=(\"|'){0,1}([^\"\']+)(\"|'){0,1}/i",$matches[0], $buff); + $style = str_replace("\"","'",$buff[0]); + preg_match("/alt\=\"{0,1}([^\"]+)\"{0,1}/i",$matches[0], $buff); + $opt = explode('|@|',$buff[1]); + if(count($opt)<1) return $matches[0]; + + for($i=0;$i{$cmd} = $val; + } + + return sprintf("", $obj->type, $obj->src, $style); + }/*}}}*/ + } +?> diff --git a/modules/document/lang/ko.lang.php b/modules/document/lang/ko.lang.php new file mode 100644 index 000000000..601fb4572 --- /dev/null +++ b/modules/document/lang/ko.lang.php @@ -0,0 +1,8 @@ + + * @desc : 문서(document) 모듈의 기본 언어팩 + **/ + $lang->msg_category_not_moved = "이동할 수가 없습니다"; +?> diff --git a/modules/document/module.xml b/modules/document/module.xml new file mode 100644 index 000000000..d8bf37a17 --- /dev/null +++ b/modules/document/module.xml @@ -0,0 +1,11 @@ + + + 문서 + document + + 제로 + zero + 문서 모듈 + document + + diff --git a/modules/document/queries/deleteCategory.xml b/modules/document/queries/deleteCategory.xml new file mode 100644 index 000000000..c1a98762a --- /dev/null +++ b/modules/document/queries/deleteCategory.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/modules/document/queries/deleteDocument.xml b/modules/document/queries/deleteDocument.xml new file mode 100644 index 000000000..36d157a90 --- /dev/null +++ b/modules/document/queries/deleteDocument.xml @@ -0,0 +1,8 @@ + + +
+ + + + + diff --git a/modules/document/queries/deleteFile.xml b/modules/document/queries/deleteFile.xml new file mode 100644 index 000000000..3584ea182 --- /dev/null +++ b/modules/document/queries/deleteFile.xml @@ -0,0 +1,8 @@ + + +
+ + + + + diff --git a/modules/document/queries/deleteFiles.xml b/modules/document/queries/deleteFiles.xml new file mode 100644 index 000000000..d4ee8b8df --- /dev/null +++ b/modules/document/queries/deleteFiles.xml @@ -0,0 +1,8 @@ + + +
+ + + + + diff --git a/modules/document/queries/deleteModuleCategory.xml b/modules/document/queries/deleteModuleCategory.xml new file mode 100644 index 000000000..152826bc4 --- /dev/null +++ b/modules/document/queries/deleteModuleCategory.xml @@ -0,0 +1,8 @@ + + +
+ + + + + diff --git a/modules/document/queries/deleteModuleDocument.xml b/modules/document/queries/deleteModuleDocument.xml new file mode 100644 index 000000000..0338b85cc --- /dev/null +++ b/modules/document/queries/deleteModuleDocument.xml @@ -0,0 +1,8 @@ + + +
+ + + + + diff --git a/modules/document/queries/deleteModuleFiles.xml b/modules/document/queries/deleteModuleFiles.xml new file mode 100644 index 000000000..f2f7c2ad7 --- /dev/null +++ b/modules/document/queries/deleteModuleFiles.xml @@ -0,0 +1,8 @@ + + +
+ + + + + diff --git a/modules/document/queries/getCategory.xml b/modules/document/queries/getCategory.xml new file mode 100644 index 000000000..97ba6536a --- /dev/null +++ b/modules/document/queries/getCategory.xml @@ -0,0 +1,8 @@ + + +
+ + + + + diff --git a/modules/document/queries/getCategoryDocumentCount.xml b/modules/document/queries/getCategoryDocumentCount.xml new file mode 100644 index 000000000..bf0df824d --- /dev/null +++ b/modules/document/queries/getCategoryDocumentCount.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/document/queries/getCategoryList.xml b/modules/document/queries/getCategoryList.xml new file mode 100644 index 000000000..1625c3cfe --- /dev/null +++ b/modules/document/queries/getCategoryList.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/document/queries/getDocument.xml b/modules/document/queries/getDocument.xml new file mode 100644 index 000000000..eb3b6af8a --- /dev/null +++ b/modules/document/queries/getDocument.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/document/queries/getDocumentCount.xml b/modules/document/queries/getDocumentCount.xml new file mode 100644 index 000000000..5ea51255e --- /dev/null +++ b/modules/document/queries/getDocumentCount.xml @@ -0,0 +1,19 @@ + + +
+ + + + + + + + + + + + + + + + diff --git a/modules/document/queries/getDocumentList.xml b/modules/document/queries/getDocumentList.xml new file mode 100644 index 000000000..de2f2aa88 --- /dev/null +++ b/modules/document/queries/getDocumentList.xml @@ -0,0 +1,26 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/document/queries/getDocumentPage.xml b/modules/document/queries/getDocumentPage.xml new file mode 100644 index 000000000..35bee06c4 --- /dev/null +++ b/modules/document/queries/getDocumentPage.xml @@ -0,0 +1,12 @@ + + +
+ + + + + + + + + diff --git a/modules/document/queries/getDocuments.xml b/modules/document/queries/getDocuments.xml new file mode 100644 index 000000000..828a6b2db --- /dev/null +++ b/modules/document/queries/getDocuments.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/document/queries/getFile.xml b/modules/document/queries/getFile.xml new file mode 100644 index 000000000..deb35b994 --- /dev/null +++ b/modules/document/queries/getFile.xml @@ -0,0 +1,8 @@ + + +
+ + + + + diff --git a/modules/document/queries/getFiles.xml b/modules/document/queries/getFiles.xml new file mode 100644 index 000000000..d4e1510f9 --- /dev/null +++ b/modules/document/queries/getFiles.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/document/queries/getFilesCount.xml b/modules/document/queries/getFilesCount.xml new file mode 100644 index 000000000..a03e6a3e0 --- /dev/null +++ b/modules/document/queries/getFilesCount.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/document/queries/insertCategory.xml b/modules/document/queries/insertCategory.xml new file mode 100644 index 000000000..79bfe78e9 --- /dev/null +++ b/modules/document/queries/insertCategory.xml @@ -0,0 +1,14 @@ + + +
+ + + + + + + + + + + diff --git a/modules/document/queries/insertDocument.xml b/modules/document/queries/insertDocument.xml new file mode 100644 index 000000000..08c0d48eb --- /dev/null +++ b/modules/document/queries/insertDocument.xml @@ -0,0 +1,34 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/document/queries/insertFile.xml b/modules/document/queries/insertFile.xml new file mode 100644 index 000000000..873310014 --- /dev/null +++ b/modules/document/queries/insertFile.xml @@ -0,0 +1,20 @@ + + +
+ + + + + + + + + + + + + + + + + diff --git a/modules/document/queries/updateCategory.xml b/modules/document/queries/updateCategory.xml new file mode 100644 index 000000000..2d1d60687 --- /dev/null +++ b/modules/document/queries/updateCategory.xml @@ -0,0 +1,13 @@ + + +
+ + + + + + + + + + diff --git a/modules/document/queries/updateCategoryCount.xml b/modules/document/queries/updateCategoryCount.xml new file mode 100644 index 000000000..1d4c5fc2f --- /dev/null +++ b/modules/document/queries/updateCategoryCount.xml @@ -0,0 +1,12 @@ + + +
+ + + + + + + + + diff --git a/modules/document/queries/updateCommentCount.xml b/modules/document/queries/updateCommentCount.xml new file mode 100644 index 000000000..8c71dd3c4 --- /dev/null +++ b/modules/document/queries/updateCommentCount.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/document/queries/updateDocument.xml b/modules/document/queries/updateDocument.xml new file mode 100644 index 000000000..43d89bc00 --- /dev/null +++ b/modules/document/queries/updateDocument.xml @@ -0,0 +1,31 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/document/queries/updateDocumentCategory.xml b/modules/document/queries/updateDocumentCategory.xml new file mode 100644 index 000000000..67a2976a1 --- /dev/null +++ b/modules/document/queries/updateDocumentCategory.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/document/queries/updateFileDownloadCount.xml b/modules/document/queries/updateFileDownloadCount.xml new file mode 100644 index 000000000..251291af2 --- /dev/null +++ b/modules/document/queries/updateFileDownloadCount.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/document/queries/updateReadedCount.xml b/modules/document/queries/updateReadedCount.xml new file mode 100644 index 000000000..8391d8cd8 --- /dev/null +++ b/modules/document/queries/updateReadedCount.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/document/queries/updateTrackbackCount.xml b/modules/document/queries/updateTrackbackCount.xml new file mode 100644 index 000000000..dd8b58c8f --- /dev/null +++ b/modules/document/queries/updateTrackbackCount.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/document/queries/updateVotedCount.xml b/modules/document/queries/updateVotedCount.xml new file mode 100644 index 000000000..bd2ddbb04 --- /dev/null +++ b/modules/document/queries/updateVotedCount.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/document/schemas/category.xml b/modules/document/schemas/category.xml new file mode 100644 index 000000000..a201b6c0b --- /dev/null +++ b/modules/document/schemas/category.xml @@ -0,0 +1,9 @@ +
+ + + + + + + +
diff --git a/modules/document/schemas/documents.xml b/modules/document/schemas/documents.xml new file mode 100644 index 000000000..c5b1c4f27 --- /dev/null +++ b/modules/document/schemas/documents.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/modules/document/schemas/files.xml b/modules/document/schemas/files.xml new file mode 100644 index 000000000..5ee2ee2a8 --- /dev/null +++ b/modules/document/schemas/files.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + +
diff --git a/modules/install/install.module.php b/modules/install/install.module.php new file mode 100644 index 000000000..bebf589e2 --- /dev/null +++ b/modules/install/install.module.php @@ -0,0 +1,264 @@ + + * @desc : 기본 모듈중의 하나인 install module + * Module class에서 상속을 받아서 사용 + * action 의 경우 disp/proc 2가지만 존재하며 이는 action명세서에 + * 미리 기록을 하여야 함 + **/ + + class install extends Module { + + /** + * 모듈의 정보 + **/ + var $cur_version = "20070130_0.01"; + + /** + * 기본 action 지정 + * $act값이 없거나 잘못된 값이 들어올 경우 $default_act 값으로 진행 + **/ + var $default_act = 'dispIntroduce'; + + /** + * 현재 모듈의 초기화를 위한 작업을 지정해 놓은 method + * css/js파일의 load라든지 lang파일 load등을 미리 선언 + * + * Init() => 공통 + * dispInit() => disp시에 + * procInit() => proc시에 + * + * $this->module_path는 현재 이 모듈파일의 위치를 나타낸다 + * (ex: $this->module_path = "./modules/install/"; + **/ + + // 초기화 + function init() {/*{{{*/ + Context::loadLang($this->module_path.'lang'); + + // 설치시 필수항목 검사 + $this->checkInstallEnv(); + + if(Context::get('install_enable')) $this->makeDefaultDirectory(); + }/*}}}*/ + + // disp 초기화 + function dispInit() {/*{{{*/ + // 설치가 가능하면 기본 디렉토리등을 만듬 + if(!Context::get('install_enable')) { + $this->act = 'dispIntroduce'; + } + + return true; + }/*}}}*/ + + // proc 초기화 + function procInit() {/*{{{*/ + // 설치가 불가능한 환경인데 요청이 오면 에러 표시 + if(!Context::get('install_enable')) return $this->doError('msg_already_installed'); + return true; + }/*}}}*/ + + /** + * 여기서부터는 action의 구현 + * request parameter의 경우 각 method의 첫번째 인자로 넘어온다 + * + * dispXXXX : 출력을 위한 method, output에 tpl file이 지정되어야 한다 + * procXXXX : 처리를 위한 method, output에는 error, message가 지정되어야 한다 + * + * 변수의 사용은 Context::get('이름')으로 얻어오면 된다 + **/ + function dispIntroduce() {/*{{{*/ + // disp_license.html 파일 출력 + $this->setTemplateFile('disp_license'); + }/*}}}*/ + + function dispDBInfoForm() {/*{{{*/ + // db_type이 지정되지 않았다면 다시 초기화면 출력 + if(!Context::get('db_type')) return $this->dispIntroduce(); + + // disp_db_info_form.html 파일 출력 + $tpl_filename = sprintf('db_form.%s.html', Context::get('db_type')); + $this->setTemplateFile($tpl_filename); + }/*}}}*/ + + function procInstall() {/*{{{*/ + // 설치가 되어 있는지에 대한 체크 + if(Context::isInstalled()) { + return $this->doError('msg_already_installed'); + } + + // DB와 관련된 변수를 받음 + $db_info = Context::gets('db_type','db_hostname','db_userid','db_password','db_database','db_table_prefix'); + + // DB의 타입과 정보를 등록 + Context::setDBInfo($db_info); + + // DB Instance 생성 + $oDB = &DB::getInstance(); + + // DB접속이 가능한지 체크 + if(!$oDB->isConnected()) { + return $this->doError('msg_dbconnect_failed'); + } + + // 모든 모듈의 테이블 생성 + $output = $this->makeTable(); + if(!$output->toBool()) return $output; + + // 관리자 정보 입력 (member 모듈을 찾아서 method 실행) + $oMember = getModule('member'); + + // 그룹을 입력 + $group_args->title = Context::getLang('default_group_1'); + $group_args->is_default = 'Y'; + $oMember->insertGroup($group_args); + + $group_args->title = Context::getLang('default_group_2'); + $group_args->is_default = 'N'; + $oMember->insertGroup($group_args); + + // 금지 아이디 등록 + $oMember->insertDeniedID('www',''); + $oMember->insertDeniedID('root',''); + $oMember->insertDeniedID('admin',''); + $oMember->insertDeniedID('administrator',''); + $oMember->insertDeniedID('ftp',''); + $oMember->insertDeniedID('http',''); + + // 관리자 정보 세팅 + $admin_info = Context::gets('user_id','password','nick_name','user_name', 'email_address'); + + // 관리자 정보 입력 + $oMember->insertAdmin($admin_info); + + // 로그인 처리시킴 + $oMember->doLogin($admin_info->user_id, $admin_info->password); + + // 기본 모듈을 생성 + $oModule = getModule('module_manager'); + $oModule->makeDefaultModule(); + + // config 파일 생성 + if(!$this->makeConfigFile()) return $this->doError('msg_install_failed'); + + // 설치 완료 메세지 출력 + $this->setMessage('msg_install_completed'); + }/*}}}*/ + + /** + * 여기부터는 이 모듈과 관련된 라이브러리 개념의 method들 + **/ + // public void checkInstallEnv()/*{{{*/ + // 기본적으로 필수적인 체크항목들을 검사하여 Context에 바로 넣어버림.. + function checkInstallEnv() { + // 각 필요한 항목 체크 + $checklist = array(); + + // 1. permission 체크 + if(is_writable('./')||is_writable('./files')) $checklist['permission'] = true; + else $checklist['permission'] = false; + + // 2. xml_parser_create함수 유무 체크 + if(function_exists('xml_parser_create')) $checklist['xml'] = true; + else $checklist['xml'] = false; + + // 3. ini_get(session.auto_start)==1 체크 + if(ini_get(session.auto_start)!=1) $checklist['session'] = true; + else $checklist['session'] = false; + + // 4. iconv 체크 + if(function_exists('iconv')) $checklist['iconv'] = true; + else $checklist['iconv'] = false; + + // 5. gd 체크 (imagecreatefromgif함수) + if(function_exists('imagecreatefromgif')) $checklist['gd'] = true; + else $checklist['gd'] = false; + + // 6. mysql_get_client_info() 체크 + if(mysql_get_client_info() < "4.1.00") $checklist['mysql'] = false; + else $checklist['mysql'] = true; + + if(!$checklist['permission'] || !$checklist['xml'] || !$checklist['session']) $install_enable = false; + else $install_enable = true; + + // 체크 결과를 Context에 저장 + Context::set('install_enable', $install_enable); + Context::set('checklist', $checklist); + }/*}}}*/ + + // public void makeDefaultDirectory()/*{{{*/ + // files 및 하위 디렉토리 생성 + function makeDefaultDirectory() { + $directory_list = array( + './files', + './files/modules', + './files/plugins', + './files/addons', + './files/layouts', + './files/queries', + './files/schemas', + './files/js_filter_compiled', + './files/template_compiled', + './files/config', + './files/attach', + './files/attach/images', + './files/attach/binaries', + ); + + foreach($directory_list as $dir) { + if(is_dir($dir)) continue; + @mkdir($dir, 0707); + @chmod($dir, 0707); + } + }/*}}}*/ + + // public void makeTable()/*{{{*/ + // 모든 모듈의 테이블 생성 schema를 찾아서 생성 + function makeTable() { + // db instance생성 + $oDB = &DB::getInstance(); + + // 각 모듈의 schemas/*.xml 파일을 모두 찾아서 table 생성 + $module_list_1 = FileHandler::readDir('./modules/', NULL, false, true); + $module_list_2 = FileHandler::readDir('./files/modules/', NULL, false, true); + $module_list = array_merge($module_list_1, $module_list_2); + foreach($module_list as $module_path) { + $schema_dir = sprintf('%s/schemas/', $module_path); + $schema_files = FileHandler::readDir($schema_dir, NULL, false, true); + $file_cnt = count($schema_files); + if(!$file_cnt) continue; + + for($i=0;$i<$file_cnt;$i++) { + $file = trim($schema_files[$i]); + if(!$file || substr($file,-4)!='.xml') continue; + $output = $oDB->createTableByXmlFile($file); + if($oDB->isError()) return $oDB->getError(); + } + } + return new Output(); + }/*}}}*/ + + // public boolean makeConfigFile() /*{{{*/ + // config 파일을 생성 + function makeConfigFile() { + $config_file = Context::getConfigFile(); + if(file_exists($config_file)) return; + + $db_info = Context::getDbInfo(); + if(!$db_info) return; + + $buff = ' $val) { + $buff .= sprintf("\$db_info->%s = \"%s\";\n", $key, $val); + } + $buff .= "?>"; + + FileHandler::writeFile($config_file, $buff); + + if(@file_exists($config_file)) return true; + return false; + }/*}}}*/ + } +?> diff --git a/modules/install/lang/ko.lang.php b/modules/install/lang/ko.lang.php new file mode 100644 index 000000000..c2e7c302c --- /dev/null +++ b/modules/install/lang/ko.lang.php @@ -0,0 +1,65 @@ + + * @desc : 한국어 언어팩 (기본적인 내용만 수록) + **/ + + $lang->introduce_title = '제로보드5 설치'; + $lang->introduce = + "제로보드5를 사용해주셔서 감사합니다.\n". + "제로보드5는 GPL라이센스를 따르며 블라블라..\n"; + + $lang->install_condition_title = "설치 조건"; + + $lang->install_checklist_title = array( + 'permission' => '퍼미션', + 'xml' => 'XML 라이브러리', + 'iconv' => 'ICONV 라이브러리', + 'gd' => 'GD 라이브러리', + 'session' => 'Session.auto_start 설정', + 'mysql' => 'MySQL 버전', + ); + + $lang->install_checklist_desc = array( + 'permission' => '[필수] 제로보드의 설치 경로 또는 ./files 디렉토리의 퍼미션이 707이어야 합니다', + 'xml' => '[필수] XML통신을 위하여 XML 라이브러리가 필요합니다', + 'session' => '[필수] 제로보드에서 세션 사용을 위해 php.ini 설정의 session.auto_start=0 이어야 합니다', + 'iconv' => 'UTF-8과 다른 언어셋의 변환을 위한 iconv설치가 필요합니다', + 'gd' => '이미지변환 기능을 사용하기 위해 GD라이브러리가 설치되어 있어야 합니다', + 'mysql' => 'UTF-8 언어셋 사용을 위해 mysql버전이 4.1 이상이어야 합니다', + ); + + $lang->install_checklist_xml = 'XML라이브러리 설치'; + $lang->install_without_xml = 'xml 라이브러리가 설치되어 있지 않습니다'; + $lang->install_checklist_gd = 'GD라이브러리 설치'; + $lang->install_without_gd = '이미지 변환을 위한 gd 라이브러리가 설치되어 있지 않습니다'; + $lang->install_checklist_gd = 'GD라이브러리 설치'; + $lang->install_without_iconv = '문자열을 처리하기 위한 iconv 라이브러리가 설치되어 있지 않습니다'; + $lang->install_mysql_version = 'mysql client version이 4.1 이하라서 문제가 발생할 수 있습니다'; + $lang->install_session_auto_start = 'php설정의 session.auto_start==1 이라 세션 처리에 문제가 발생할 수 있습니다'; + $lang->install_permission_denied = '설치대상 디렉토리의 퍼미션이 707이 아닙니다'; + + $lang->cmd_install_fix_checklist = '필수 조건을 만족시켰습니다.'; + $lang->cmd_install_next = '설치를 진행합니다'; + + $lang->db_title = 'DB정보 입력'; + $lang->db_type = 'DB 종류'; + $lang->db_hostname = 'DB 호스트네임'; + $lang->db_userid = 'DB 아이디'; + $lang->db_password = 'DB 비밀번호'; + $lang->db_database = 'DB 데이터베이스'; + $lang->db_table_prefix = '테이블 머릿말'; + + $lang->admin_title = '관리자정보'; + + $lang->default_group_1 = "준회원"; + $lang->default_group_2 = "정회원"; + + $lang->msg_cannot_proc = '설치 환경이 갖춰지지 않아 요청을 실행할 수가 없습니다'; + $lang->msg_already_installed = '이미 설치가 되어 있습니다'; + $lang->msg_dbconnect_failed = "DB접속 오류가 발생하였습니다.\nDB정보를 다시 확인해주세요"; + $lang->msg_table_is_exists = "이미 DB에 테이블이 생성되어 있습니다.\nconfig파일을 재생성하였습니다"; + $lang->msg_install_completed = "설치가 완료되었습니다.\n감사합니다"; + $lang->msg_install_failed = "설치 파일 생성시에 오류가 발생하였습니다."; +?> diff --git a/modules/install/module.xml b/modules/install/module.xml new file mode 100644 index 000000000..7e85528b8 --- /dev/null +++ b/modules/install/module.xml @@ -0,0 +1,11 @@ + + + 설치관리 + install + + 제로 + zero + 설치 관리 모듈 + install + + diff --git a/modules/install/schemas/sequence.xml b/modules/install/schemas/sequence.xml new file mode 100644 index 000000000..c7cabb213 --- /dev/null +++ b/modules/install/schemas/sequence.xml @@ -0,0 +1,3 @@ + + +
diff --git a/modules/install/skins/default/css/install.css b/modules/install/skins/default/css/install.css new file mode 100644 index 000000000..e69de29bb diff --git a/modules/install/skins/default/db_form.mysql.html b/modules/install/skins/default/db_form.mysql.html new file mode 100644 index 000000000..172911c15 --- /dev/null +++ b/modules/install/skins/default/db_form.mysql.html @@ -0,0 +1,92 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ {$lang->db_title} +
{$lang->db_hostname} + +
{$lang->db_userid} + +
{$lang->db_password} + +
{$lang->db_database} + +
{$lang->db_table_prefix} + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ {$lang->admin_title} +
{$lang->user_id} + +
{$lang->password1} + +
{$lang->password2} + +
{$lang->user_name} + +
{$lang->nick_name} + +
{$lang->email_address} + +
+ + +
diff --git a/modules/install/skins/default/disp_license.html b/modules/install/skins/default/disp_license.html new file mode 100644 index 000000000..1c8b015e4 --- /dev/null +++ b/modules/install/skins/default/disp_license.html @@ -0,0 +1,48 @@ + + + + + + + + + +
{$lang->introduce_title}
+ {nl2br($lang->introduce)} +
+ + + + + + + + + + + + + + +
{$lang->install_condition_title}
{$lang->install_checklist_title[$key]}{$lang->enable}{$lang->disable}
{$lang->install_checklist_desc[$key]}
+ + +
+ + + + + + + +
{$lang->db_type} + +
+
+ +{$lang->cmd_install_fix_checklist} + diff --git a/modules/install/skins/default/filter/filter.mysql_form.xml b/modules/install/skins/default/filter/filter.mysql_form.xml new file mode 100644 index 000000000..d25c1c0ff --- /dev/null +++ b/modules/install/skins/default/filter/filter.mysql_form.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/install/skins/default/js/install.js b/modules/install/skins/default/js/install.js new file mode 100644 index 000000000..49a692fc5 --- /dev/null +++ b/modules/install/skins/default/js/install.js @@ -0,0 +1,6 @@ +function procInstall(ret_obj, response_tags) { + var error = ret_obj['error']; + var message = ret_obj['message']; + alert(message); + location.href = "./"; +} diff --git a/modules/log/log.module.php b/modules/log/log.module.php new file mode 100644 index 000000000..e441cf9c4 --- /dev/null +++ b/modules/log/log.module.php @@ -0,0 +1,60 @@ + + * @desc : 기본 모듈중의 하나인 log module + * Module class에서 상속을 받아서 사용 + * action 의 경우 disp/proc 2가지만 존재하며 이는 action명세서에 + * 미리 기록을 하여야 함 + **/ + + class log extends Module { + + /** + * 모듈의 정보 + **/ + var $cur_version = "20070130_0.01"; + + /** + * 기본 action 지정 + * $act값이 없거나 잘못된 값이 들어올 경우 $default_act 값으로 진행 + **/ + var $default_act = ''; + + /** + * 현재 모듈의 초기화를 위한 작업을 지정해 놓은 method + * css/js파일의 load라든지 lang파일 load등을 미리 선언 + * + * Init() => 공통 + * dispInit() => disp시에 + * procInit() => proc시에 + * + * $this->module_path는 현재 이 모듈파일의 위치를 나타낸다 + * (ex: $this->module_path = "./modules/install/"; + **/ + + // 초기화 + function init() {/*{{{*/ + }/*}}}*/ + + // disp 초기화 + function dispInit() {/*{{{*/ + }/*}}}*/ + + // proc 초기화 + function procInit() {/*{{{*/ + }/*}}}*/ + + /** + * 여기서부터는 action의 구현 + * request parameter의 경우 각 method의 첫번째 인자로 넘어온다 + * + * dispXXXX : 출력을 위한 method, output에 tpl file이 지정되어야 한다 + * procXXXX : 처리를 위한 method, output에는 log, log가 지정되어야 한다 + **/ + + /** + * 여기부터는 이 모듈과 관련된 라이브러리 개념의 method들 + **/ + } +?> diff --git a/modules/log/module.xml b/modules/log/module.xml new file mode 100644 index 000000000..c53da79c9 --- /dev/null +++ b/modules/log/module.xml @@ -0,0 +1,11 @@ + + + 로그 + log + + 제로 + zero + 로그 관리 모듈 + log + + diff --git a/modules/log/schemas/log.xml b/modules/log/schemas/log.xml new file mode 100644 index 000000000..41c7f0345 --- /dev/null +++ b/modules/log/schemas/log.xml @@ -0,0 +1,8 @@ + + + + + + + +
diff --git a/modules/member/admin/delete_form.html b/modules/member/admin/delete_form.html new file mode 100644 index 000000000..3b4b8779f --- /dev/null +++ b/modules/member/admin/delete_form.html @@ -0,0 +1,34 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + +
{$lang->confirm_delete}
{$lang->user_id}{$member_info->user_id}
{$lang->nick_name}{$member_info->nick_name}
{$lang->email_address}{$member_info->email_address}
+ + +
+ +
+ diff --git a/modules/member/admin/denied_list.html b/modules/member/admin/denied_list.html new file mode 100644 index 000000000..f4cea09ac --- /dev/null +++ b/modules/member/admin/denied_list.html @@ -0,0 +1,67 @@ + + + + + +
+ {number_format($total_count)}, + {$lang->page_count} : {number_format($page)} / {number_format($total_page)} +
+ + +
+ + + + +
+ + +
+ + + + + + + + + + + + + + + + +
{$lang->no}{$lang->user_id}{$lang->regdate}{$lang->description}{$lang->cmd_delete}
{$no}{$val->user_id}{zdate($val->regdate,"Y-m-d")}{$lang->cmd_delete}
+
+ + +
+ [{$lang->first_page}] + + + + {$page_no} + + [{$page_no}] + + + + [{$lang->last_page}] +
+ + +
+ + + + +
+ {$lang->user_id} :
+ {$lang->description} :
+ +
+ +
diff --git a/modules/member/admin/filter/filter.delete.xml b/modules/member/admin/filter/filter.delete.xml new file mode 100644 index 000000000..512dadb63 --- /dev/null +++ b/modules/member/admin/filter/filter.delete.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/modules/member/admin/filter/filter.insert.xml b/modules/member/admin/filter/filter.insert.xml new file mode 100644 index 000000000..afcca3f9a --- /dev/null +++ b/modules/member/admin/filter/filter.insert.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/modules/member/admin/filter/filter.insert_denied_id.xml b/modules/member/admin/filter/filter.insert_denied_id.xml new file mode 100644 index 000000000..113179346 --- /dev/null +++ b/modules/member/admin/filter/filter.insert_denied_id.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/modules/member/admin/filter/filter.insert_group.xml b/modules/member/admin/filter/filter.insert_group.xml new file mode 100644 index 000000000..92c3e41e2 --- /dev/null +++ b/modules/member/admin/filter/filter.insert_group.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/modules/member/admin/filter/filter.update_denied_id.xml b/modules/member/admin/filter/filter.update_denied_id.xml new file mode 100644 index 000000000..c5c17a3b7 --- /dev/null +++ b/modules/member/admin/filter/filter.update_denied_id.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/modules/member/admin/filter/filter.update_group.xml b/modules/member/admin/filter/filter.update_group.xml new file mode 100644 index 000000000..81495886e --- /dev/null +++ b/modules/member/admin/filter/filter.update_group.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/modules/member/admin/group_list.html b/modules/member/admin/group_list.html new file mode 100644 index 000000000..8ff5541c2 --- /dev/null +++ b/modules/member/admin/group_list.html @@ -0,0 +1,64 @@ + + + + + +
+ {$lang->cmd_member_group} +
+ + +
+ + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
{$lang->group_title}{$lang->regdate}{$lang->description}{$lang->is_default}{$lang->cmd_modify}{$lang->cmd_delete}
{$lang->msg_group_is_null}
{$group_info->title}{zdate($group_info->regdate,"Y-m-d H:i:s")}{nl2br($group_info->description)}{$group_info->is_default}{$lang->cmd_modify} + + {$lang->cmd_delete} + +
+
+ + +
+ + + + + +
+ {$lang->group_title} :
+ {$lang->is_default} :
+ {$lang->description} :
+ +
+ +
diff --git a/modules/member/admin/group_update_form.html b/modules/member/admin/group_update_form.html new file mode 100644 index 000000000..544a7f4f6 --- /dev/null +++ b/modules/member/admin/group_update_form.html @@ -0,0 +1,30 @@ + + + + +
+ {$lang->cmd_member_group} +
+ + + +
+ + + + + + +
+ {$lang->group_title} :
+ + {$lang->is_default} :
+ + {$lang->description} :
+ + +
+ +
+ + diff --git a/modules/member/admin/header.html b/modules/member/admin/header.html new file mode 100644 index 000000000..898b49abe --- /dev/null +++ b/modules/member/admin/header.html @@ -0,0 +1,9 @@ + + +
+ [{$lang->cmd_list}] + style="font-weight:bold">[{$lang->cmd_member_group}] + style="font-weight:bold">[{$lang->cmd_manage_form}] + style="font-weight:bold">[{$lang->cmd_send_mail}] + style="font-weight:bold">[{$lang->cmd_manage_id}] +
diff --git a/modules/member/admin/insert_member.html b/modules/member/admin/insert_member.html new file mode 100644 index 000000000..ea6df7de3 --- /dev/null +++ b/modules/member/admin/insert_member.html @@ -0,0 +1,111 @@ + + + +
+ + {$lang->msg_new_member} + + {$lang->msg_update_member} + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{$lang->user_id} + + {$member_info->user_id} + + + +
{$lang->about_user_id}
{$lang->password} + +
{$lang->user_name} + +
{$lang->about_user_name}
{$lang->nick_name} + +
{$lang->about_nick_name}
{$lang->email_address} + +
{$lang->allow_mailing}allow_mailing!='N')-->checked="true"/>
{$lang->about_allow_mailing}
{$lang->denied}denied=='Y')-->checked="true"/>
{$lang->about_denied}
{$lang->is_admin}is_admin=='Y')-->checked="true"/>
{$lang->about_is_admin}
{$lang->description}
{$lang->about_description}
{$lang->group} + + group_list[$key])-->checked="true"/> + + +
{$lang->about_group}
+ + +
+
diff --git a/modules/member/admin/js/admin.js b/modules/member/admin/js/admin.js new file mode 100644 index 000000000..fea743870 --- /dev/null +++ b/modules/member/admin/js/admin.js @@ -0,0 +1,81 @@ +/* 메세지 출력후 현페이지 리로드 */ +function procReload(ret_obj, response_tags) { + var error = ret_obj['error']; + var message = ret_obj['message']; + if(message) alert(message); + + location.href = location.href; +} + +/* 사용자 추가 */ +function procInsert(ret_obj, response_tags) { + var error = ret_obj['error']; + var message = ret_obj['message']; + var sid = ret_obj['sid']; + var member_srl = ret_obj['member_srl']; + var act = ret_obj['act']; + var page = ret_obj['page']; + alert(message); + + url = "./admin.php?sid="+sid+"&member_srl="+member_srl+"&page="+page+"&act="+act; + location.href = url; +} + +/* 사용자 삭제 */ +function procDelete(ret_obj, response_tags) { + var error = ret_obj['error']; + var message = ret_obj['message']; + var sid = ret_obj['sid']; + var page = ret_obj['page']; + alert(message); + + url = "./admin.php?sid="+sid+"&page="+page; + location.href = url; +} + +/* 그룹 추가 */ +function procInsertGroup(ret_obj, response_tags) { + var error = ret_obj['error']; + var message = ret_obj['message']; + var sid = ret_obj['sid']; + var act = ret_obj['act']; + var page = ret_obj['page']; + alert(message); + + url = "./admin.php?sid="+sid+"&page="+page+"&act="+act; + location.href = url; +} + +/* 그룹 관련 작업들 */ +function doUpdateGroup(group_srl, mode, message) { + if(typeof(message)!='undefined'&&!confirm(message)) return; + + var fo_obj = xGetElementById('fo_group_info'); + fo_obj.group_srl.value = group_srl; + fo_obj.mode.value = mode; + procFormFilter(fo_obj, update_group, procReload); +} + + +/* 금지아이디 추가 */ +function procInsertDeniedID(ret_obj, response_tags) { + var error = ret_obj['error']; + var message = ret_obj['message']; + var sid = ret_obj['sid']; + var act = ret_obj['act']; + var page = ret_obj['page']; + alert(message); + + url = "./admin.php?sid="+sid+"&page="+page+"&act="+act; + location.href = url; +} + +/* 금지아이디 관련 작업들 */ +function doUpdateDeniedID(user_id, mode, message) { + if(typeof(message)!='undefined'&&!confirm(message)) return; + + var fo_obj = xGetElementById('fo_denied_id_info'); + fo_obj.user_id.value = user_id; + fo_obj.mode.value = mode; + procFormFilter(fo_obj, update_denied_id, procReload); +} diff --git a/modules/member/admin/list.html b/modules/member/admin/list.html new file mode 100644 index 000000000..c78feff66 --- /dev/null +++ b/modules/member/admin/list.html @@ -0,0 +1,58 @@ + + + +
+ {number_format($total_count)}, + {$lang->page_count} : {number_format($page)} / {number_format($total_page)} +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
{$lang->no}{$lang->user_id}{$lang->user_name}{$lang->nick_name}{$lang->allow_mailing}{$lang->denied}{$lang->regdate}{$lang->last_login}{$lang->cmd_delete}
{$val->member_srl}{$val->user_id}{$val->user_name}{$val->nick_name}{$val->allow_mailing}{$val->denied}{zdate($val->regdate,"Y-m-d")}{zdate($val->last_login,"Y-m-d H:i:s")}{$lang->cmd_delete}
+
+ + + + + +
+ [{$lang->first_page}] + + + + {$page_no} + + [{$page_no}] + + + + [{$lang->last_page}] +
diff --git a/modules/member/admin/member_info.html b/modules/member/admin/member_info.html new file mode 100644 index 000000000..cfce3aceb --- /dev/null +++ b/modules/member/admin/member_info.html @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{$lang->user_id}{$member_info->user_id}
{$lang->user_name}{$member_info->user_name}
{$lang->nick_name}{$member_info->nick_name}
{$lang->email_address}{$member_info->email_address}
{$lang->allow_mailing}{$member_info->allow_mailing}
{$lang->denied}{$member_info->denied}
{$lang->is_admin}{$member_info->is_admin}
{$lang->group} + + {$val} + +
{$lang->description}{$member_info->description}
+ +
diff --git a/modules/member/lang/ko.lang.php b/modules/member/lang/ko.lang.php new file mode 100644 index 000000000..d11a19c02 --- /dev/null +++ b/modules/member/lang/ko.lang.php @@ -0,0 +1,45 @@ + + * @desc : 한국어 언어팩 (기본적인 내용만 수록) + **/ + + $lang->cmd_member_group = "그룹 관리"; + $lang->cmd_send_mail = "메일발송"; + $lang->cmd_manage_id = "금지아이디관리"; + $lang->cmd_manage_form = "가입폼관리"; + + $lang->already_logged = "이미 로그인되어 있습니다"; + $lang->denied_user_id = "사용금지된 아이디입니다"; + $lang->null_user_id = "사용자 아이디를 입력해주세요"; + $lang->null_password = "비밀번호를 입력해주세요"; + $lang->invalid_user_id= "존재하지 않는 사용자 아이디입니다"; + $lang->invalid_password = "잘못된 비밀번호입니다"; + + $lang->allow_mailing = "메일링 가입"; + $lang->denied = "사용중지"; + $lang->is_admin = "최고관리 권한"; + $lang->group = "소속 그룹"; + $lang->group_title = "그룹제목"; + $lang->group_srl = "그룹번호"; + + $lang->msg_new_member = "회원 추가"; + $lang->msg_update_member = "회원 정보 수정"; + $lang->msg_group_is_null = "등록된 그룹이 없습니다"; + $lang->msg_not_delete_default = "기본 항목을 삭제할 수 없습니다"; + $lang->msg_not_exists_member = '존재하지 않는 사용자입니다'; + $lang->msg_cannot_delete_admin = '관리자 아이디는 삭제할 수 없습니다. 관리자 해제후 다시 삭제시도해주세요'; + $lang->msg_exists_user_id = '이미 존재하는 아이디입니다. 다른 아이디를 입력해주세요'; + $lang->msg_exists_email_address = '이미 존재하는 메일주소입니다. 다른 메일주소를 입력해주세요'; + $lang->msg_exists_nick_name = '이미 존재하는 닉네임입니다. 다른 닉네임을 입력해주세요'; + + $lang->about_user_id = "사용자 ID는 3~20자 사이의 영문+숫자로 이루어져야 하며 영문으로 시작되어야 합니다"; + $lang->about_user_name = "이름은 2~20자 이내여야 합니다"; + $lang->about_nick_name = "닉네임은 2~20자 이내여야 합니다"; + $lang->about_allow_mailing = "메일링 가입이 체크되지 않으면 단체메일 발송시 메일을 받지 않습니다"; + $lang->about_denied = "체크시 아이디를 사용할 수 없도록 합니다"; + $lang->about_is_admin = "체크시 최고 관리자 권한을 가지게 됩니다"; + $lang->about_description = "회원에 대한 관리자 메모입니다"; + $lang->about_group = "한 아이디는 여러개의 group에 속할 수 있습니다"; +?> diff --git a/modules/member/member.admin.php b/modules/member/member.admin.php new file mode 100644 index 000000000..d9bcd26be --- /dev/null +++ b/modules/member/member.admin.php @@ -0,0 +1,267 @@ + + * @desc : member의 관리자 파일 + * Module class에서 상속을 받아서 사용 + * action 의 경우 disp/proc 2가지만 존재하며 이는 action명세서에 + * 미리 기록을 하여야 함 + **/ + + class member_admin extends Module { + + /** + * 기본 action 지정 + * $act값이 없거나 잘못된 값이 들어올 경우 $default_act 값으로 진행 + **/ + var $default_act = 'dispContent'; + + /** + * 현재 모듈의 초기화를 위한 작업을 지정해 놓은 method + * css/js파일의 load라든지 lang파일 load등을 미리 선언 + * + * Init() => 공통 + * dispInit() => disp시에 + * procInit() => proc시에 + * + * $this->module_path는 현재 이 모듈파일의 위치를 나타낸다 + * (ex: $this->module_path = "./modules/system_install/"; + **/ + + // 초기화 + function init() {/*{{{*/ + // 기본 정보를 읽음 + Context::loadLang($this->module_path.'lang'); + }/*}}}*/ + + // disp 초기화 + function dispInit() {/*{{{*/ + $oMember = getModule('member'); + + // member_srl이 있으면 미리 체크하여 member_info 세팅 + $member_srl = Context::get('member_srl'); + if($member_srl) { + $member_info = $oMember->getMemberInfoByMemberSrl($member_srl); + if(!$member_info) { + Context::set('member_srl',''); + $this->act = 'dispContent'; + } else Context::set('member_info',$member_info); + } + + // group 목록 가져오기 + $group_list = $oMember->getGroups(); + Context::set('group_list', $group_list); + + return true; + }/*}}}*/ + + // proc 초기화 + function procInit() {/*{{{*/ + return true; + }/*}}}*/ + + /** + * 여기서부터는 action의 구현 + * request parameter의 경우 각 method의 첫번째 인자로 넘어온다 + * + * dispXXXX : 출력을 위한 method, output에 tpl file이 지정되어야 한다 + * procXXXX : 처리를 위한 method, output에는 error, message가 지정되어야 한다 + **/ + + // 출력 부분 + function dispContent() {/*{{{*/ + + // 등록된 member 모듈을 불러와 세팅 + $oDB = &DB::getInstance(); + $args->sort_index = "member_srl"; + $args->page = Context::get('page'); + $args->list_count = 40; + $args->page_count = 10; + $output = $oDB->executeQuery('member.getMemberList', $args); + + // 템플릿에 쓰기 위해서 context::set + Context::set('total_count', $output->total_count); + Context::set('total_page', $output->total_page); + Context::set('page', $output->page); + Context::set('member_list', $output->data); + Context::set('page_navigation', $output->page_navigation); + + // 템플릿 파일 지정 + $this->setTemplateFile('list'); + }/*}}}*/ + + function dispInfo() {/*{{{*/ + // 템플릿 파일 지정 + $this->setTemplateFile('member_info'); + }/*}}}*/ + + function dispInsert() {/*{{{*/ + // 템플릿 파일 지정 + $this->setTemplateFile('insert_member'); + }/*}}}*/ + + function dispDeleteForm() {/*{{{*/ + if(!Context::get('member_srl')) return $this->dispContent(); + + // 템플릿 파일 지정 + $this->setTemplateFile('delete_form'); + }/*}}}*/ + + function dispGroup() {/*{{{*/ + // 그룹 목록 가져오기 + $oMember = getModule('member'); + $group_list = $oMember->getGroups(); + Context::set('group_list', $group_list); + + // 선택된 gruop_srl이 있으면 selected_group에 담기 + $group_srl = Context::get('group_srl'); + if($group_srl && $group_list[$group_srl]) { + Context::set('selected_group', $group_list[$group_srl]); + $this->setTemplateFile('group_update_form'); + } else { + $this->setTemplateFile('group_list'); + } + + }/*}}}*/ + + function dispDeniedID() {/*{{{*/ + // 사용금지 목록 가져오기 + $oMember = getModule('member'); + $output = $oMember->getDeniedIDList(); + + // 템플릿에 쓰기 위해서 context::set + Context::set('total_count', $output->total_count); + Context::set('total_page', $output->total_page); + Context::set('page', $output->page); + Context::set('member_list', $output->data); + Context::set('page_navigation', $output->page_navigation); + + // 템플릿 파일 지정 + $this->setTemplateFile('denied_list'); + }/*}}}*/ + + // 실행 부분 + function procInsert() {/*{{{*/ + // 일단 입력된 값들을 모두 받아서 db 입력항목과 그외 것으로 분리 + $args = Context::gets('member_srl','user_id','user_name','nick_name','email_address','password','allow_mailing','denied','is_admin','signature','profile_image','image_nick','image_mark','description','group_srl_list'); + + // member_srl이 있으면 원본을 구해온다 + $oMember = getModule('member'); + + // member_srl이 넘어오면 원 모듈이 있는지 확인 + if($args->member_srl) { + $member_info = $oMember->getMemberInfoByMemberSrl($args->member_srl); + // 만약 원래 모듈이 없으면 새로 입력하기 위한 처리 + if($member_info->member_srl != $args->member_srl) unset($args->member_srl); + } + + // member_srl의 값에 따라 insert/update + if(!$args->member_srl) { + $output = $oMember->insertMember($args); + $msg_code = 'success_registed'; + } else { + $output = $oMember->updateMember($args); + $msg_code = 'success_updated'; + } + + if(!$output->toBool()) return $output; + + $this->add('sid','member'); + $this->add('member_srl',$output->get('member_srl')); + $this->add('act','dispInfo'); + $this->add('page',Context::get('page')); + $this->setMessage($msg_code); + }/*}}}*/ + + function procDelete() {/*{{{*/ + // 일단 입력된 값들을 모두 받아서 db 입력항목과 그외 것으로 분리 + $member_srl = Context::get('member_srl'); + + // member_srl이 있으면 원본을 구해온다 + $oMember = getModule('member'); + $output = $oMember->deleteMember($member_srl); + if(!$output->toBool()) return $output; + + $this->add('sid','member'); + $this->add('page',Context::get('page')); + $this->setMessage("success_deleted"); + }/*}}}*/ + + function procInsertGroup() {/*{{{*/ + $args = Context::gets('title','description','is_default'); + $oMember = getModule('member'); + $output = $oMember->insertGroup($args); + if(!$output->toBool()) return $output; + + $this->add('sid','member'); + $this->add('act','dispGroup'); + $this->add('group_srl',''); + $this->add('page',Context::get('page')); + $this->setMessage('success_registed'); + }/*}}}*/ + + function procUpdateGroup() {/*{{{*/ + $group_srl = Context::get('group_srl'); + $mode = Context::get('mode'); + + $oMember = getModule('member'); + + switch($mode) { + case 'delete' : + $output = $oMember->deleteGroup($group_srl); + if(!$output->toBool()) return $output; + $msg_code = 'success_deleted'; + break; + case 'update' : + $args = Context::gets('group_srl','title','description','is_default'); + $output = $oMember->updateGroup($args); + if(!$output->toBool()) return $output; + $msg_code = 'success_updated'; + break; + } + + $this->add('sid','member'); + $this->add('act','dispGroup'); + $this->add('group_srl',''); + $this->add('page',Context::get('page')); + $this->setMessage($msg_code); + }/*}}}*/ + + function procInsertDeniedID() {/*{{{*/ + $user_id = Context::get('user_id'); + $description = Context::get('description'); + $oMember = getModule('member'); + $output = $oMember->insertDeniedID($user_id, $description); + if(!$output->toBool()) return $output; + + $this->add('sid','member'); + $this->add('act','dispDeniedID'); + $this->add('group_srl',''); + $this->add('page',Context::get('page')); + $this->setMessage('success_registed'); + }/*}}}*/ + + function procUpdateDeniedID() {/*{{{*/ + $user_id = Context::get('user_id'); + $mode = Context::get('mode'); + + $oMember = getModule('member'); + + switch($mode) { + case 'delete' : + $output = $oMember->deleteDeniedID($user_id); + if(!$output->toBool()) return $output; + $msg_code = 'success_deleted'; + break; + } + + $this->add('sid','member'); + $this->add('act','dispDeniedID'); + $this->add('page',Context::get('page')); + $this->setMessage($msg_code); + }/*}}}*/ + /** + * 여기부터는 이 모듈과 관련된 라이브러리 개념의 method들 + **/ + } +?> diff --git a/modules/member/member.module.php b/modules/member/member.module.php new file mode 100644 index 000000000..54761b5d1 --- /dev/null +++ b/modules/member/member.module.php @@ -0,0 +1,477 @@ + + * @desc : 기본 모듈중의 하나인 member module + * Module class에서 상속을 받아서 사용 + * action 의 경우 disp/proc 2가지만 존재하며 이는 action명세서에 + * 미리 기록을 하여야 함 + **/ + + class member extends Module { + + /** + * 모듈의 정보 + **/ + var $cur_version = "20070130_0.01"; + + /** + * 기본 action 지정 + * $act값이 없거나 잘못된 값이 들어올 경우 $default_act 값으로 진행 + **/ + var $default_act = ''; + + /** + * 현재 모듈의 초기화를 위한 작업을 지정해 놓은 method + * css/js파일의 load라든지 lang파일 load등을 미리 선언 + * + * Init() => 공통 + * dispInit() => disp시에 + * procInit() => proc시에 + * + * $this->module_path는 현재 이 모듈파일의 위치를 나타낸다 + * (ex: $this->module_path = "./modules/member/"; + **/ + + // 초기화 + function init() {/*{{{*/ + Context::loadLang($this->module_path.'lang'); + }/*}}}*/ + + // disp 초기화 + function dispInit() {/*{{{*/ + return true; + }/*}}}*/ + + // proc 초기화 + function procInit() {/*{{{*/ + return true; + }/*}}}*/ + + /** + * 여기서부터는 action의 구현 + * request parameter의 경우 각 method의 첫번째 인자로 넘어온다 + * + * dispXXXX : 출력을 위한 method, output에 tpl file이 지정되어야 한다 + * procXXXX : 처리를 위한 method, output에는 error, message가 지정되어야 한다 + * + * 변수의 사용은 Context::get('이름')으로 얻어오면 된다 + **/ + + /** + * 여기부터는 이 모듈과 관련된 라이브러리 개념의 method들 + **/ + + // 로그인/로그아웃 처리 + // public void doLogin($user_id, $password) /*{{{*/ + // user_id, password를 체크하여 로그인 시킴 + function doLogin($user_id, $password) { + // 변수 정리 + $user_id = trim($user_id); + $password = trim($password); + + // 이메일 주소나 비밀번호가 없을때 오류 return + if(!$user_id) return new Output(-1,Context::getLang('null_user_id')); + if(!$password) return new Output(-1,Context::getLang('null_password')); + + $oDB = &DB::getInstance(); + + // user_id 에 따른 정보 가져옴 + $args->user_id = $user_id; + $member_info = $this->getMemberInfo($user_id, false); + + // return 값이 없거나 비밀번호가 틀릴 경우 + if($member_info->user_id != $user_id) return new Output(-1, Context::getLang('invalid_user_id')); + if($member_info->password != md5($password)) return new Output(-1, Context::getLang('invalid_password')); + + // 로그인 처리 + $_SESSION['is_logged'] = true; + $_SESSION['ipaddress'] = $_SERVER['REMOTE_ADDR']; + + unset($member_info->password); + + // 세션에 로그인 사용자 정보 저장 + $_SESSION['member_srl'] = $member_info->member_srl; + $_SESSION['logged_info'] = $member_info; + + // 사용자 정보의 최근 로그인 시간을 기록 + $args->member_srl = $member_info->member_srl; + $oDB->executeQuery('member.updateLastLogin', $args); + + return new Output(); + }/*}}}*/ + + // public void doLogout() /*{{{*/ + // 로그아웃 + function doLogout() { + // 로그인 처리 + $_SESSION['is_logged'] = false; + $_SESSION['ipaddress'] = $_SERVER['REMOTE_ADDR']; + $_SESSION['logged_info'] = NULL; + return new Output(); + }/*}}}*/ + + // member 정보 입출력 관련 + // public void insertAdmin($args)/*{{{*/ + // 관리자를 추가한다 + function insertAdmin($args) { + $args->is_admin = 'Y'; + return $this->insertMember($args); + }/*}}}*/ + + // public void insertMember($args)/*{{{*/ + // member 테이블에 사용자 추가 + function insertMember($args) { + // 필수 변수들의 조절 + if($args->allow_mailing!='Y') $args->allow_mailing = 'N'; + if($args->denied!='Y') $args->denied = 'N'; + if($args->is_admin!='Y') $args->is_admin = 'N'; + list($args->email_id, $args->email_host) = explode('@', $args->email_address); + + // 금지 아이디인지 체크 + if($this->chkDeniedID($args->user_id)) return new Output(-1,'denied_user_id'); + + // 아이디, 닉네임, email address 의 중복 체크 + $member_srl = $this->getMemberSrlByUserID($args->user_id); + if($member_srl) return new Output(-1,'msg_exists_user_id'); + + $member_srl = $this->getMemberSrlByNickName($args->nick_name); + if($member_srl) return new Output(-1,'msg_exists_nick_name'); + + $member_srl = $this->getMemberSrlByEmailAddress($args->email_address); + if($member_srl) return new Output(-1,'msg_exists_email_address'); + + // DB 입력 + $oDB = &DB::getInstance(); + $args->member_srl = $oDB->getNextSequence(); + if($args->password) $args->password = md5($args->password); + else unset($args->password); + $output = $oDB->executeQuery('member.insertMember', $args); + if(!$output->toBool()) return $output; + + // 기본 그룹을 입력 + $default_group = $this->getDefaultGroup(); + + // 기본 그룹에 추가 + $output = $this->addMemberToGroup($args->member_srl,$default_group->group_srl); + if(!$output->toBool()) return $output; + + $output->add('member_srl', $args->member_srl); + return $output; + }/*}}}*/ + + // public void updateMember($args)/*{{{*/ + // member 정보 수정 + function updateMember($args) { + $member_info = $this->getMemberInfoByMemberSrl($args->member_srl); + + // 필수 변수들의 조절 + if($args->allow_mailing!='Y') $args->is_default = 'N'; + if($args->denied!='Y') $args->denied = 'N'; + if($args->is_admin!='Y') $args->use_category = 'N'; + list($args->email_id, $args->email_host) = explode('@', $args->email_address); + + // 아이디, 닉네임, email address 의 중복 체크 + $member_srl = $this->getMemberSrlByUserID($args->user_id); + if($member_srl&&$args->member_srl!=$member_srl) return new Output(-1,'msg_exists_user_id'); + $member_srl = $this->getMemberSrlByNickName($args->nick_name); + if($member_srl&&$args->member_srl!=$member_srl) return new Output(-1,'msg_exists_nick_name'); + $member_srl = $this->getMemberSrlByEmailAddress($args->email_address); + if($member_srl&&$args->member_srl!=$member_srl) return new Output(-1,'msg_exists_email_address'); + + // DB 입력 + $oDB = &DB::getInstance(); + if($args->password) $args->password = md5($args->password); + else $args->password = $member_info->password; + + $output = $oDB->executeQuery('member.updateMember', $args); + if(!$output->toBool()) return $output; + + // 그룹에 추가 + $output = $oDB->executeQuery('member.deleteMemberGroupMember', $args); + if(!$output->toBool()) return $output; + + $group_srl_list = explode(',', $args->group_srl_list); + for($i=0;$iaddMemberToGroup($args->member_srl,$group_srl_list[$i]); + if(!$output->toBool()) return $output; + } + + $output->add('member_srl', $args->member_srl); + return $output; + }/*}}}*/ + + // public void deleteMember($member_srl)/*{{{*/ + // 사용자 삭제 + function deleteMember($member_srl) { + + $oDB = &DB::getInstance(); + + // 해당 사용자의 정보를 가져옴 + $member_info = $this->getMemberInfoByMemberSrl($member_srl); + if(!$member_info) return new Output(-1, 'msg_not_exists_member'); + + // 관리자의 경우 삭제 불가능 + if($member_info->is_admin == 'Y') return new Output(-1, 'msg_cannot_delete_admin'); + + // member_group_member에서 해당 항목들 삭제 + $args->member_srl = $member_srl; + $output = $oDB->executeQuery('member.deleteMemberGroupMember', $args); + if(!$output->toBool()) return $output; + + // member 테이블에서 삭제 + $output = $oDB->executeQuery('member.deleteMember', $args); + return $output; + }/*}}}*/ + + // public boolean isLogged() {/*{{{*/ + // 로그인 되어 있는지에 대한 체크 + function isLogged() { + if($_SESSION['is_logged']&&$_SESSION['ipaddress']==$_SERVER['REMOTE_ADDR']) return true; + + $_SESSION['is_logged'] = false; + $_SESSION['logged_info'] = ''; + return false; + }/*}}}*/ + + // public object getLoggedInfo()/*{{{*/ + // user_id에 해당하는 사용자 정보 return + function getLoggedInfo() { + // 로그인 되어 있고 세션 정보를 요청하면 세션 정보를 return + if($this->isLogged()) return $_SESSION['logged_info']; + }/*}}}*/ + + // public object getMemberInfo($user_id)/*{{{*/ + // user_id에 해당하는 사용자 정보 return + function getMemberInfo($user_id) { + // DB에서 가져오기 + $oDB = &DB::getInstance(); + $args->user_id = $user_id; + $output = $oDB->executeQuery('member.getMemberInfo', $args); + if(!$output) return $output; + + $member_info = $output->data; + $member_info->group_list = $this->getMemberGroups($member_info->member_srl); + + return $member_info; + }/*}}}*/ + + // public object getMemberInfoByMemberSrl($member_srl)/*{{{*/ + // user_id에 해당하는 사용자 정보 return + function getMemberInfoByMemberSrl($member_srl) { + // DB에서 가져오기 + $oDB = &DB::getInstance(); + $args->member_srl = $member_srl; + $output = $oDB->executeQuery('member.getMemberInfoByMemberSrl', $args); + if(!$output) return $output; + + $member_info = $output->data; + $member_info->group_list = $this->getMemberGroups($member_info->member_srl); + + return $member_info; + }/*}}}*/ + + // public int getMemberSrl() /*{{{*/ + // 현재 접속자의 member_srl을 return + function getMemberSrl() { + if(!$this->isLogged()) return; + return $_SESSION['member_srl']; + }/*}}}*/ + + // group 관련 + // public object addMemberToGroup($member_srl, $group_srl) /*{{{*/ + // member_srl에 gruop_srl을 추가 + function addMemberToGroup($member_srl,$group_srl) { + $args->member_srl = $member_srl; + $args->group_srl = $group_srl; + + $oDB = &DB::getInstance(); + + // 추가 + $output = $oDB->executeQuery('member.addMemberToGroup',$args); + if(!$output->toBool()) return $output; + + return $output; + }/*}}}*/ + + // public void changeGroup($source_group_srl, $target_group_srl)/*{{{*/ + // 회원의 그룹값을 변경 + function changeGroup($source_group_srl, $target_group_srl) { + $oDB = &DB::getInstance(); + $args->source_group_srl = $source_group_srl; + $args->target_group_srl = $target_group_srl; + return $oDB->executeQuery('member.changeGroup', $args); + }/*}}}*/ + + // public object getMemberGroups($member_srl) /*{{{*/ + // member_srl이 속한 group 목록을 가져옴 + function getMemberGroups($member_srl) { + $oDB = &DB::getInstance(); + $args->member_srl = $member_srl; + $output = $oDB->executeQuery('member.getMemberGroups', $args); + if(!$output->data) return; + + $group_list = $output->data; + if(!is_array($group_list)) $group_list = array($group_list); + foreach($group_list as $group) { + $result[$group->group_srl] = $group->title; + } + return $result; + }/*}}}*/ + + // public object getDefaultGroup() /*{{{*/ + // 기본 그룹을 가져옴 + function getDefaultGroup() { + $oDB = &DB::getInstance(); + $output = $oDB->executeQuery('member.getDefaultGroup'); + return $output->data; + }/*}}}*/ + + // public object getGroup($group_srl) /*{{{*/ + // group_srl에 해당하는 그룹 정보 가져옴 + function getGroup($group_srl) { + $oDB = &DB::getInstance(); + $args->group_srl = $group_srl; + $output = $oDB->executeQuery('member.getGroup', $args); + return $output->data; + }/*}}}*/ + + // public object getGroups() /*{{{*/ + // 그룹 목록을 가져옴 + function getGroups() { + $oDB = &DB::getInstance(); + $output = $oDB->executeQuery('member.getGroups'); + if(!$output->data) return; + + $group_list = $output->data; + if(!is_array($group_list)) $group_list = array($group_list); + foreach($group_list as $val) { + $result[$val->group_srl] = $val; + } + return $result; + }/*}}}*/ + + // public object insertGroup() /*{{{*/ + // 그룹 등록 + function insertGroup($args) { + $oDB = &DB::getInstance(); + + // is_default값을 체크, Y일 경우 일단 모든 is_default에 대해서 N 처리 + if($args->is_default!='Y') $args->is_default = 'N'; + else $oDB->executeQuery('member.updateGroupDefaultClear'); + + $output = $oDB->executeQuery('member.insertGroup', $args); + return $output; + }/*}}}*/ + + // public object updateGroup() /*{{{*/ + // 그룹 등록 + function updateGroup($args) { + $oDB = &DB::getInstance(); + // is_default값을 체크, Y일 경우 일단 모든 is_default에 대해서 N 처리 + if($args->is_default!='Y') $args->is_default = 'N'; + else { + $oDB->executeQuery('member.updateGroupDefaultClear'); + } + + $output = $oDB->executeQuery('member.updateGroup', $args); + return $output; + }/*}}}*/ + + // public object deleteGroup($group_srl) /*{{{*/ + // 그룹 등록 + function deleteGroup($group_srl) { + // 삭제 대상 그룹을 가져와서 체크 (is_default == 'Y'일 경우 삭제 불가) + $group_info = $this->getGroup($group_srl); + if(!$group_info) return new Output(-1, 'lang->msg_not_founded'); + if($group_info->is_default == 'Y') return new Output(-1, 'msg_not_delete_default'); + + // is_default == 'Y'인 그룹을 가져옴 + $default_group = $this->getDefaultGroup(); + $default_group_srl = $default_group->group_srl; + + // default_group_srl로 변경 + $this->changeGroup($group_srl, $default_group_srl); + + // 그룹 삭제 + $oDB = &DB::getInstance(); + $args->group_srl = $group_srl; + $output = $oDB->executeQuery('member.deleteGroup', $args); + return $output; + }/*}}}*/ + + // 금지 아이디 + // public object getDeniedIDList() /*{{{*/ + // 금지 아이디 목록 가져오기 + function getDeniedIDList() { + $oDB = &DB::getInstance(); + $args->sort_index = "list_order"; + $args->page = Context::get('page'); + $args->list_count = 40; + $args->page_count = 10; + $output = $oDB->executeQuery('member.getDeniedIDList', $args); + return $output; + }/*}}}*/ + + // public object insertDeniedID() /*{{{*/ + // 금지아이디 등록 + function insertDeniedID($user_id, $desription = '') { + $oDB = &DB::getInstance(); + + $args->user_id = $user_id; + $args->description = $description; + $args->list_order = -1*$oDB->getNextSequence(); + + return $oDB->executeQuery('member.insertDeniedID', $args); + }/*}}}*/ + + // public object deleteDeniedID() /*{{{*/ + // 금지아이디 등록 + function deleteDeniedID($user_id) { + $oDB = &DB::getInstance(); + + $args->user_id = $user_id; + return $oDB->executeQuery('member.deleteDeniedID', $args); + }/*}}}*/ + + // public object chkDeniedID($user_id) /*{{{*/ + // 금지아이디 등록 + function chkDeniedID($user_id) { + $oDB = &DB::getInstance(); + + $args->user_id = $user_id; + + $output = $oDB->executeQuery('member.chkDeniedID', $args); + if($output->data->count) return true; + return false; + }/*}}}*/ + + // 기타 + // public boolean getMemberSrlByUserID($user_id) {/*{{{*/ + // userid에 해당하는 member_srl을 구함 + function getMemberSrlByUserID($user_id) { + $oDB = &DB::getInstance(); + $args->user_id = $user_id; + $output = $oDB->executeQuery('member.getMemberSrl', $args); + return $output->data->member_srl; + }/*}}}*/ + + // public boolean getMemberSrlByEmailAddress($email_address) {/*{{{*/ + // userid에 해당하는 member_srl을 구함 + function getMemberSrlByEmailAddress($email_address) { + $oDB = &DB::getInstance(); + $args->email_address = $email_address; + $output = $oDB->executeQuery('member.getMemberSrl', $args); + return $output->data->member_srl; + }/*}}}*/ + + // public boolean getMemberSrlByNickName($nick_name) {/*{{{*/ + // userid에 해당하는 member_srl을 구함 + function getMemberSrlByNickName($nick_name) { + $oDB = &DB::getInstance(); + $args->nick_name = $nick_name; + $output = $oDB->executeQuery('member.getMemberSrl', $args); + return $output->data->member_srl; + }/*}}}*/ + } +?> diff --git a/modules/member/module.xml b/modules/member/module.xml new file mode 100644 index 000000000..97767fae8 --- /dev/null +++ b/modules/member/module.xml @@ -0,0 +1,11 @@ + + + 회원 관리 + member + + 제로 + zero + 회원 관리 모듈 + member + + diff --git a/modules/member/queries/addMemberToGroup.xml b/modules/member/queries/addMemberToGroup.xml new file mode 100644 index 000000000..275893565 --- /dev/null +++ b/modules/member/queries/addMemberToGroup.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/modules/member/queries/changeGroup.xml b/modules/member/queries/changeGroup.xml new file mode 100644 index 000000000..c45084d34 --- /dev/null +++ b/modules/member/queries/changeGroup.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/member/queries/chkDeniedID.xml b/modules/member/queries/chkDeniedID.xml new file mode 100644 index 000000000..5258c11f0 --- /dev/null +++ b/modules/member/queries/chkDeniedID.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/member/queries/deleteDeniedID.xml b/modules/member/queries/deleteDeniedID.xml new file mode 100644 index 000000000..6f9698adb --- /dev/null +++ b/modules/member/queries/deleteDeniedID.xml @@ -0,0 +1,8 @@ + + +
+ + + + + diff --git a/modules/member/queries/deleteGroup.xml b/modules/member/queries/deleteGroup.xml new file mode 100644 index 000000000..5ae5991a7 --- /dev/null +++ b/modules/member/queries/deleteGroup.xml @@ -0,0 +1,8 @@ + + +
+ + + + + diff --git a/modules/member/queries/deleteMember.xml b/modules/member/queries/deleteMember.xml new file mode 100644 index 000000000..e8dd2d4a3 --- /dev/null +++ b/modules/member/queries/deleteMember.xml @@ -0,0 +1,8 @@ + + +
+ + + + + diff --git a/modules/member/queries/deleteMemberGroupMember.xml b/modules/member/queries/deleteMemberGroupMember.xml new file mode 100644 index 000000000..d3415451a --- /dev/null +++ b/modules/member/queries/deleteMemberGroupMember.xml @@ -0,0 +1,9 @@ + + +
+ + + + + + diff --git a/modules/member/queries/getDefaultGroup.xml b/modules/member/queries/getDefaultGroup.xml new file mode 100644 index 000000000..a8db3549b --- /dev/null +++ b/modules/member/queries/getDefaultGroup.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/member/queries/getDeniedIDList.xml b/modules/member/queries/getDeniedIDList.xml new file mode 100644 index 000000000..7ced9bc13 --- /dev/null +++ b/modules/member/queries/getDeniedIDList.xml @@ -0,0 +1,14 @@ + + +
+ + + + + + + + + + + diff --git a/modules/member/queries/getGroup.xml b/modules/member/queries/getGroup.xml new file mode 100644 index 000000000..d782f933f --- /dev/null +++ b/modules/member/queries/getGroup.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/member/queries/getGroups.xml b/modules/member/queries/getGroups.xml new file mode 100644 index 000000000..806806252 --- /dev/null +++ b/modules/member/queries/getGroups.xml @@ -0,0 +1,8 @@ + + +
+ + + + + diff --git a/modules/member/queries/getMemberGroups.xml b/modules/member/queries/getMemberGroups.xml new file mode 100644 index 000000000..e9336ae6f --- /dev/null +++ b/modules/member/queries/getMemberGroups.xml @@ -0,0 +1,14 @@ + + +
+
+ + + + + + + + + + diff --git a/modules/member/queries/getMemberInfo.xml b/modules/member/queries/getMemberInfo.xml new file mode 100644 index 000000000..36a5e0b97 --- /dev/null +++ b/modules/member/queries/getMemberInfo.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/member/queries/getMemberInfoByMemberSrl.xml b/modules/member/queries/getMemberInfoByMemberSrl.xml new file mode 100644 index 000000000..bc777ece3 --- /dev/null +++ b/modules/member/queries/getMemberInfoByMemberSrl.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/member/queries/getMemberList.xml b/modules/member/queries/getMemberList.xml new file mode 100644 index 000000000..a0d080ab4 --- /dev/null +++ b/modules/member/queries/getMemberList.xml @@ -0,0 +1,14 @@ + + +
+ + + + + + + + + + + diff --git a/modules/member/queries/getMemberSrl.xml b/modules/member/queries/getMemberSrl.xml new file mode 100644 index 000000000..93f413939 --- /dev/null +++ b/modules/member/queries/getMemberSrl.xml @@ -0,0 +1,13 @@ + + +
+ + + + + + + + + + diff --git a/modules/member/queries/insertDeniedID.xml b/modules/member/queries/insertDeniedID.xml new file mode 100644 index 000000000..d428887cf --- /dev/null +++ b/modules/member/queries/insertDeniedID.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/member/queries/insertGroup.xml b/modules/member/queries/insertGroup.xml new file mode 100644 index 000000000..0096f724b --- /dev/null +++ b/modules/member/queries/insertGroup.xml @@ -0,0 +1,12 @@ + + +
+ + + + + + + + + diff --git a/modules/member/queries/insertMember.xml b/modules/member/queries/insertMember.xml new file mode 100644 index 000000000..bacc7366d --- /dev/null +++ b/modules/member/queries/insertMember.xml @@ -0,0 +1,26 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/member/queries/updateGroup.xml b/modules/member/queries/updateGroup.xml new file mode 100644 index 000000000..546ca4edd --- /dev/null +++ b/modules/member/queries/updateGroup.xml @@ -0,0 +1,13 @@ + + +
+ + + + + + + + + + diff --git a/modules/member/queries/updateGroupDefaultClear.xml b/modules/member/queries/updateGroupDefaultClear.xml new file mode 100644 index 000000000..1c4726ab2 --- /dev/null +++ b/modules/member/queries/updateGroupDefaultClear.xml @@ -0,0 +1,8 @@ + + +
+ + + + + diff --git a/modules/member/queries/updateLastLogin.xml b/modules/member/queries/updateLastLogin.xml new file mode 100644 index 000000000..186e026c8 --- /dev/null +++ b/modules/member/queries/updateLastLogin.xml @@ -0,0 +1,12 @@ + + +
+ + + + + + + + + diff --git a/modules/member/queries/updateMember.xml b/modules/member/queries/updateMember.xml new file mode 100644 index 000000000..1dedebeef --- /dev/null +++ b/modules/member/queries/updateMember.xml @@ -0,0 +1,24 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + diff --git a/modules/member/schemas/member.xml b/modules/member/schemas/member.xml new file mode 100644 index 000000000..169f8e21f --- /dev/null +++ b/modules/member/schemas/member.xml @@ -0,0 +1,23 @@ +
+ + + + + + + + + + + + + + + + + + + + + +
diff --git a/modules/member/schemas/member_denied_user_id.xml b/modules/member/schemas/member_denied_user_id.xml new file mode 100644 index 000000000..8924879e8 --- /dev/null +++ b/modules/member/schemas/member_denied_user_id.xml @@ -0,0 +1,6 @@ + + + + + +
diff --git a/modules/member/schemas/member_group.xml b/modules/member/schemas/member_group.xml new file mode 100644 index 000000000..3abce647f --- /dev/null +++ b/modules/member/schemas/member_group.xml @@ -0,0 +1,7 @@ + + + + + + +
diff --git a/modules/member/schemas/member_group_member.xml b/modules/member/schemas/member_group_member.xml new file mode 100644 index 000000000..69324707a --- /dev/null +++ b/modules/member/schemas/member_group_member.xml @@ -0,0 +1,5 @@ + + + + +
diff --git a/modules/message/message.module.php b/modules/message/message.module.php new file mode 100644 index 000000000..d8029868a --- /dev/null +++ b/modules/message/message.module.php @@ -0,0 +1,66 @@ + + * @desc : 기본 모듈중의 하나인 message module + * Module class에서 상속을 받아서 사용 + * action 의 경우 disp/proc 2가지만 존재하며 이는 action명세서에 + * 미리 기록을 하여야 함 + **/ + + class message extends Module { + + /** + * 모듈의 정보 + **/ + var $cur_version = "20070130_0.01"; + + /** + * 기본 action 지정 + * $act값이 없거나 잘못된 값이 들어올 경우 $default_act 값으로 진행 + **/ + var $default_act = 'dispSystemMessage'; + + /** + * 현재 모듈의 초기화를 위한 작업을 지정해 놓은 method + * css/js파일의 load라든지 lang파일 load등을 미리 선언 + * + * Init() => 공통 + * dispInit() => disp시에 + * procInit() => proc시에 + * + * $this->module_path는 현재 이 모듈파일의 위치를 나타낸다 + * (ex: $this->module_path = "./modules/install/"; + **/ + + // 초기화 + function init() {/*{{{*/ + }/*}}}*/ + + // disp 초기화 + function dispInit() {/*{{{*/ + Context::addCssFile($this->template_path.'css/message.css'); + }/*}}}*/ + + // proc 초기화 + function procInit() {/*{{{*/ + }/*}}}*/ + + /** + * 여기서부터는 action의 구현 + * request parameter의 경우 각 method의 첫번째 인자로 넘어온다 + * + * dispXXXX : 출력을 위한 method, output에 tpl file이 지정되어야 한다 + * procXXXX : 처리를 위한 method, output에는 message, message가 지정되어야 한다 + **/ + // function void dispSystemMessage()/*{{{*/ + // 메세지 출력 Context의 erro/ message를 출력 + function dispSystemMessage() { + $this->setTemplateFile('system_message'); + }/*}}}*/ + + /** + * 여기부터는 이 모듈과 관련된 라이브러리 개념의 method들 + **/ + } +?> diff --git a/modules/message/module.xml b/modules/message/module.xml new file mode 100644 index 000000000..27d544ce4 --- /dev/null +++ b/modules/message/module.xml @@ -0,0 +1,11 @@ + + + 메세지 + message + + 제로 + zero + 메세지 관리 모듈 + message + + diff --git a/modules/message/skins/default/css/message.css b/modules/message/skins/default/css/message.css new file mode 100644 index 000000000..e69de29bb diff --git a/modules/message/skins/default/system_message.html b/modules/message/skins/default/system_message.html new file mode 100644 index 000000000..77ad1866e --- /dev/null +++ b/modules/message/skins/default/system_message.html @@ -0,0 +1,11 @@ + + + + + + + + + + +
error{$error}
message{$message}
diff --git a/modules/module_manager/admin/index.html b/modules/module_manager/admin/index.html new file mode 100644 index 000000000..ca3cd2939 --- /dev/null +++ b/modules/module_manager/admin/index.html @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + +
{$lang->no}{$lang->module_name}{$lang->module_version}{$lang->module_table_count}{$lang->module_installed_path}{$lang->author}
{$no+1}{$module_obj->title}{$module_obj->version}{$module_obj->created_table_count} / {$module_obj->table_count}{$module_obj->path}{$module_obj->author->name}
+ diff --git a/modules/module_manager/lang/ko.lang.php b/modules/module_manager/lang/ko.lang.php new file mode 100644 index 000000000..ef59ce7a3 --- /dev/null +++ b/modules/module_manager/lang/ko.lang.php @@ -0,0 +1,12 @@ + + * @desc : 한국어 언어팩 + **/ + $lang->module_name = "모듈 이름"; + $lang->module_table_count = "테이블수"; + $lang->module_date = "제작일"; + $lang->module_installed_path = "설치경로"; + $lang->module_version = "버전"; +?> diff --git a/modules/module_manager/module.xml b/modules/module_manager/module.xml new file mode 100644 index 000000000..7fee6be0b --- /dev/null +++ b/modules/module_manager/module.xml @@ -0,0 +1,11 @@ + + + 모듈 관리 + module management + + 제로 + zero + 모듈 관리 모듈 + module management + + diff --git a/modules/module_manager/module_manager.admin.php b/modules/module_manager/module_manager.admin.php new file mode 100644 index 000000000..c90a0662c --- /dev/null +++ b/modules/module_manager/module_manager.admin.php @@ -0,0 +1,119 @@ + + * @desc : module_manager의 관리자 파일 + * Module class에서 상속을 받아서 사용 + * action 의 경우 disp/proc 2가지만 존재하며 이는 action명세서에 + * 미리 기록을 하여야 함 + **/ + + class module_manager_admin extends Module { + + /** + * 기본 action 지정 + * $act값이 없거나 잘못된 값이 들어올 경우 $default_act 값으로 진행 + **/ + var $default_act = 'dispContent'; + + /** + * 현재 모듈의 초기화를 위한 작업을 지정해 놓은 method + * css/js파일의 load라든지 lang파일 load등을 미리 선언 + * + * Init() => 공통 + * dispInit() => disp시에 + * procInit() => proc시에 + * + * $this->module_path는 현재 이 모듈파일의 위치를 나타낸다 + * (ex: $this->module_path = "./modules/system_install/"; + **/ + + // 초기화 + function init() {/*{{{*/ + + // 기본 정보를 읽음 + Context::loadLang($this->module_path.'lang'); + }/*}}}*/ + + // disp 초기화 + function dispInit() {/*{{{*/ + return true; + }/*}}}*/ + + // proc 초기화 + function procInit() {/*{{{*/ + return true; + }/*}}}*/ + + /** + * 여기서부터는 action의 구현 + * request parameter의 경우 각 method의 첫번째 인자로 넘어온다 + * + * dispXXXX : 출력을 위한 method, output에 tpl file이 지정되어야 한다 + * procXXXX : 처리를 위한 method, output에는 error, message가 지정되어야 한다 + **/ + + // 출력 부분 + function dispContent() {/*{{{*/ + // 등록된 모듈의 목록을 구해옴 + $installed_module_list = $this->getModulesInfo(); + Context::set('installed_module_list', $installed_module_list); + + // 템플릿 파일 지정 + $this->setTemplateFile('index'); + }/*}}}*/ + + // 실행 부분 + + /** + * 여기부터는 이 모듈과 관련된 라이브러리 개념의 method들 + **/ + function getModulesInfo() {/*{{{*/ + // DB 객체 생성 + $oDB = &DB::getInstance(); + + // 다운받은 모듈과 설치된 모듈의 목록을 구함 + $downloaded_list = FileHandler::readDir('./files/modules'); + $installed_list = FileHandler::readDir('./modules'); + + // 찾아진 모듈목록에서 admin은 제외시킴 + $searched_list = array_merge($downloaded_list, $installed_list); + if(!count($searched_list)) return; + + for($i=0;$iisTableExists($table_name)) $created_table_count ++; + } + + // 해당 모듈의 정보를 구함 + $info = module_manager::loadModuleXml($path); + unset($obj); + + $info->module = $module_name; + $info->created_table_count = $created_table_count; + $info->table_count = $table_count; + $info->path = $path; + + $list[] = $info; + } + return $list; + }/*}}}*/ + } + +?> diff --git a/modules/module_manager/module_manager.module.php b/modules/module_manager/module_manager.module.php new file mode 100644 index 000000000..da5ba16a5 --- /dev/null +++ b/modules/module_manager/module_manager.module.php @@ -0,0 +1,455 @@ + + * @desc : 기본 모듈중의 하나 + * Module class에서 상속을 받아서 사용 + * 모듈과 관련된 method들이 존재 + **/ + + class module_manager extends Module { + + /** + * 모듈의 정보 + **/ + var $cur_version = "20070130_0.01"; + + /** + * 기본 action 지정 + * $act값이 없거나 잘못된 값이 들어올 경우 $default_act 값으로 진행 + **/ + var $default_act = ''; + + /** + * 현재 모듈의 초기화를 위한 작업을 지정해 놓은 method + * css/js파일의 load라든지 lang파일 load등을 미리 선언 + * + * Init() => 공통 + * dispInit() => disp시에 + * procInit() => proc시에 + * + * $this->module_path는 현재 이 모듈파일의 위치를 나타낸다 + * (ex: $this->module_path = "./modules/module/"; + **/ + + // 초기화 + function init() {/*{{{*/ + Context::loadLang($this->module_path.'lang'); + }/*}}}*/ + + // disp 초기화 + function dispInit() {/*{{{*/ + return true; + }/*}}}*/ + + // proc 초기화 + function procInit() {/*{{{*/ + return true; + }/*}}}*/ + + /** + * 여기서부터는 action의 구현 + * request parameter의 경우 각 method의 첫번째 인자로 넘어온다 + * + * dispXXXX : 출력을 위한 method, output에 tpl file이 지정되어야 한다 + * procXXXX : 처리를 위한 method, output에는 error, message가 지정되어야 한다 + * + * 변수의 사용은 Context::get('이름')으로 얻어오면 된다 + **/ + + /** + * 여기서부터는 관련 lib... + **/ + // public string getModuleInfoByDocument($document_srl)/*{{{*/ + // $document_srl로 모듈정보를 구함 + function getModuleInfoByDocument($document_srl) { + $oDB = &DB::getInstance(); + $args->document_srl = $document_srl; + $output = $oDB->executeQuery('module_manager.getModuleInfoByDocument', $args); + // extra_vars의 정리 + $module_info = module_manager::extractExtraVar($output->data); + return $module_info; + }/*}}}*/ + + // public object getModuleInfo($mid='')/*{{{*/ + // $mid의 정보를 load, mid값이 없다면 기본 mid 정보를 읽음 + function getModuleInfo($mid='') { + // DB에서 가져옴 + $oDB = &DB::getInstance(); + if($mid) { + $args->mid = $mid; + $output = $oDB->executeQuery('module_manager.getMidInfo', $args); + } + if(!$output->data) $output = $oDB->executeQuery('module_manager.getDefaultMidInfo'); + return module_manager::arrangeModuleInfo($output->data); + }/*}}}*/ + + // public object getModuleInfoByModuleSrl($module_srl='')/*{{{*/ + // $modulr_srl로 모듈의 정보를 읽음 + function getModuleInfoByModuleSrl($module_srl='') { + $oDB = &DB::getInstance(); + $args->module_srl = $module_srl; + $output = $oDB->executeQuery('module_manager.getMidInfo', $args); + if(!$output->data) return; + return module_manager::arrangeModuleInfo($output->data); + } + + // public object arrangeModuleInfo($source_module_info) + // grant, extraVar등의 정리 + function arrangeModuleInfo($source_module_info) { + if(!$source_module_info) return; + + // serialize되어 있는 변수들 추출 + $extra_vars = $source_module_info->extra_vars; + $grant = $source_module_info->grant; + //$admin_id = $source_module_info->admin_id; + + unset($source_module_info->extra_vars); + unset($source_module_info->grant); + //unset($source_module_info->admin_id); + + $module_info = clone($source_module_info); + + // extra_vars의 정리 + if($extra_vars) { + $extra_vars = unserialize($extra_vars); + foreach($extra_vars as $key => $val) if(!$module_info->{$key}) $module_info->{$key} = $val; + } + + // 권한의 정리 + if($grant) $module_info->grant = unserialize($grant); + + return $module_info; + }/*}}}*/ + + // public object getModuleObject($module)/*{{{*/ + // module을 찾아서 instance를 생성하여 return + function getModuleObject($module) { + // 요청받은 모듈이 있는지 확인 + $module = strtolower($module); + + // global 변수에 저장한 객체가 있으면 그걸 return + if($GLOBALS['_loaded_module'][$module]) return $GLOBALS['_loaded_module'][$module]; + + $class_path = sprintf('./modules/%s/', $module); + if(!is_dir($class_path)) $class_path = sprintf('./classs/modules/%s/', $module); + if(!is_dir($class_path)) return NULL; + + $class_file = $class_path.$module.'.module.php'; + if(!file_exists($class_file)) return NULL; + + // 새로 객체 생성 + require_once($class_file); + $eval_str = sprintf('$oModule = new %s();', $module); + eval($eval_str); + $oModule->setModulePath($class_path); + $oModule->init(); + + // 언어파일 읽기 + Context::loadLang($class_path.'lang'); + + $GLOBALS['_loaded_module'][$module] = $oModule; + + // 객체 리턴 + return $oModule; + }/*}}}*/ + + // public object getAdminModuleObject($module)/*{{{*/ + // module의 관리자를 찾아서 instance를 생성하여 return + function getAdminModuleObject($module) { + // 요청받은 모듈이 있는지 확인 + $module = strtolower($module); + + // global 변수에 저장한 객체가 있으면 그걸 return + if($GLOBALS['_loaded_admin_module'][$module]) return $GLOBALS['_loaded_admin_module'][$module]; + + $class_path = sprintf('./modules/%s/', $module); + if(!is_dir($class_path)) $class_path = sprintf('./classs/modules/%s/', $module); + if(!is_dir($class_path)) return NULL; + + $class_file = $class_path.$module.'.admin.php'; + if(!file_exists($class_file)) return NULL; + + // 새로 객체 생성 + require_once($class_file); + $eval_str = sprintf('$oModule = new %s_admin();', $module); + eval($eval_str); + $oModule->setModulePath($class_path); + $oModule->init(); + + $template_path = sprintf("%sadmin/", $class_path); + $oModule->setTemplatePath($template_path); + + // 언어파일 읽기 + Context::loadLang($class_path.'lang'); + + // global 변수에 객체 저장 + $GLOBALS['_loaded_admin_module'][$module] = $oModule; + + return $oModule; + }/*}}}*/ + + // public object makeDefaultModule() /*{{{*/ + // 설치시 기본 모듈을 생성 + function makeDefaultModule() { + $oDB = &DB::getInstance(); + + // 설치된 기본 모듈이 있는지 확인 + $output = $oDB->executeQuery('module_manager.getDefaultMidInfo'); + if($output->data) return; + + // 기본 모듈 입력 + $args->mid = 'board'; + $args->browser_title = '테스트 모듈'; + $args->is_default = 'Y'; + $args->module = 'board'; + $args->skin = 'default'; + + $extra_vars->colorset = 'normal'; + $args->extra_vars = serialize($extra_vars); + + return $this->insertModule($args); + }/*}}}*/ + + // public object insertModule($args)/*{{{*/ + // 모듈 입력 + function insertModule($args) { + // 등록하려는 모듈의 path를 구함 + $oModule = getModule($args->module); + + // 선택된 스킨정보에서 colorset을 구함 + $skin_info = $this->loadSkinInfo($oModule->module_path, $args->skin); + $extra_vars->colorset = $skin_info->colorset[0]->name; + + // db에 입력 + $oDB = &DB::getInstance(); + $args->module_srl = $oDB->getNextSequence(); + $args->extra_vars = serialize($extra_vars); + $output = $oDB->executeQuery('module_manager.insertModule', $args); + $output->add('module_srl',$args->module_srl); + return $output; + }/*}}}*/ + + // public object updateModule($args)/*{{{*/ + // 모듈 입력 + function updateModule($args) { + $oDB = &DB::getInstance(); + $output = $oDB->executeQuery('module_manager.updateModule', $args); + $output->add('module_srl',$args->module_srl); + return $output; + }/*}}}*/ + + // public object updateModuleExtraVars($args)/*{{{*/ + // 모듈 입력 + function updateModuleExtraVars($module_srl, $extra_vars) { + $oDB = &DB::getInstance(); + $args->module_srl = $module_srl; + $args->extra_vars = $extra_vars; + $output = $oDB->executeQuery('module_manager.updateModuleExtraVars', $args); + return $output; + }/*}}}*/ + + // public object updateModuleGrant($module_srl, $grant)/*{{{*/ + // 모듈 입력 + function updateModuleGrant($module_srl, $grant) { + $oDB = &DB::getInstance(); + $args->module_srl = $module_srl; + $args->grant = $grant; + $output = $oDB->executeQuery('module_manager.updateModuleGrant', $args); + return $output; + }/*}}}*/ + + // public object deleteModule($module_srl)/*{{{*/ + // 모듈 입력 + function deleteModule($module_srl) { + $oDB = &DB::getInstance(); + $oDocument = getModule('document'); + + // addon 삭제 + // plugin 삭제 + + // document 삭제 + $output = $oDocument->deleteModuleDocument($module_srl); + if(!$output->toBool()) return $output; + + // category 삭제 + $output = $oDocument->deleteModuleCategory($module_srl); + if(!$output->toBool()) return $output; + + // trackbacks 삭제 + $oTrackback = getModule('trackback'); + $output = $oTrackback->deleteModuleTrackbacks($module_srl); + if(!$output->toBool()) return $output; + + // comments 삭제 + $oComment = getModule('comment'); + $output = $oComment->deleteModuleComments($module_srl); + if(!$output->toBool()) return $output; + + // tags 삭제 + $oTag = getModule('tag'); + $output = $oTag->deleteModuleTags($module_srl); + if(!$output->toBool()) return $output; + + // files 삭제 + $output = $oDocument->deleteModuleFiles($module_srl); + if(!$output->toBool()) return $output; + + // module 정보 삭제 + $args->module_srl = $module_srl; + $output = $oDB->executeQuery('module_manager.deleteModule', $args); + + return $output; + }/*}}}*/ + + // public object clearDefaultModule() /*{{{*/ + // 모든 모듈의 is_default='N'로 세팅 + function clearDefaultModule() { + $oDB = &DB::getInstance(); + return $oDB->executeQuery('module_manager.clearDefaultModule'); + }/*}}}*/ + + // public object getAdminModuleList() /*{{{*/ + // 관리자 모듈 목록을 가져옴 + function getAdminModuleList() { + // 다운받은 모듈과 설치된 모듈의 목록을 구함 + $downloaded_list = FileHandler::readDir('./files/modules'); + $installed_list = FileHandler::readDir('./modules'); + + // 찾아진 모듈목록에서 admin은 제외시킴 + $searched_list = array_merge($downloaded_list, $installed_list); + if(!count($searched_list)) return; + + for($i=0;$ititle; + } + if($list) asort($list); + return $list; + }/*}}}*/ + + function loadModuleXml($module_path) {/*{{{*/ + // 현재 선택된 모듈의 스킨의 정보 xml 파일을 읽음 + $xml_file = sprintf("%s/module.xml", $module_path); + if(!file_exists($xml_file)) return; + $oXmlParser = new XmlParser(); + $xml_obj = $oXmlParser->loadXmlFile($xml_file); + + // 스킨 정보를 이용 변수 정리 + if(!$xml_obj) return; + + // 스킨이름 + $info->title = $xml_obj->title->body; + + // 작성자 정보 + $module_info->title = $xml_obj->title->body; + $module_info->version = $xml_obj->attrs->version; + $module_info->author->name = $xml_obj->author->name->body; + $module_info->author->email_address = $xml_obj->author->attrs->email_address; + $module_info->author->homepage = $xml_obj->author->attrs->link; + $module_info->author->date = $xml_obj->author->attrs->date; + $module_info->author->description = $xml_obj->author->description->body; + + // history + if(!is_array($xml_obj->history->author)) $history[] = $xml_obj->history->author; + else $history = $xml_obj->history->author; + foreach($history as $item) { + unset($obj); + $obj->name = $item->name->body; + $obj->email_address = $item->attrs->email_address; + $obj->homepage = $item->attrs->link; + $obj->date = $item->attrs->date; + $obj->description = $item->description->body; + $module_info->history[] = $obj; + } + + return $module_info; + }/*}}}*/ + + function getSkins($module_path) {/*{{{*/ + $skins_path = sprintf("%s/skins/", $module_path); + $list = FileHandler::readDir($skins_path); + return $list; + }/*}}}*/ + + function loadSkinInfo($module_path, $skin) {/*{{{*/ + // 현재 선택된 모듈의 스킨의 정보 xml 파일을 읽음 + $skin_xml_file = sprintf("%sskins/%s/skin.xml", $module_path, $skin); + if(!file_exists($skin_xml_file)) return; + $oXmlParser = new XmlParser(); + $xml_obj = $oXmlParser->loadXmlFile($skin_xml_file); + + // 스킨 정보를 이용 변수 정리 + if(!$xml_obj) return; + + // 스킨이름 + $skin_info->title = $xml_obj->title->body; + + // 작성자 정보 + $skin_info->maker->name = $xml_obj->maker->name->body; + $skin_info->maker->email_address = $xml_obj->maker->attrs->email_address; + $skin_info->maker->homepage = $xml_obj->maker->attrs->link; + $skin_info->maker->date = $xml_obj->maker->attrs->date; + $skin_info->maker->description = $xml_obj->maker->description->body; + + // colorset + if(!is_array($xml_obj->colorset->color)) $colorset[] = $xml_obj->colorset->color; + else $colorset = $xml_obj->colorset->color; + foreach($colorset as $color) { + $name = $color->attrs->name; + $title = $color->title->body; + $screenshot = $color->attrs->src; + if($screenshot && file_exists($screenshot)) $screenshot = sprintf("%sskins/%s/%s",$module_path,$skin,$screenshot); + else $screenshot = ""; + + unset($obj); + $obj->name = $name; + $obj->title = $title; + $obj->screenshot = $screenshot; + $skin_info->colorset[] = $obj; + } + + // 스킨에서 사용되는 변수들 + if(!is_array($xml_obj->extra_vars->var)) $extra_vars[] = $xml_obj->extra_vars->var; + else $extra_vars = $xml_obj->extra_vars->var; + foreach($extra_vars as $var) { + $name = $var->attrs->name; + $type = $var->attrs->type; + $title = $var->title->body; + $description = $var->description->body; + if($var->default) { + unset($default); + if(is_array($var->default)) { + for($i=0;$idefault);$i++) $default[] = $var->default[$i]->body; + } else { + $default = $var->default->body; + } + } + $width = $var->attrs->width; + $height = $var->attrs->height; + + unset($obj); + $obj->title = $title; + $obj->description = $description; + $obj->name = $name; + $obj->type = $type; + $obj->default = $default; + $obj->width = $width; + $obj->height = $height; + + $skin_info->extra_vars[] = $obj; + } + + return $skin_info; + }/*}}}*/ + } +?> diff --git a/modules/module_manager/queries/clearDefaultModule.xml b/modules/module_manager/queries/clearDefaultModule.xml new file mode 100644 index 000000000..8b5716716 --- /dev/null +++ b/modules/module_manager/queries/clearDefaultModule.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/modules/module_manager/queries/deleteModule.xml b/modules/module_manager/queries/deleteModule.xml new file mode 100644 index 000000000..3967fc73d --- /dev/null +++ b/modules/module_manager/queries/deleteModule.xml @@ -0,0 +1,8 @@ + + +
+ + + + + diff --git a/modules/module_manager/queries/getDefaultMidInfo.xml b/modules/module_manager/queries/getDefaultMidInfo.xml new file mode 100644 index 000000000..cd8391044 --- /dev/null +++ b/modules/module_manager/queries/getDefaultMidInfo.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/module_manager/queries/getMidInfo.xml b/modules/module_manager/queries/getMidInfo.xml new file mode 100644 index 000000000..f50ddb7e7 --- /dev/null +++ b/modules/module_manager/queries/getMidInfo.xml @@ -0,0 +1,12 @@ + + +
+ + + + + + + + + diff --git a/modules/module_manager/queries/getModuleInfoByDocument.xml b/modules/module_manager/queries/getModuleInfoByDocument.xml new file mode 100644 index 000000000..41a934136 --- /dev/null +++ b/modules/module_manager/queries/getModuleInfoByDocument.xml @@ -0,0 +1,24 @@ + + +
+
+ + + + + + + + + + + + + + + + + + + + diff --git a/modules/module_manager/queries/insertModule.xml b/modules/module_manager/queries/insertModule.xml new file mode 100644 index 000000000..70a3cc165 --- /dev/null +++ b/modules/module_manager/queries/insertModule.xml @@ -0,0 +1,22 @@ + + +
+ + + + + + + + + + + + + + + + + + + diff --git a/modules/module_manager/queries/updateModule.xml b/modules/module_manager/queries/updateModule.xml new file mode 100644 index 000000000..736caff11 --- /dev/null +++ b/modules/module_manager/queries/updateModule.xml @@ -0,0 +1,23 @@ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/modules/module_manager/queries/updateModuleExtraVars.xml b/modules/module_manager/queries/updateModuleExtraVars.xml new file mode 100644 index 000000000..8b6f15f0f --- /dev/null +++ b/modules/module_manager/queries/updateModuleExtraVars.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/module_manager/queries/updateModuleGrant.xml b/modules/module_manager/queries/updateModuleGrant.xml new file mode 100644 index 000000000..fccdc44e0 --- /dev/null +++ b/modules/module_manager/queries/updateModuleGrant.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/module_manager/schemas/module_addon.xml b/modules/module_manager/schemas/module_addon.xml new file mode 100644 index 000000000..d3ba78007 --- /dev/null +++ b/modules/module_manager/schemas/module_addon.xml @@ -0,0 +1,9 @@ +
+ + + + + + + +
diff --git a/modules/module_manager/schemas/module_plugin.xml b/modules/module_manager/schemas/module_plugin.xml new file mode 100644 index 000000000..67b381f32 --- /dev/null +++ b/modules/module_manager/schemas/module_plugin.xml @@ -0,0 +1,7 @@ + + + + + + +
diff --git a/modules/module_manager/schemas/modules.xml b/modules/module_manager/schemas/modules.xml new file mode 100644 index 000000000..4f633a1d0 --- /dev/null +++ b/modules/module_manager/schemas/modules.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + +
diff --git a/modules/rss/module.xml b/modules/rss/module.xml new file mode 100644 index 000000000..1f24f238e --- /dev/null +++ b/modules/rss/module.xml @@ -0,0 +1,11 @@ + + + RSS + RSS + + 제로 + zero + RSS 관리 모듈 + rss management + + diff --git a/modules/rss/rss.module.php b/modules/rss/rss.module.php new file mode 100644 index 000000000..747c6082c --- /dev/null +++ b/modules/rss/rss.module.php @@ -0,0 +1,111 @@ + + * @desc : 기본 모듈중의 하나인 rss module + * RSS 2.0형식으로 문서 출력 + **/ + + class rss extends Module { + + /** + * 모듈의 정보 + **/ + var $cur_version = "20070130_0.01"; + + /** + * 기본 action 지정 + * $act값이 없거나 잘못된 값이 들어올 경우 $default_act 값으로 진행 + **/ + var $default_act = ''; + + /** + * 현재 모듈의 초기화를 위한 작업을 지정해 놓은 method + * css/js파일의 load라든지 lang파일 load등을 미리 선언 + * + * Init() => 공통 + * dispInit() => disp시에 + * procInit() => proc시에 + * + * $this->module_path는 현재 이 모듈파일의 위치를 나타낸다 + * (ex: $this->module_path = "./modules/system_install/"; + **/ + + // 초기화 + function init() {/*{{{*/ + }/*}}}*/ + + // disp 초기화 + function dispInit() {/*{{{*/ + }/*}}}*/ + + // proc 초기화 + function procInit() {/*{{{*/ + }/*}}}*/ + + /** + * 여기서부터는 action의 구현 + * request parameter의 경우 각 method의 첫번째 인자로 넘어온다 + * + * dispXXXX : 출력을 위한 method, output에 tpl file이 지정되어야 한다 + * procXXXX : 처리를 위한 method, output에는 error, message가 지정되어야 한다 + **/ + + // 출력 부분 + + // 실행 부분 + + /** + * 여기부터는 이 모듈과 관련된 라이브러리 개념의 method들 + **/ + function printRssDocument($info, $content) { /*{{{*/ + header("Content-Type: text/xml; charset=UTF-8"); + header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); + header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); + header("Cache-Control: no-store, no-cache, must-revalidate"); + header("Cache-Control: post-check=0, pre-check=0", false); + header("Pragma: no-cache"); + print ''."\n"; + print "\n"; +?> + + <![CDATA[<?=$info->title?>]]> + link?>]]> + description?>]]> + language?> + date?> +regdate,0,4); + $month = substr($item->regdate,4,2); + $day = substr($item->regdate,6,2); + $hour = substr($item->regdate,8,2); + $min = substr($item->regdate,10,2); + $sec = substr($item->regdate,12,2); + $time = mktime($hour,$min,$sec,$month,$day,$year); + + $title = $item->title; + $author = $item->user_name; + $link = sprintf("%s?document_srl=%d", Context::getRequestUri(), $item->document_srl); + $description = $item->content; + $date = gmdate("D, d M Y H:i:s", $time); +?> + + <![CDATA[<?=$title?>]]> + ]]> + ]]> + ]]> + + + + + + diff --git a/modules/tag/module.xml b/modules/tag/module.xml new file mode 100644 index 000000000..d20d63c46 --- /dev/null +++ b/modules/tag/module.xml @@ -0,0 +1,11 @@ + + + 꼬리표 + tag + + 제로 + zero + 꼬리표 관리 모듈 + tag + + diff --git a/modules/tag/queries/deleteModuleTags.xml b/modules/tag/queries/deleteModuleTags.xml new file mode 100644 index 000000000..cf5a19887 --- /dev/null +++ b/modules/tag/queries/deleteModuleTags.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/modules/tag/queries/deleteTag.xml b/modules/tag/queries/deleteTag.xml new file mode 100644 index 000000000..ee9b981dc --- /dev/null +++ b/modules/tag/queries/deleteTag.xml @@ -0,0 +1,8 @@ + + +
+ + + + + diff --git a/modules/tag/queries/insertTag.xml b/modules/tag/queries/insertTag.xml new file mode 100644 index 000000000..c6155e886 --- /dev/null +++ b/modules/tag/queries/insertTag.xml @@ -0,0 +1,12 @@ + + +
+ + + + + + + + + diff --git a/modules/tag/schemas/tags.xml b/modules/tag/schemas/tags.xml new file mode 100644 index 000000000..1d3613ef6 --- /dev/null +++ b/modules/tag/schemas/tags.xml @@ -0,0 +1,7 @@ +
+ + + + + +
diff --git a/modules/tag/tag.module.php b/modules/tag/tag.module.php new file mode 100644 index 000000000..58e362711 --- /dev/null +++ b/modules/tag/tag.module.php @@ -0,0 +1,110 @@ + + * @desc : 기본 모듈중의 하나인 tag module + * Module class에서 상속을 받아서 사용 + * action 의 경우 disp/proc 2가지만 존재하며 이는 action명세서에 + * 미리 기록을 하여야 함 + **/ + + class tag extends Module { + + /** + * 모듈의 정보 + **/ + var $cur_version = "20070130_0.01"; + + /** + * 기본 action 지정 + * $act값이 없거나 잘못된 값이 들어올 경우 $default_act 값으로 진행 + **/ + var $default_act = ''; + + /** + * 현재 모듈의 초기화를 위한 작업을 지정해 놓은 method + * css/js파일의 load라든지 lang파일 load등을 미리 선언 + * + * Init() => 공통 + * dispInit() => disp시에 + * procInit() => proc시에 + * + * $this->module_path는 현재 이 모듈파일의 위치를 나타낸다 + * (ex: $this->module_path = "./modules/install/"; + **/ + + // 초기화 + function init() {/*{{{*/ + }/*}}}*/ + + // disp 초기화 + function dispInit() {/*{{{*/ + }/*}}}*/ + + // proc 초기화 + function procInit() {/*{{{*/ + }/*}}}*/ + + /** + * 여기서부터는 action의 구현 + * request parameter의 경우 각 method의 첫번째 인자로 넘어온다 + * + * dispXXXX : 출력을 위한 method, output에 tpl file이 지정되어야 한다 + * procXXXX : 처리를 위한 method, output에는 tag, tag가 지정되어야 한다 + **/ + + /** + * 여기부터는 이 모듈과 관련된 라이브러리 개념의 method들 + **/ + + // public string insertTag($module_srl, $document_srl, $tags)/*{{{*/ + // 태그 입력 + function insertTag($module_srl, $document_srl, $tags) { + + // 해당 글의 tags를 모두 삭제 + $this->deleteTag($document_srl); + + if(!$tags) return; + + // tags변수 정리 + $tmp_tag_list = explode(',', $tags); + $tag_count = count($tmp_tag_list); + for($i=0;$i<$tag_count;$i++) { + $tag = trim($tmp_tag_list[$i]); + if(!$tag) continue; + $tag_list[] = $tag; + } + if(!count($tag_list)) return; + + // 다시 태그를 입력 + $oDB = &DB::getInstance(); + + $args->module_srl = $module_srl; + $args->document_srl = $document_srl; + $tag_count = count($tag_list); + for($i=0;$i<$tag_count;$i++) { + $args->tag = $tag_list[$i]; + $oDB->executeQuery('tag.insertTag', $args); + } + + return implode(',',$tag_list); + }/*}}}*/ + + // public boolean deleteTag($document_srl)/*{{{*/ + // 특정 문서의 태그 삭제 + function deleteTag($document_srl) { + $oDB = &DB::getInstance(); + $args->document_srl = $document_srl; + return $oDB->executeQuery('tag.deleteTag', $args); + }/*}}}*/ + + // public boolean deleteModuleTags($module_sr)/*{{{*/ + // 특정 모듈의 태그 삭제 + function deleteModuleTags($module_srl) { + // 삭제 + $oDB = &DB::getInstance(); + $args->module_srl = $module_srl; + return $oDB->executeQuery('tag.deleteModuleTags', $args); + }/*}}}*/ + } +?> diff --git a/modules/trackback/module.xml b/modules/trackback/module.xml new file mode 100644 index 000000000..53940899d --- /dev/null +++ b/modules/trackback/module.xml @@ -0,0 +1,19 @@ + + + 엮인글 + Trackback + + 제로 + zero + 엮인글 관리 모듈 + module of trackback management + + + + 제로 + zero + 엮인글 관리 모듈 + module of trackback management + + + diff --git a/modules/trackback/queries/deleteModuleTrackbacks.xml b/modules/trackback/queries/deleteModuleTrackbacks.xml new file mode 100644 index 000000000..4ca806765 --- /dev/null +++ b/modules/trackback/queries/deleteModuleTrackbacks.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/modules/trackback/queries/deleteTrackback.xml b/modules/trackback/queries/deleteTrackback.xml new file mode 100644 index 000000000..249ec3056 --- /dev/null +++ b/modules/trackback/queries/deleteTrackback.xml @@ -0,0 +1,8 @@ + + +
+ + + + + diff --git a/modules/trackback/queries/deleteTrackbacks.xml b/modules/trackback/queries/deleteTrackbacks.xml new file mode 100644 index 000000000..7f254d978 --- /dev/null +++ b/modules/trackback/queries/deleteTrackbacks.xml @@ -0,0 +1,8 @@ + + +
+ + + + + diff --git a/modules/trackback/queries/getTrackback.xml b/modules/trackback/queries/getTrackback.xml new file mode 100644 index 000000000..d70f3b223 --- /dev/null +++ b/modules/trackback/queries/getTrackback.xml @@ -0,0 +1,8 @@ + + +
+ + + + + diff --git a/modules/trackback/queries/getTrackbackCount.xml b/modules/trackback/queries/getTrackbackCount.xml new file mode 100644 index 000000000..28771c696 --- /dev/null +++ b/modules/trackback/queries/getTrackbackCount.xml @@ -0,0 +1,11 @@ + + +
+ + + + + + + + diff --git a/modules/trackback/queries/getTrackbackList.xml b/modules/trackback/queries/getTrackbackList.xml new file mode 100644 index 000000000..90ca1705d --- /dev/null +++ b/modules/trackback/queries/getTrackbackList.xml @@ -0,0 +1,14 @@ + + +
+ + + + + + + + + + + diff --git a/modules/trackback/queries/insertTrackback.xml b/modules/trackback/queries/insertTrackback.xml new file mode 100644 index 000000000..ca96d8531 --- /dev/null +++ b/modules/trackback/queries/insertTrackback.xml @@ -0,0 +1,17 @@ + + +
+ + + + + + + + + + + + + + diff --git a/modules/trackback/schemas/trackbacks.xml b/modules/trackback/schemas/trackbacks.xml new file mode 100644 index 000000000..03462beec --- /dev/null +++ b/modules/trackback/schemas/trackbacks.xml @@ -0,0 +1,12 @@ +
+ + + + + + + + + + +
diff --git a/modules/trackback/trackback.module.php b/modules/trackback/trackback.module.php new file mode 100644 index 000000000..1c3959961 --- /dev/null +++ b/modules/trackback/trackback.module.php @@ -0,0 +1,251 @@ + + * @desc : 기본 모듈중의 하나인 trackback module + * Module class에서 상속을 받아서 사용 + * action 의 경우 disp/proc 2가지만 존재하며 이는 action명세서에 + * 미리 기록을 하여야 함 + **/ + + class trackback extends Module { + + /** + * 모듈의 정보 + **/ + var $cur_version = "20070130_0.01"; + + /** + * 기본 action 지정 + * $act값이 없거나 잘못된 값이 들어올 경우 $default_act 값으로 진행 + **/ + var $default_act = ''; + + /** + * 현재 모듈의 초기화를 위한 작업을 지정해 놓은 method + * css/js파일의 load라든지 lang파일 load등을 미리 선언 + * + * Init() => 공통 + * dispInit() => disp시에 + * procInit() => proc시에 + * + * $this->module_path는 현재 이 모듈파일의 위치를 나타낸다 + * (ex: $this->module_path = "./modules/install/"; + **/ + + // 초기화 + function init() {/*{{{*/ + }/*}}}*/ + + // disp 초기화 + function dispInit() {/*{{{*/ + }/*}}}*/ + + // proc 초기화 + function procInit() {/*{{{*/ + }/*}}}*/ + + /** + * 여기서부터는 action의 구현 + * request parameter의 경우 각 method의 첫번째 인자로 넘어온다 + * + * dispXXXX : 출력을 위한 method, output에 tpl file이 지정되어야 한다 + * procXXXX : 처리를 위한 method, output에는 trackback, trackback가 지정되어야 한다 + **/ + + /** + * 여기부터는 이 모듈과 관련된 라이브러리 개념의 method들 + **/ + + // public boolean insertTrackback($obj)/*{{{*/ + // 엮인글 입력 + function insertTrackback($obj) { + // document_srl에 해당하는 글이 있는지 확인 + $document_srl = $obj->document_srl; + if(!$document_srl) $this->dispMessage(-1, 'fail'); + + $oDocument = getModule('document'); + $document = $oDocument->getDocument($document_srl); + + if(!$document_srl) $this->dispMessage(-1,'fail'); + if($document->allow_trackback=='N') $this->dispMessage(-1,'fail'); + + // 엮인글 정리 + $obj = Context::convertEncoding($obj); + if(!$obj->blog_name) $obj->blog_name = $obj->title; + $obj->excerpt = strip_tags($obj->excerpt); + + // 엮인글를 입력 + $oDB = &DB::getInstance(); + $obj->list_order = $obj->trackback_srl = $oDB->getNextSequence(); + $obj->module_srl = $document->module_srl; + $output = $oDB->executeQuery('trackback.insertTrackback', $obj); + + // 입력에 이상이 없으면 해당 글의 엮인글 수를 올림 + if(!$output->toBool()) $this->dispMessage(-1, 'fail'); + + // 해당 글의 전체 엮인글 수를 구해옴 + $trackback_count = $this->getTrackbackCount($document_srl); + + // 해당글의 엮인글 수를 업데이트 + $output = $oDocument->updateTrackbackCount($document_srl, $trackback_count); + + if(!$output->toBool()) $this->dispMessage(-1,'fail'); + else $this->dispMessage(0,'success'); + }/*}}}*/ + + function dispMessage($error, $message) {/*{{{*/ + // 헤더 출력 + header("Content-Type: text/xml; charset=UTF-8"); + header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); + header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); + header("Cache-Control: no-store, no-cache, must-revalidate"); + header("Cache-Control: post-check=0, pre-check=0", false); + header("Pragma: no-cache"); + print ''."\n"; + print "\n{$error}{$message}"; + exit(); + }/*}}}*/ + + // public boolean getTrackback($trackback_srl)/*{{{*/ + // 엮인글 삭제 + function getTrackback($trackback_srl) { + $oDB = &DB::getInstance(); + $args->trackback_srl = $trackback_srl; + return $oDB->executeQuery('trackback.getTrackback', $args); + }/*}}}*/ + + // public boolean deleteTrackback($trackback_srl)/*{{{*/ + // 엮인글 삭제 + function deleteTrackback($trackback_srl) { + // 삭제하려는 엮인글이 있는지 확인 + $trackback = $this->getTrackback($trackback_srl); + if($trackback->data->trackback_srl != $trackback_srl) return new Output(-1, 'msg_invalid_request'); + $document_srl = $trackback->data->document_srl; + + // 권한이 있는지 확인 + $oDocument = getModule('document'); + if(!$oDocument->isGranted($document_srl)) return new Output(-1, 'msg_not_permitted'); + + // 삭제 + $oDB = &DB::getInstance(); + $args->trackback_srl = $trackback_srl; + $output = $oDB->executeQuery('trackback.deleteTrackback', $args); + if(!$output->toBool()) return new Output(-1, 'msg_error_occured'); + + // 엮인글 수를 구해서 업데이트 + $trackback_count = $this->getTrackbackCount($document_srl); + + // 해당글의 엮인글 수를 업데이트 + $oDocument = getModule('document'); + $output = $oDocument->updateTrackbackCount($document_srl, $trackback_count); + $output->add('document_srl', $document_srl); + return $output; + }/*}}}*/ + + // public boolean deleteTrackbacks($document_srl)/*{{{*/ + // 엮인글 삭제 + function deleteTrackbacks($document_srl) { + // 삭제 + $oDB = &DB::getInstance(); + $args->document_srl = $document_srl; + $output = $oDB->executeQuery('trackback.deleteTrackbacks', $args); + return $output; + }/*}}}*/ + + // public boolean deleteModuleTrackbacks($module_srl)/*{{{*/ + // 엮인글 삭제 + function deleteModuleTrackbacks($module_srl) { + // 삭제 + $oDB = &DB::getInstance(); + $args->module_srl = $module_srl; + $output = $oDB->executeQuery('trackback.deleteModuleTrackbacks', $args); + return $output; + }/*}}}*/ + + // public number getTrackbackCount($module_srl, $search_obj = NULL)/*{{{*/ + // document_srl 에 해당하는 엮인글의 전체 갯수를 가져옴 + function getTrackbackCount($document_srl) { + $oDB = &DB::getInstance(); + $args->document_srl = $document_srl; + $output = $oDB->executeQuery('trackback.getTrackbackCount', $args); + $total_count = $output->data->count; + return (int)$total_count; + }/*}}}*/ + + // public boolean getTrackbackList($document_srl)/*{{{*/ + // module_srl값을 가지는 엮인글의 목록을 가져옴 + function getTrackbackList($document_srl) { + // 엮인글 목록을 가져옴 + $oDB = &DB::getInstance(); + $args->document_srl = $document_srl; + $args->list_order = 'list_order'; + $output = $oDB->executeQuery('trackback.getTrackbackList', $args); + if(!$output->toBool()) return $output; + $trackback_list = $output->data; + if(!is_array($trackback_list)) $trackback_list = array($trackback_list); + return $trackback_list; + }/*}}}*/ + + // public boolean sendTrackback($document)/*{{{*/ + // 엮인글을 발송 + function sendTrackback($document, $trackback_url, $charset) { + // 발송할 정보를 정리 + $http = parse_url($trackback_url); + $obj->blog_name = Context::getBrowserTitle(); + $obj->title = $document->title; + $obj->excerpt = cut_str($document->content, 240); + $obj->url = sprintf("%s?document_srl=%d", Context::getRequestUri(), $document->document_srl); + + if($charset && function_exists('iconv')) { + foreach($obj as $key=>$val) { + $obj->{$key} = iconv('UTF-8',$charset,$val); + } + } + + if($http['query']) $http['query'].="&"; + if(!$http['port']) $http['port'] = 80; + $content = + sprintf( + "title=%s&". + "url=%s&". + "blog_name=%s&". + "excerpt=%s", + urlencode($obj->title), + urlencode($obj->url), + urlencode($obj->blog_name), + urlencode($obj->excerpt) + ); + if($http['query']) $content .= '&'.$http['query']; + + $content_length = strlen($content); + + $header = + sprintf( + "POST %s HTTP/1.1\r\n". + "Host: %s\r\n". + "Content-Type: %s\r\n". + "Content-Length: %s\r\n\r\n". + "%s\r\n", + $http['path'], + $http['host'], + "application/x-www-form-urlencoded", + $content_length, + $content + ); + if(!$http['host']||!$http['port']) return; + + $fp = @fsockopen($http['host'], $http['port'], $errno, $errstr, 5); + if(!$fp) return; + + fputs($fp, $header); + + while(!feof($fp)) { + $line = trim(fgets($fp, 4096)); + if(eregi("^",$line)) break; + } + + fclose($fp); + }/*}}}*/ + } +?> diff --git a/rss.php b/rss.php new file mode 100644 index 000000000..8fd024876 --- /dev/null +++ b/rss.php @@ -0,0 +1,22 @@ + + * @desc : rss를 출력하기 위한 파일. index.php와 거의 동일하나 act를 dispRss 로 고정시키는 것만 다름 + **/ + + // 필요한 설정 파일들을 include + require_once("./config/config.inc.php"); + + // Request Method와 설정값들을 세팅 + $oContext = &Context::getInstance(); + $oContext->init(); + + // act값을 dispRss로 강제 설정 + // 각 모듈마다 dispRss가 필수적으로 있어야 함 + Context::set('act', 'dispRss'); + + // ModuleHandler 호출하여 content 출력 + $oModuleHandler = new ModuleHandler(); + $oModule = $oModuleHandler->proc(); +?> diff --git a/trackback.php b/trackback.php new file mode 100644 index 000000000..e0043a26b --- /dev/null +++ b/trackback.php @@ -0,0 +1,22 @@ + + * @desc : 트랙백을 받기 위한 파일. 파일이름때문에.. index.php와 거의 동일하나 act를 procReceiveTrackback로 고정 + **/ + + // 필요한 설정 파일들을 include + require_once("./config/config.inc.php"); + + // Request Method와 설정값들을 세팅 + $oContext = &Context::getInstance(); + $oContext->init(); + + // act값을 procReceiveTrackback로 강제 설정 + // 각 모듈마다 procReceiveTrackback가 필수적으로 있어야 함 + Context::set('act', 'procReceiveTrackback'); + + // ModuleHandler 호출하여 content 출력 + $oModuleHandler = new ModuleHandler(); + $oModule = $oModuleHandler->proc(); +?>