diff --git a/addons/blogapi/blogapi.addon.php b/addons/blogapi/blogapi.addon.php index e6a079f9e..11c4fc7b2 100644 --- a/addons/blogapi/blogapi.addon.php +++ b/addons/blogapi/blogapi.addon.php @@ -13,7 +13,8 @@ // called_position가 after_module_proc일때 rsd 태그 삽입 if($called_position == 'after_module_proc') { // 현재 모듈의 rsd주소를 만듬 - $rsd_url = sprintf('%s%s/api', Context::getRequestUri(), $this->mid); + $site_module_info = Context::get('site_module_info'); + $rsd_url = getFullSiteUrl($site_module_info->domain, '', 'mid',$site_module_info->mid, 'act','api'); // 헤더에 rsd태그 삽입 Context::addHtmlHeader(" ".''); @@ -34,6 +35,11 @@ $params = $xmlDoc->methodcall->params->param; if($params && !is_array($params)) $params = array($params); + // 일부 methodname에 대한 호환 + if(in_array($method_name, array('metaWeblog.deletePost', 'metaWeblog.getUsersBlogs', 'metaWeblog.getUserInfo'))) { + $method_name = str_replace('metaWeblog.', 'blogger.', $method_name); + } + // blogger.deletePost일 경우 첫번째 인자 값 삭제 if($method_name == 'blogger.deletePost') array_shift($params); @@ -440,7 +446,8 @@ default : $homepagelink = getUrl('','mid',$this->mid); - $api_url = sprintf('%s%s/api', Context::getRequestUri(), $this->mid); + $site_module_info = Context::get('site_module_info'); + $api_url = getFullSiteUrl($site_module_info->domain, '', 'mid',$site_module_info->mid, 'act','api'); $content = << diff --git a/addons/captcha/audio/F_A.mp3 b/addons/captcha/audio/F_A.mp3 new file mode 100755 index 000000000..90aa7c382 Binary files /dev/null and b/addons/captcha/audio/F_A.mp3 differ diff --git a/addons/captcha/audio/F_B.mp3 b/addons/captcha/audio/F_B.mp3 new file mode 100755 index 000000000..af2fa091e Binary files /dev/null and b/addons/captcha/audio/F_B.mp3 differ diff --git a/addons/captcha/audio/F_C.mp3 b/addons/captcha/audio/F_C.mp3 new file mode 100755 index 000000000..83566b97b Binary files /dev/null and b/addons/captcha/audio/F_C.mp3 differ diff --git a/addons/captcha/audio/F_D.mp3 b/addons/captcha/audio/F_D.mp3 new file mode 100755 index 000000000..ee685b080 Binary files /dev/null and b/addons/captcha/audio/F_D.mp3 differ diff --git a/addons/captcha/audio/F_E.mp3 b/addons/captcha/audio/F_E.mp3 new file mode 100755 index 000000000..353583ce9 Binary files /dev/null and b/addons/captcha/audio/F_E.mp3 differ diff --git a/addons/captcha/audio/F_F.mp3 b/addons/captcha/audio/F_F.mp3 new file mode 100755 index 000000000..62810c6f7 Binary files /dev/null and b/addons/captcha/audio/F_F.mp3 differ diff --git a/addons/captcha/audio/F_G.mp3 b/addons/captcha/audio/F_G.mp3 new file mode 100755 index 000000000..d52639161 Binary files /dev/null and b/addons/captcha/audio/F_G.mp3 differ diff --git a/addons/captcha/audio/F_H.mp3 b/addons/captcha/audio/F_H.mp3 new file mode 100755 index 000000000..de0b0bace Binary files /dev/null and b/addons/captcha/audio/F_H.mp3 differ diff --git a/addons/captcha/audio/F_I.mp3 b/addons/captcha/audio/F_I.mp3 new file mode 100755 index 000000000..50d09f19c Binary files /dev/null and b/addons/captcha/audio/F_I.mp3 differ diff --git a/addons/captcha/audio/F_J.mp3 b/addons/captcha/audio/F_J.mp3 new file mode 100755 index 000000000..647380efd Binary files /dev/null and b/addons/captcha/audio/F_J.mp3 differ diff --git a/addons/captcha/audio/F_K.mp3 b/addons/captcha/audio/F_K.mp3 new file mode 100755 index 000000000..c03d39feb Binary files /dev/null and b/addons/captcha/audio/F_K.mp3 differ diff --git a/addons/captcha/audio/F_L.mp3 b/addons/captcha/audio/F_L.mp3 new file mode 100755 index 000000000..d118a5cfe Binary files /dev/null and b/addons/captcha/audio/F_L.mp3 differ diff --git a/addons/captcha/audio/F_M.mp3 b/addons/captcha/audio/F_M.mp3 new file mode 100755 index 000000000..a253ebddf Binary files /dev/null and b/addons/captcha/audio/F_M.mp3 differ diff --git a/addons/captcha/audio/F_N.mp3 b/addons/captcha/audio/F_N.mp3 new file mode 100755 index 000000000..6a612b6c6 Binary files /dev/null and b/addons/captcha/audio/F_N.mp3 differ diff --git a/addons/captcha/audio/F_O.mp3 b/addons/captcha/audio/F_O.mp3 new file mode 100755 index 000000000..ceb35dac4 Binary files /dev/null and b/addons/captcha/audio/F_O.mp3 differ diff --git a/addons/captcha/audio/F_P.mp3 b/addons/captcha/audio/F_P.mp3 new file mode 100755 index 000000000..cbe13027b Binary files /dev/null and b/addons/captcha/audio/F_P.mp3 differ diff --git a/addons/captcha/audio/F_Q.mp3 b/addons/captcha/audio/F_Q.mp3 new file mode 100755 index 000000000..8fab925bf Binary files /dev/null and b/addons/captcha/audio/F_Q.mp3 differ diff --git a/addons/captcha/audio/F_R.mp3 b/addons/captcha/audio/F_R.mp3 new file mode 100755 index 000000000..af4bc5dcf Binary files /dev/null and b/addons/captcha/audio/F_R.mp3 differ diff --git a/addons/captcha/audio/F_S.mp3 b/addons/captcha/audio/F_S.mp3 new file mode 100755 index 000000000..42d30c5f6 Binary files /dev/null and b/addons/captcha/audio/F_S.mp3 differ diff --git a/addons/captcha/audio/F_T.mp3 b/addons/captcha/audio/F_T.mp3 new file mode 100755 index 000000000..47ea6e664 Binary files /dev/null and b/addons/captcha/audio/F_T.mp3 differ diff --git a/addons/captcha/audio/F_U.mp3 b/addons/captcha/audio/F_U.mp3 new file mode 100755 index 000000000..ba39f155e Binary files /dev/null and b/addons/captcha/audio/F_U.mp3 differ diff --git a/addons/captcha/audio/F_V.mp3 b/addons/captcha/audio/F_V.mp3 new file mode 100755 index 000000000..b8e8686e7 Binary files /dev/null and b/addons/captcha/audio/F_V.mp3 differ diff --git a/addons/captcha/audio/F_W.mp3 b/addons/captcha/audio/F_W.mp3 new file mode 100755 index 000000000..00cc2afe1 Binary files /dev/null and b/addons/captcha/audio/F_W.mp3 differ diff --git a/addons/captcha/audio/F_X.mp3 b/addons/captcha/audio/F_X.mp3 new file mode 100755 index 000000000..b3bb0c1d7 Binary files /dev/null and b/addons/captcha/audio/F_X.mp3 differ diff --git a/addons/captcha/audio/F_Y.mp3 b/addons/captcha/audio/F_Y.mp3 new file mode 100755 index 000000000..1d9c35537 Binary files /dev/null and b/addons/captcha/audio/F_Y.mp3 differ diff --git a/addons/captcha/captcha.addon.php b/addons/captcha/captcha.addon.php index b51a2eae5..a07cd69ac 100644 --- a/addons/captcha/captcha.addon.php +++ b/addons/captcha/captcha.addon.php @@ -3,41 +3,68 @@ /** * @file captcha.addon.php - * @author zero (zero@nzeo.com) - * @brief 특정 action을 실행할때 captcah를 띄우도록 함 + * @author zero (zero@nzeo.com), sol(ngleader@gmail.com) + * @brief 특정 action을 실행할때 captcha를 띄우도록 함 + * 영어 알파벳을 입력, 음성기능 추가 **/ - // before_module_proc 일 경우 && act_type != everytime 이면 세션 초기화 - if($called_position == "before_module_proc" && $addon_info->act_type == 'everytime' && $_SESSION['captcha_authed']) { - unset($_SESSION['captcha_authed']); + if(!class_exists('AddonCaptcha')) + { + class AddonCaptcha + { + var $addon_info; - // before_module_init 일때에 captcha 동작 - } else if($called_position == 'before_module_init') { + function setInfo(&$addon_info) + { + $this->addon_info = $addon_info; + } - $logged_info = Context::get('logged_info'); - if($logged_info->is_admin == 'Y' || $logged_info->is_site_admin) return; - if($addon_info->target != 'all' && Context::get('is_logged')) return; + function before_module_proc() + { + if($this->addon_info->act_type == 'everytime' && $_SESSION['captcha_authed']) { + unset($_SESSION['captcha_authed']); + } + } - $target_acts = array('procBoardInsertDocument','procBoardInsertComment','procIssuetrackerInsertIssue','procIssuetrackerInsertHistory','procTextyleInsertComment'); - if($addon_info->apply_find_account=='apply') $target_acts[] = 'procMemberFindAccount'; - if($addon_info->apply_resend_auth_mail=='apply') $target_acts[] = 'procMemberResendAuthMail'; - if($addon_info->apply_signup=='apply') $target_acts[] = 'procMemberInsert'; + function before_module_init(&$ModuleHandler) + { + $logged_info = Context::get('logged_info'); + if($logged_info->is_admin == 'Y' || $logged_info->is_site_admin) return false; + if($this->addon_info->target != 'all' && Context::get('is_logged')) return false; - Context::addHtmlHeader(''); + $target_acts = array('procBoardInsertDocument','procBoardInsertComment','procIssuetrackerInsertIssue','procIssuetrackerInsertHistory','procTextyleInsertComment'); + if($this->addon_info->apply_find_account=='apply') $target_acts[] = 'procMemberFindAccount'; + if($this->addon_info->apply_resend_auth_mail=='apply') $target_acts[] = 'procMemberResendAuthMail'; + if($this->addon_info->apply_signup=='apply') $target_acts[] = 'procMemberInsert'; - // 캡챠 인증이 되지 않은 세션이면 실행 시작 - if(!$_SESSION['captcha_authed']) { + if(Context::getRequestMethod()!='XMLRPC' && Context::getRequestMethod()!=='JSON') + { + Context::addHtmlHeader(''); + Context::addJsFile('./addons/captcha/captcha.js',false); + } - // 언어파일 로드 - Context::loadLang(_XE_PATH_.'addons/captcha/lang'); + // 게시판/ 이슈트래커의 글쓰기/댓글쓰기 액션 호출시 세션 비교 + if(!$_SESSION['captcha_authed'] && in_array(Context::get('act'), $target_acts)) { + Context::loadLang('./addons/captcha/lang'); + $ModuleHandler->error = "captcha_denied"; + } + + return true; + } + + function before_module_init_setCaptchaSession() + { + if($_SESSION['captcha_authed']) return false; + + // 언어파일 로드 + Context::loadLang(_XE_PATH_.'addons/captcha/lang'); + + // 키워드 생성 + $arr = range('A','Y'); + shuffle($arr); + $arr = array_slice($arr,0,6); + $_SESSION['captcha_keyword'] = join('', $arr); - // 캡챠 세션 세팅 - if(Context::get('captcha_action')=='setCaptchaSession') { - $f = FileHandler::readDir('./addons/captcha/icon'); - shuffle($f); - $key = rand(0,count($f)-1); - $keyword = str_replace('.gif','',$f[$key]); - $_SESSION['captcha_keyword'] = $keyword; $target = Context::getLang('target_captcha'); header("Content-Type: text/xml; charset=UTF-8"); header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); @@ -45,50 +72,161 @@ header("Cache-Control: no-store, no-cache, must-revalidate"); header("Cache-Control: post-check=0, pre-check=0", false); header("Pragma: no-cache"); - printf("\r\n0\r\nsuccess\r\n\r\n\r\n",Context::getLang('about_captcha'),$target[$keyword]); + printf("\r\n 0\r\n success\r\n \r\n \r\n \r\n \r\n \r\n " + ,Context::getLang('about_captcha') + ,Context::getLang('captcha_reload') + ,Context::getLang('captcha_play') + ,Context::getLang('cmd_input') + ,Context::getLang('cmd_cancel') + ); Context::close(); exit(); + } - // 캡챠 이미지 출력 - } else if(Context::get('captcha_action')=='captchaImage') { - $f = FileHandler::readDir('./addons/captcha/icon'); - shuffle($f); - $keyword = $_SESSION['captcha_keyword']; - for($key=0,$c=count($f);$key<$c;$key++) { - if($keyword.".gif" == $f[$key]) break; - } + function before_module_init_captchaImage() + { + if($_SESSION['captcha_authed']) return false; - // 이미지 만들기 - $thumb = imagecreatetruecolor(250,100); - for($i=0,$c=count($f);$i<$c;$i++) { - $x = ($i%5)*50; - $y = $i>4?0:50; - imagedestroy($dummy); - $dummy = imagecreatefromgif('./addons/captcha/icon/'.$f[$i]); - imagecopyresampled($thumb, $dummy, $x, $y, 0, 0, 50, 50, 50, 50); + $keyword = $_SESSION['captcha_keyword']; + $im = $this->createCaptchaImage($keyword); - if($i==$key) { - $_SESSION['captcha_x'] = $x; - $_SESSION['captcha_y'] = $y; - } - } - imagedestroy($dummy); header("Cache-Control: "); header("Pragma: "); header("Content-Type: image/png"); - imagepng($thumb, null,9); - imagedestroy($thumb); - Context::close(); + + imagepng($im); + imagedestroy($im); + + Context::close(); exit(); + } - // 캡챠 이미지 점검 - } else if(Context::get('captcha_action')=='captchaCompare') { - $x = Context::get('mx'); - $y = Context::get('my'); - $sx = $_SESSION['captcha_x']; - $sy = $_SESSION['captcha_y']; + function createCaptchaImage($string) + { + $arr = array(); + for($i=0,$c=strlen($string);$i<$c;$i++) $arr[] = $string{$i}; - if($x>=$sx && $x<=$sx+50 && $y>=$sy && $y<=$sy+50) $_SESSION['captcha_authed'] = true; + // 글자 하나 사이즈 + $w = 18; + $h = 25; + + // 글자 수 + $c = count($arr); + + // 글자 이미지 + $im = array(); + + // 총사이즈로 바탕 이미지 생성 + $im[] = imagecreate(($w+2)*count($arr), $h); + + $deg = range(-30,30); + shuffle($deg); + + // 글자별 이미지 생성 + foreach($arr as $i => $str) + { + $im[$i+1] = @imagecreate($w, $h); + $background_color = imagecolorallocate($im[$i+1], 255, 255, 255); + $text_color = imagecolorallocate($im[$i+1], 0, 0, 0); + + // 글자폰트(사이즈) 조절 + $ran = range(1,20); + shuffle($ran); + + if(function_exists('imagerotate')) + { + imagestring($im[$i+1], (array_pop($ran)%3)+3, 2, (array_pop($ran)%8), $str, $text_color); + $im[$i+1] = imagerotate($im[$i+1], array_pop($deg), 0); + + $background_color = imagecolorallocate($im[$i+1], 255, 255, 255); + imagecolortransparent($im[$i+1], $background_color); + } + else + { + imagestring($im[$i+1], (array_pop($ran)%3)+3, 2, (array_pop($ran)%4), $str, $text_color); + } + } + + // 각글자 이미지를 합침 + for($i=1;$icreateCaptchaAudio($keyword); + + header('Content-type: audio/mpeg'); + header("Content-Disposition: attachment; filename=\"captcha_audio.mp3\""); + header('Cache-Control: no-store, no-cache, must-revalidate'); + header('Expires: Sun, 1 Jan 2000 12:00:00 GMT'); + header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT'); + header('Content-Length: ' . strlen($data)); + + echo $data; + Context::close(); + exit(); + } + + function createCaptchaAudio($string) + { + $data = ''; + $_audio = './addons/captcha/audio/F_%s.mp3'; + for($i=0,$c=strlen($string);$i<$c;$i++) + { + $_data = FileHandler::readFile(sprintf($_audio, $string{$i})); + + $start = rand(5, 68); // 해더 4바이트, 데이터 영역 64바이트 정도 랜덤하게 시작 + $datalen = strlen($_data) - $start - 256; // 마지막 unchanged 256 바이트 + + for($j=$start;$j<$datalen;$j+=64) + { + $ch = ord($_data{$j}); + if($ch<9 || $ch>119) continue; + $_data{$j} = chr($ch+rand(-8,8)); + } + + $data .= $_data; + } + + return $data; + } + + function before_module_init_captchaCompare() + { + if($_SESSION['captcha_authed']) return false; + + if(strtoupper($_SESSION['captcha_keyword']) == strtoupper(Context::get('secret_text'))) $_SESSION['captcha_authed'] = true; else $_SESSION['captcha_authed'] = false; header("Content-Type: text/xml; charset=UTF-8"); @@ -100,15 +238,25 @@ print("\r\n0\r\nsuccess\r\n"); Context::close(); - exit(); - } - Context::addJsFile('./addons/captcha/captcha.min.js',false); + } + } + + $GLOBALS['__AddonCaptcha__'] = new AddonCaptcha; + $GLOBALS['__AddonCaptcha__']->setInfo($addon_info); + } + + $oAddonCaptcha = &$GLOBALS['__AddonCaptcha__']; + + if(method_exists(&$oAddonCaptcha, $called_position)) + { + if(!call_user_func(array(&$oAddonCaptcha, $called_position), &$this)) return false; + } + + $addon_act = Context::get('captcha_action'); + if($addon_act && method_exists(&$oAddonCaptcha, $called_position.'_'.$addon_act)) + { + if(!call_user_func(array(&$oAddonCaptcha, $called_position.'_'.$addon_act), &$this)) return false; + } - // 게시판/ 이슈트래커의 글쓰기/댓글쓰기 액션 호출시 세션 비교 - if(in_array(Context::get('act'), $target_acts)) { - $this->error = "msg_not_permitted"; - } - } - } ?> diff --git a/addons/captcha/captcha.js b/addons/captcha/captcha.js index 7c60c8253..ea17856a8 100644 --- a/addons/captcha/captcha.js +++ b/addons/captcha/captcha.js @@ -11,103 +11,111 @@ var calledArgs = null; function xeCaptcha() { var body = $(document.body); var captchaIma; - - if (!captchaXE) { - captchaXE = $("
") - .attr("id","captcha_screen") - .css({ - position:"absolute", - display:"none", - backgroundColor:"#111", - backgroundRepeat:"repeat", - backgroundPosition:"0 0", - zIndex:500 - }); - $('').appendTo(captchaXE); - - body.append(captchaXE); - + if (!captchaXE) { + var fc_isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false; + var fc_isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false; + var fc_isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false; + var _swfURL_ = request_uri + 'addons/captcha/swf/play.swf'; + + if(fc_isIE && fc_isWin && !fc_isOpera){ + _object_ =''; + _object_ += ''; + _object_ += ''; + _object_ += ''; + _object_ += ''; + _object_ += ''; + _object_ += ''; + _object_ += ''; + }else{ + _object_ = ''; + } + + captchaXE = $(' + -

{$lang->env_information}

+
+

{$lang->env_information} {$lang->cmd_setup}

{nl2br($lang->about_download_link)} [{$lang->cmd_download}]

- +
+ + @@ -191,16 +172,12 @@ - + + - - - - - - - + + @@ -214,6 +191,10 @@ + + + + @@ -228,36 +209,105 @@
{$lang->current_version}
{$lang->current_path}
{$lang->current_path}
{$installed_path}/
{$installed_path}/
{$lang->start_module}
{$start_module->browser_title}
{$lang->start_module}
{$start_module->browser_title}
{$lang->time_zone}
{$lang->use_optimizer}
{$lang->use}{$lang->notuse}
{$lang->mobile_view}
{$lang->use}{$lang->notuse}
Language
{$val}
+
+
-

{$lang->cmd_remake_cache}

- +
+
+
+ + +
+
+ + {@$_show_modules = false; } + + + {@$_show_modules = true; } + + + +
+
+ + + - - - - + + + + + + + +
{$lang->module}
- - - -
{$val->title} ({$val->module}) + + {$lang->cmd_install} + + {$lang->cmd_update} + +   + +
+ + - -

{$lang->newest_news}

- + +
+
+ + + - + +
{$lang->newest_news}
- {$val->title} - {zdate($val->date,"Y-m-d")} - {cut_str($val->title,36)}{zdate($val->date,"y-m-d")}
- + + + +
+
+ +
+ + + + + + + + + + + + + + + + + + + +
{$lang->addon}{$lang->cmd_setup}PCMobile
{cut_str($val->title,24)}{$lang->cmd_setup} + + {$lang->use} + + {$lang->notuse} + + + + {$lang->use} + + {$lang->notuse} + +
diff --git a/modules/admin/tpl/js/admin.js b/modules/admin/tpl/js/admin.js index d84c26cf8..ff4bfa099 100644 --- a/modules/admin/tpl/js/admin.js +++ b/modules/admin/tpl/js/admin.js @@ -11,7 +11,18 @@ function doRecompileCacheFile() { // 모듈 목록 오픈 function toggleModuleMenu(category) { - jQuery('#module_'+category).toggleClass('open'); + jQuery('#module_'+category).toggleClass('close'); + + var arr = new Array(); + jQuery('ul.navigation > li').each(function(){ + var o = jQuery(this); + if(!o.hasClass('close')) return; + var idx = o.attr('id').replace(/^module_/,''); + arr.push(idx); + }); + var expire= new Date(); + expire.setTime(expire.getTime()+(7000*24*3600000)); + xSetCookie('XEAM',arr.join(','),expire,'/'); } // 메인 모듈/ 애드온 토글 diff --git a/modules/admin/tpl/swf/count.swf b/modules/admin/tpl/swf/count.swf new file mode 100644 index 000000000..f0b906ccc Binary files /dev/null and b/modules/admin/tpl/swf/count.swf differ diff --git a/modules/autoinstall/autoinstall.admin.controller.php b/modules/autoinstall/autoinstall.admin.controller.php index d9e16ebd8..20a3c0773 100644 --- a/modules/autoinstall/autoinstall.admin.controller.php +++ b/modules/autoinstall/autoinstall.admin.controller.php @@ -171,11 +171,16 @@ } if($oModel->getPackage($args->package_srl)) { - executeQuery("autoinstall.updatePackage", $args); + $output = executeQuery("autoinstall.updatePackage", $args); } else { - executeQuery("autoinstall.insertPackage", $args); + $output = executeQuery("autoinstall.insertPackage", $args); + if(!$output->toBool()) + { + $output = executeQuery("autoinstall.deletePackage", $args); + $output = executeQuery("autoinstall.insertPackage", $args); + } } } } diff --git a/modules/autoinstall/queries/deletePackage.xml b/modules/autoinstall/queries/deletePackage.xml new file mode 100644 index 000000000..f3dbf7183 --- /dev/null +++ b/modules/autoinstall/queries/deletePackage.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/modules/autoinstall/schemas/autoinstall_packages.xml b/modules/autoinstall/schemas/autoinstall_packages.xml index cf1e102a9..645fd6db8 100644 --- a/modules/autoinstall/schemas/autoinstall_packages.xml +++ b/modules/autoinstall/schemas/autoinstall_packages.xml @@ -2,7 +2,7 @@ - +
diff --git a/modules/document/schemas/documents.xml b/modules/document/schemas/documents.xml index f95f92c87..aaa53a832 100644 --- a/modules/document/schemas/documents.xml +++ b/modules/document/schemas/documents.xml @@ -24,7 +24,7 @@ - + diff --git a/modules/editor/skins/xpresseditor/css/default.css b/modules/editor/skins/xpresseditor/css/default.css index b1f0325e1..40c114cc6 100644 --- a/modules/editor/skins/xpresseditor/css/default.css +++ b/modules/editor/skins/xpresseditor/css/default.css @@ -249,7 +249,7 @@ .xpress-editor .tool li.fcolor .layer{ width:218px !important; height:auto !important; background-image:none !important; overflow:hidden;} .xpress-editor .tool .layer .palette{ width:210px; position:relative; left:7px; padding:8px 0 7px 0; margin:0;} .xpress-editor .tool .layer .palette li{ float:left; margin:0 1px 1px 0; font-size:0; line-height:0;} -.xpress-editor .tool .layer .palette button{ position:relative; overflow:hidden; width:11px; height:11px;} +.xpress-editor .tool .layer .palette button{ position:relative; overflow:hidden; width:11px !important; height:11px !important;} .xpress-editor .tool li.bcolor .layer { width:218px; overflow:hidden;} .xpress-editor .tool .layer .background{ width:210px; position:relative; left:7px; margin:0 0 -2px 0; padding:8px 0 0 0; *padding-bottom:8px; _padding-bottom:4px;} diff --git a/modules/file/lang/en.lang.php b/modules/file/lang/en.lang.php index 1b72dfaf2..9a9754858 100644 --- a/modules/file/lang/en.lang.php +++ b/modules/file/lang/en.lang.php @@ -53,7 +53,7 @@ 'ipaddress' => 'IP Address', ); $lang->msg_not_allowed_outlink = 'It is not allowed to download files not from this site.'; - $lang->msg_not_permitted_create = '파일 또는 디렉토리를 생성할 수 없습니다.'; - $lang->msg_file_upload_error = '파일 업로드 중 에러가 발생하였습니다.'; + $lang->msg_not_permitted_create = 'Failed to create a file or directory.'; + $lang->msg_file_upload_error = 'An error has occurred during uploading.'; ?> diff --git a/modules/layout/layout.model.php b/modules/layout/layout.model.php index 2630720ce..22994e4f3 100644 --- a/modules/layout/layout.model.php +++ b/modules/layout/layout.model.php @@ -83,6 +83,8 @@ $searched_count = count($searched_list); if(!$searched_count) return; + natcasesort($searched_list); + // 찾아진 레이아웃 목록을 loop돌면서 필요한 정보를 간추려 return for($i=0;$i<$searched_count;$i++) { // 레이아웃의 이름 diff --git a/modules/member/member.mobile.php b/modules/member/member.mobile.php index 2a441e66b..b7a8c6ebb 100644 --- a/modules/member/member.mobile.php +++ b/modules/member/member.mobile.php @@ -4,6 +4,11 @@ class memberMobile extends member { function init() { // 회원 관리 정보를 받음 + $oModuleModel = &getModel('module'); + $this->member_config = $oModuleModel->getModuleConfig('member'); + + Context::set('member_config', $this->member_config); + $this->setTemplatePath($this->module_path.'tpl'); } @@ -20,5 +25,134 @@ class memberMobile extends member Context::set('referer_url', $_SERVER['HTTP_REFERER']); $this->setTemplateFile('login_form'); } + + function dispMemberSignUpForm(){ + $oMemberModel = &getModel('member'); + + if($oMemberModel->isLogged()) return $this->stop('msg_already_logged'); + + $trigger_output = ModuleHandler::triggerCall('member.dispMemberSignUpForm', 'before', $this->member_config); + if(!$trigger_output->toBool()) return $trigger_output; + + if ($this->member_config->enable_join != 'Y') return $this->stop('msg_signup_disabled'); + Context::set('extend_form_list', $oMemberModel->getCombineJoinForm($member_info)); + + $member_config = $oMemberModel->getMemberConfig(); + Context::set('member_config', $member_config); + + $this->setTemplateFile('signup_form'); + } + + function dispMemberInfo() { + $oMemberModel = &getModel('member'); + $logged_info = Context::get('logged_info'); + + // 비회원일 경우 정보 열람 중지 + if(!$logged_info->member_srl) return $this->stop('msg_not_permitted'); + $member_srl = Context::get('member_srl'); + if(!$member_srl && Context::get('is_logged')) { + $member_srl = $logged_info->member_srl; + } elseif(!$member_srl) { + return $this->dispMemberSignUpForm(); + } + + $site_module_info = Context::get('site_module_info'); + $member_info = $oMemberModel->getMemberInfoByMemberSrl($member_srl, $site_module_info->site_srl); + unset($member_info->password); + unset($member_info->email_id); + unset($member_info->email_host); + unset($member_info->email_address); + + if(!$member_info->member_srl) return $this->dispMemberSignUpForm(); + + Context::set('member_info', $member_info); + Context::set('extend_form_list', $oMemberModel->getCombineJoinForm($member_info)); + if ($member_info->member_srl == $logged_info->member_srl) + Context::set('openids', $oMemberModel->getMemberOpenIDByMemberSrl($member_srl)); + $this->setTemplateFile('member_info_mobile'); + } + + /** + * @brief 회원 정보 수정 + **/ + function dispMemberModifyInfo() { + $oMemberModel = &getModel('member'); + $oModuleModel = &getModel('module'); + $memberModuleConfig = $oModuleModel->getModuleConfig('member'); + + // 로그인 되어 있지 않을 경우 로그인 되어 있지 않다는 메세지 출력 + if(!$oMemberModel->isLogged()) return $this->stop('msg_not_logged'); + + $logged_info = Context::get('logged_info'); + $member_srl = $logged_info->member_srl; + + $member_info = $oMemberModel->getMemberInfoByMemberSrl($member_srl); + $member_info->signature = $oMemberModel->getSignature($member_srl); + Context::set('member_info',$member_info); + + // 추가 가입폼 목록을 받음 + Context::set('extend_form_list', $oMemberModel->getCombineJoinForm($member_info)); + + Context::set('openids', $oMemberModel->getMemberOpenIDByMemberSrl($member_srl)); + + // 에디터 모듈의 getEditor를 호출하여 서명용으로 세팅 + if($member_info->member_srl) { + $oEditorModel = &getModel('editor'); + $option->primary_key_name = 'member_srl'; + $option->content_key_name = 'signature'; + $option->allow_fileupload = false; + $option->enable_autosave = false; + $option->enable_default_component = true; + $option->enable_component = false; + $option->resizable = false; + $option->disable_html = true; + $option->height = 200; + $option->skin = $this->member_config->editor_skin; + $option->colorset = $this->member_config->editor_colorset; + $editor = $oEditorModel->getEditor($member_info->member_srl, $option); + Context::set('editor', $editor); + } + + // 템플릿 파일 지정 + $this->setTemplateFile('modify_info'); + } + + /** + * @brief 회원 비밀번호 수정 + **/ + function dispMemberModifyPassword() { + $oMemberModel = &getModel('member'); + + // 로그인 되어 있지 않을 경우 로그인 되어 있지 않다는 메세지 출력 + if(!$oMemberModel->isLogged()) return $this->stop('msg_not_logged'); + + $logged_info = Context::get('logged_info'); + $member_srl = $logged_info->member_srl; + + $member_info = $oMemberModel->getMemberInfoByMemberSrl($member_srl); + Context::set('member_info',$member_info); + + // 템플릿 파일 지정 + $this->setTemplateFile('modify_password'); + } + + /** + * @brief 탈퇴 화면 + **/ + function dispMemberLeave() { + $oMemberModel = &getModel('member'); + + // 로그인 되어 있지 않을 경우 로그인 되어 있지 않다는 메세지 출력 + if(!$oMemberModel->isLogged()) return $this->stop('msg_not_logged'); + + $logged_info = Context::get('logged_info'); + $member_srl = $logged_info->member_srl; + + $member_info = $oMemberModel->getMemberInfoByMemberSrl($member_srl); + Context::set('member_info',$member_info); + + // 템플릿 파일 지정 + $this->setTemplateFile('leave_form'); + } } ?> diff --git a/modules/member/tpl/css/mlogin.css b/modules/member/tpl/css/mlogin.css index 4c5fec05c..a7a2d0f34 100644 --- a/modules/member/tpl/css/mlogin.css +++ b/modules/member/tpl/css/mlogin.css @@ -1,33 +1,42 @@ -/* Mobile XE */ -body{margin:0;background:#fff;color:#000;word-wrap:break-word} -body,input,textarea,select,button,table{font-family:Tahoma, Geneva, sans-serif} -form{margin:0;padding:0} -form ul{margin:0;padding:0;list-style:none} -form li{margin:0 0 10px 0;padding:0 0 10px 0;border-bottom:1px dashed #999} -form li:last-child{border:0} -form p{margin:0} -form p.help{color:#666} -fieldset{border:0;margin:0;padding:0} -input,textarea,select{font-size:16px} -button{font-size:12px;cursor:pointer;background:#eee;border:1px solid #666;border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px;overflow:visible;padding:3px;text-shadow:1px 1px 0 #fff;box-shadow:0 0 2px #666;-moz-box-shadow:0 0 2px #666;-webkit-box-shadow:0 0 2px #666;text-decoration:none;font-weight:normal} -select{width:90%} -/* Common Class */ -.al{text-align:left} -.db{display:block} -.fb{font-weight:bold} -.itx{border:1px solid #ccc;width:90%;font-size:20px;height:30px;padding:5px 10px} -.sn{margin:10px;*zoom:1} -.sn:after{content:"";display:block;clear:both} -/* Body */ -.bd{position:relative;overflow:hidden;clear:both} -.bd .h2{font-size:20px;background:#ccc;border:1px solid #aaa} -.bd .h3{font-size:16px;background:#eee;border:1px solid #ccc} -.bd .h2,.bd .h3{position:relative;margin:-1px 0;padding:10px;border:1px solid #aaa;border-left:0;border-right:0;text-shadow:1px 1px #fff} -.bd .h2 em,.bd .h3 em{font-weight:normal;color:#f60;font-size:12px} -.bd .h2 a,.bd .h3 a{color:#000} -.bd .h2 .bn{position:absolute;top:8px;right:10px;font-size:12px;margin:0} -/* Context */ -.cm{margin:0;padding:10px;background:#777;color:#fff;text-align:center;list-style:none;border-top:1px solid #555;*zoom:1} -.cm:after{content:"";display:block;clear:both} -.cm .fl{margin:0 5px 0 0} -.cm .fr{margin:0 0 0 5px} +/* Mobile XE Login (/modules/member/tpl/login_form.html) */ +body{margin:0;background:#fff;color:#000;word-wrap:break-word} +body,input,textarea,select,button,table{font-family:Tahoma,Geneva,sans-serif} +img{border:0} +em{font-style:normal} +form{margin:0;padding:0} +fieldset{margin:0;padding:0;border:0} +textarea{resize:vertical} +input[type=checkbox], +input[type=radio]{width:13px;height:13px;margin:0;padding:0} +/* Common */ +.fl{float:left} +.fr{float:right} +/* Body */ +.bd{background:#f8f8f8;padding:1px 0;border-bottom:1px solid #ccc8be} +.bd:after{content:"";margin:0;position:relative;top:3px;display:block;clear:both;height:1px;background:#fff} +/* Hx */ +.hx{position:relative;border-bottom:1px solid #ccc8be;padding:8px 10px;margin:0} +.hx:after{content:"";margin:0 -10px;position:relative;top:10px;display:block;clear:both;height:1px;background:#fff} +.hx.h2{background:#e5e5e5} +.hx h2{margin:0 10px 0 0;display:inline} +.hx h2{font-size:16px;line-height:1.4} +/* Form Field */ +.ff{margin:0;padding:10px 0} +.ff ul{margin:0 10px 10px 10px;padding:10px 0 0 0;list-style:none} +.ff li{margin:0 0 5px 0;padding:0} +.ff label+input[type=text], +.ff label+input[type=password], +.ff label+textarea, +.ff label+select{display:block;width:96%;font-size:14px;margin:0 0 5px 0} +.ff label+input[type=text], +.ff label+input[type=password], +.ff label+textarea{padding:5px} +/* Button Area */ +.bna{text-align:center;padding:0 10px;margin:10px 0} +.bna:after{content:"";display:block;clear:both} +.bn{display:inline-block;line-height:26px !important;padding:0 10px;font-size:12px;font-weight:bold;border:1px solid;text-decoration:none;border-radius:5px;-moz-border-radius:5px;-webkit-border-radius:5px;cursor:pointer;vertical-align:middle} +.bn[type=submit], +.bn[type=button]{height:28px} +.bn[href]{height:26px} +.bn.dark{border-color:#666;background:#777 -webkit-gradient(linear,0% 0%,0% 100%,from(#7e7c78),to(#5c5b58));background:#777 -moz-linear-gradient(top,#7e7c78,#5c5b58);color:#fff;box-shadow:0 0 1px #fff inset;-moz-box-shadow:0 0 1px #fff inset;-webkit-box-shadow:0 0 1px #fff inset} +.bn.white{border-color:#b5b5b5;background:#1b1b1b -webkit-gradient(linear,0% 0%,0% 100%,from(#fff),to(#f6f6f6),color-stop(0.5,#f0f0f0),color-stop(0.5,#e4e4e4));background:#1b1b1b -moz-linear-gradient(top,#fff,#e4e4e4);color:#000} diff --git a/modules/member/tpl/css/msignup.css b/modules/member/tpl/css/msignup.css new file mode 100644 index 000000000..384e951ab --- /dev/null +++ b/modules/member/tpl/css/msignup.css @@ -0,0 +1,54 @@ +@charset "utf-8"; +/* Mobile XE */ +body{margin:0;background:#fff;color:#000;word-wrap:break-word} +body,input,textarea,select,button,table{font-family:Tahoma, Geneva, sans-serif} +img{border:0} +em{font-style:normal} +form{margin:0;padding:0} +form ul{margin:0;padding:0;list-style:none} +form li{margin:0 0 10px 0;padding:0 0 10px 0;border-bottom:1px dashed #999} +form li:last-child{border:0} +form p{margin:0} +form p.help{color:#666} +fieldset{border:0;margin:0;padding:0} +input,textarea,select{font-size:16px} +button{font-size:12px;cursor:pointer;background:#eee;border:1px solid #666;border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px;overflow:visible;padding:3px;text-shadow:1px 1px 0 #fff;box-shadow:0 0 2px #666;-moz-box-shadow:0 0 2px #666;-webkit-box-shadow:0 0 2px #666;text-decoration:none;font-weight:normal} +/* Common Class */ +.fl{float:left} +.fr{float:right} +.cb{clear:both} +.itx{border:1px solid #ccc;width:90%;font-size:20px;height:30px;padding:5px 10px} +.itxx{border:1px solid #ccc;width:90%;font-size:20px;padding:5px 10px;resize:vertical} +.db{display:block} +.fb{font-weight:bold} +.sn{margin:10px;*zoom:1} +.sn:after{content:"";display:block;clear:both} +/* Button */ +.bn{display:inline-block;padding:5px 10px;font-weight:normal;font-size:14px;border:1px solid #333;background:#eee;color:#000;text-shadow:1px 1px 0 #fff;box-shadow:0 0 3px #333;-moz-box-shadow:0 0 3px #333;-webkit-box-shadow:0 0 3px #333;border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px;text-decoration:none} +/* Edge = Header/Footer */ +.eg{position:relative;background:#666;*zoom:1} +.eg:after{content:"";display:block;clear:both} +.eg a{text-decoration:none} +/* Header */ +.hd{padding:10px;border-top:3px solid #444} +.hd .h1{float:left;display:inline;color:#fff;font-size:24px;margin:0;font-weight:bold;text-shadow:0 0 3px #000} +.hd .h1 a{color:#fff} +.hd .bn{font-size:12px} +/* Footer */ +.ft{padding:0 5px;margin:0;list-style:none} +.ft a{display:inline-block;padding:10px;color:#fff;text-shadow:0 0 2px #000;font-size:14px;font-weight:bold} +/* Context */ +.cm{margin:0;padding:10px;background:#777;color:#fff;text-align:center;list-style:none;border-top:1px solid #555;*zoom:1} +.cm:after{content:"";display:block;clear:both} +.cm .fl{margin:0 5px 0 0} +.cm .fr{margin:0 0 0 5px} +/* Copyright */ +.cr{margin:0;padding:5px 15px;text-align:center;background:#444;color:#ccc;text-shadow:0 0 2px #000;font-size:12px;font-weight:bold} +/* Body */ +.bd{position:relative;overflow:hidden;clear:both} +.bd .h2{font-size:20px;background:#ccc;border:1px solid #aaa} +.bd .h3{font-size:16px;background:#eee;border:1px solid #ccc} +.bd .h2,.bd .h3{position:relative;margin:-1px 0;padding:10px;border:1px solid #aaa;border-left:0;border-right:0;text-shadow:1px 1px #fff} +.bd .h2 em,.bd .h3 em{font-weight:normal;color:#f60;font-size:12px} +.bd .h2 a,.bd .h3 a{color:#000} +.bd .h2 .bn{position:absolute;top:8px;right:10px;font-size:12px;margin:0} \ No newline at end of file diff --git a/modules/member/tpl/leave_form.html b/modules/member/tpl/leave_form.html new file mode 100644 index 000000000..27b1d8135 --- /dev/null +++ b/modules/member/tpl/leave_form.html @@ -0,0 +1,28 @@ +{@ Context::addJsFile("./common/js/jquery.js", true, '', -100000) } +{@ Context::addJsFile("./common/js/js_app.js", true, '', -100000) } +{@ Context::addJsFile("./common/js/common.js", true, '', -100000) } +{@ Context::addJsFile("./common/js/xml_handler.js", true, '', -100000) } +{@ Context::addJsFile("./common/js/xml_js_filter.js", true, '', -100000) } + + + + +
+

{$member_title = $lang->msg_leave_member}

+
+ + + +
+
    +
  • {$member_info->user_id}
  • +
  • +
+
+ + +
+
diff --git a/modules/member/tpl/login_form.html b/modules/member/tpl/login_form.html index 52912e990..6289ce853 100644 --- a/modules/member/tpl/login_form.html +++ b/modules/member/tpl/login_form.html @@ -1,16 +1,19 @@ - -
-

{$lang->cmd_login}

-
- - - -
    -
  • -
  • -
-
-
-
-
-
+ +
+
+

{$lang->cmd_login}

+
+
+ + + +
    +
  • +
  • +
+
+
+
+
+
+
diff --git a/modules/member/tpl/member_info_mobile.html b/modules/member/tpl/member_info_mobile.html new file mode 100644 index 000000000..ad650232c --- /dev/null +++ b/modules/member/tpl/member_info_mobile.html @@ -0,0 +1,92 @@ +{@ Context::addJsFile("./common/js/jquery.js", true, '', -100000) } +{@ Context::addJsFile("./common/js/js_app.js", true, '', -100000) } +{@ Context::addJsFile("./common/js/common.js", true, '', -100000) } +{@ Context::addJsFile("./common/js/xml_handler.js", true, '', -100000) } +{@ Context::addJsFile("./common/js/xml_js_filter.js", true, '', -100000) } + + + +
+

{$lang->cmd_view_member_info}

+

{$lang->member_default_info}

+
+
+
    +
  • {htmlspecialchars($member_info->user_name)}
  • +
  • {htmlspecialchars($member_info->nick_name)}
  • + +
  • profile_image
  • + + +
  • image_name
  • + + +
  • image_mark
  • + +
  • {htmlspecialchars($member_info->homepage)}
  • +
  • {htmlspecialchars($member_info->blog)}
  • +
  • {zdate($member_info->birthday,"Y-m-d")}
  • + +
  • {$member_info->signature}
  • + +
  • {$val}
  • +
  • {zdate($member_info->regdate,"Y-m-d H:i")}
  • + +
  • {zdate($member_info->last_login,"Y-m-d H:i")}
  • + + + +
  • + +
    {$openid->openid}
  • + + + +
+
+ +

{$lang->member_extend_info}

+
+
    + +
  • + + {$lang->private} + + + {htmlspecialchars($val->value[0])} + - + {htmlspecialchars($val->value[1])} + - + {htmlspecialchars($val->value[2])} + + {htmlspecialchars($val->value[0])}
    {htmlspecialchars($val->value[1])} + + {htmlspecialchars(implode(", ",$val->value))}  + + {zdate($val->value, "Y-m-d")}  + + {nl2br(htmlspecialchars($val->value))}  + +
  • + + +
+
+ + +
+
diff --git a/modules/member/tpl/modify_info_mobile.html b/modules/member/tpl/modify_info_mobile.html new file mode 100644 index 000000000..2e0893dd5 --- /dev/null +++ b/modules/member/tpl/modify_info_mobile.html @@ -0,0 +1,205 @@ +{@ Context::addJsFile("./common/js/jquery.js", true, '', -100000) } +{@ Context::addJsFile("./common/js/js_app.js", true, '', -100000) } +{@ Context::addJsFile("./common/js/common.js", true, '', -100000) } +{@ Context::addJsFile("./common/js/xml_handler.js", true, '', -100000) } +{@ Context::addJsFile("./common/js/xml_js_filter.js", true, '', -100000) } + + + + + + + + + + + + + + + + + + + + + + + +
+

{$lang->msg_update_member}

+

{$lang->member_default_info}

+
profile_image == 'Y' || $member_config->image_name=='Y' || $member_config->image_mark=='Y')-->enctype="multipart/form-data" target="tmp_upload_iframe"> + + + + + + +
+
    +
  • {htmlspecialchars($member_info->user_id)}
  • +
  • {$lang->about_user_name}

  • +
  • {$lang->about_nick_name}

  • +
  • {$lang->about_email_address}

  • + +
  • + + + + +

    {$lang->profile_image_max_width} : {$member_config->profile_image_max_width}px, {$lang->profile_image_max_height} : {$member_config->profile_image_max_height}px

    +
  • + + +
  • + + + + +

    {$lang->image_name_max_width} : {$member_config->image_name_max_width}px, {$lang->image_name_max_height} : {$member_config->image_name_max_height}px

    +
  • + + +
  • + + + + + +

    {$lang->image_mark_max_width} : {$member_config->image_mark_max_width}px, {$lang->image_mark_max_height} : {$member_config->image_mark_max_height}px

    +
  • + +
  • {$lang->about_homepage}

  • +
  • {$lang->about_blog_url}

  • +
  • {$lang->about_birthday}

  • + +
  • allow_mailing!='N')-->checked="checked" />

    {$lang->about_allow_mailing}

  • + +
  • + +
+
+ +

{$lang->member_extend_info}

+
+
    + +
  • + + + + + + + + + + + + + + + + + + + + + + value)&&in_array($v, $val->value))-->checked="checked"/> + + + + + + value)&&in_array($v, $val->value))-->checked="checked"/> + + + + + + + + + + + + + + + + + + +

    {$val->description}

    + +
  • + +
+
+ + +

{$lang->openid}

+
+ +
+ + +
+
diff --git a/modules/member/tpl/modify_password.html b/modules/member/tpl/modify_password.html new file mode 100644 index 000000000..03e30f74e --- /dev/null +++ b/modules/member/tpl/modify_password.html @@ -0,0 +1,30 @@ +{@ Context::addJsFile("./common/js/jquery.js", true, '', -100000) } +{@ Context::addJsFile("./common/js/js_app.js", true, '', -100000) } +{@ Context::addJsFile("./common/js/common.js", true, '', -100000) } +{@ Context::addJsFile("./common/js/xml_handler.js", true, '', -100000) } +{@ Context::addJsFile("./common/js/xml_js_filter.js", true, '', -100000) } + + + + +
+

{$member_title = $lang->cmd_modify_member_password}

+
+ + + +
+
    +
  • {htmlspecialchars($member_info->user_id)}
  • +
  • +
  • +
    +

    {$lang->about_password}

  • +
+
+ + +
+
\ No newline at end of file diff --git a/modules/member/tpl/signup_form.html b/modules/member/tpl/signup_form.html new file mode 100644 index 000000000..571450c8a --- /dev/null +++ b/modules/member/tpl/signup_form.html @@ -0,0 +1,118 @@ +{@ Context::addJsFile("./common/js/jquery.js", true, '', -100000) } +{@ Context::addJsFile("./common/js/js_app.js", true, '', -100000) } +{@ Context::addJsFile("./common/js/common.js", true, '', -100000) } +{@ Context::addJsFile("./common/js/xml_handler.js", true, '', -100000) } +{@ Context::addJsFile("./common/js/xml_js_filter.js", true, '', -100000) } + + + + + + +
+

{$lang->cmd_signup}

+

{$lang->member_default_info}

+
+
+
    +
  • {$lang->about_user_id}

  • +
  • {$lang->about_password}

  • +
  • +
  • {$lang->about_user_name}

  • +
  • {$lang->about_nick_name}

  • +
  • {$lang->about_email_address}

  • +
  • {$lang->about_homepage}

  • +
  • {$lang->about_blog_url}

  • +
  • {$lang->about_birthday}

  • +
+
+ +

{$lang->member_extend_info}

+
+
    + +
  • + + + + + + + + + + + + + + + + + + + + + + value)&&in_array($v, $val->value))-->checked="checked"/> + + + + + + value)&&in_array($v, $val->value))-->checked="checked"/> + + + + + + + + + + + + + + + + + + +

    {$val->description}

    + +
  • + +
+
+ + + +
+ +
+
+
diff --git a/modules/menu/menu.mobile.php b/modules/menu/menu.mobile.php index 17be5375a..faa52cba1 100644 --- a/modules/menu/menu.mobile.php +++ b/modules/menu/menu.mobile.php @@ -8,7 +8,7 @@ class menuMobile extends moduleObject { if(!$menu_item['link']) return; $obj->href = $menu_item['href']; $obj->depth = $depth; - $obj->link = $menu_item['link']; + $obj->text = $menu_item['text']; $this->result[] = $obj; if(!$menu_item['list']) return; foreach($menu_item['list'] as $item) diff --git a/modules/menu/tpl/css/mmenu.css b/modules/menu/tpl/css/mmenu.css index 2f52eb5d8..68f8d27e5 100644 --- a/modules/menu/tpl/css/mmenu.css +++ b/modules/menu/tpl/css/mmenu.css @@ -1,11 +1,18 @@ -/* Body */ -.bd{position:relative;overflow:hidden;clear:both} -/* GNB */ -.gn,.gn ul{margin:0;padding:0;list-style:none} -.gn li{margin:-1px 0;border:1px solid #999;border-left:0;border-right:0;vertical-align:top} -.gn li a{display:block;text-decoration:none;height:45px;line-height:45px;padding:0 10px;color:#000;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} -.gn li a em{font-weight:normal;color:#f60;font-size:12px} -.gn li a:visited{color:#666} -.gn li li a{padding:0 10px 0 20px} -.gn li li li a{padding:0 10px 0 30px} -.gn li li li li a{padding:0 10px 0 50px} +@charset "utf-8"; +/* Mobile XE (/menu/tpl/menu.html) */ +.bd{background:#f8f8f8;padding:1px 0} +/* Global Navigation */ +.gn{margin:0;padding:0;list-style:none;background:#d3d1cc} +.gn li{background:#d3d1cc;border:1px solid #a3a09a;border-left:0;border-right:0;margin:0 0 -1px 0} +.gn li li{background:#f8f8f8;border:1px solid #c9c9c9;border-left:0;border-right:0} +.gn ul{margin:0 0 -1px 0;padding:0;list-style:none} +.gn a{position:relative;text-decoration:none;display:block;padding:10px;font-size:16px} +.gn li a{color:#333} +.gn li a:after{position:absolute;top:7px;right:10px;content:"›";color:#888;font-size:18px;font-weight:bold;font-family:Verdana, Geneva, sans-serif} +.gn li li a:before{content:"";display:inline-block;width:6px;height:6px;border:1px dotted #666;border-top:0;border-right:0;margin:0 4px 0 0;vertical-align:top} +.gn li li a{padding-left:15px} +.gn li li li a{padding-left:30px} +.gn li li li li a{padding-left:45px} +.gn li li li li li a{padding-left:60px} +.gn em{color:#f63;font-size:12px} + diff --git a/modules/menu/tpl/menu.html b/modules/menu/tpl/menu.html index 6a5bff6d3..4aaf5a6b6 100644 --- a/modules/menu/tpl/menu.html +++ b/modules/menu/tpl/menu.html @@ -1,30 +1,30 @@ - -
-
    - {@ $start = true } - {@ $depth = 0 } - - - - - -
      - - - -
    - {@ $depth -= 1} - - -
  • » {$val->link} - {@ $start = false } - {@ $depth = $val->depth } - - -
  • -
- {@ $depth -= 1} - - - -
+ +
+
    + {@ $start = true } + {@ $depth = 0 } + + + + + +
      + + + +
    + {@ $depth -= 1} + + +
  • {$val->text} + {@ $start = false } + {@ $depth = $val->depth } + + +
  • +
+ {@ $depth -= 1} + + + +
diff --git a/modules/module/module.controller.php b/modules/module/module.controller.php index 408b85adf..8d67358a8 100644 --- a/modules/module/module.controller.php +++ b/modules/module/module.controller.php @@ -695,5 +695,12 @@ $output = executeQuery('module.deleteLock', $args); return $output; } + + function updateModuleInSites($site_srls, $args) + { + $args->site_srls = $site_srls; + $output = executeQuery('module.updateModuleInSites', $args); + return $output; + } } ?> diff --git a/modules/module/module.model.php b/modules/module/module.model.php index 7218da92f..e7083bd16 100644 --- a/modules/module/module.model.php +++ b/modules/module/module.model.php @@ -535,9 +535,11 @@ $list = FileHandler::readDir($skin_path); if(!count($list)) return; + natcasesort($list); + foreach($list as $skin_name) { unset($skin_info); - $skin_info = $this->loadSkinInfo($path, $skin_name); + $skin_info = $this->loadSkinInfo($path, $skin_name, $dir); if(!$skin_info) $skin_info->title = $skin_name; $skin_list[$skin_name] = $skin_info; @@ -1263,7 +1265,7 @@ function getModuleFileBox($module_filebox_srl){ $args->module_filebox_srl = $module_filebox_srl; - return executeQuery('getModuleFileBox', $args); + return executeQuery('module.getModuleFileBox', $args); } function getModuleFileBoxList(){ diff --git a/modules/module/queries/updateModuleInSites.xml b/modules/module/queries/updateModuleInSites.xml new file mode 100644 index 000000000..e38da0296 --- /dev/null +++ b/modules/module/queries/updateModuleInSites.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/modules/module/tpl/css/mlang.css b/modules/module/tpl/css/mlang.css index 4c7ce15cf..e66fd6c64 100644 --- a/modules/module/tpl/css/mlang.css +++ b/modules/module/tpl/css/mlang.css @@ -1,12 +1,23 @@ -/* Body */ -.bd{position:relative;overflow:hidden;clear:both} -/* GNB */ -.gn,.gn ul{margin:0;padding:0;list-style:none} -.gn li{margin:-1px 0;border:1px solid #999;border-left:0;border-right:0;vertical-align:top} -.gn li a{display:block;text-decoration:none;height:45px;line-height:45px;padding:0 10px;color:#000;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} -.gn li strong{display:block;text-decoration:none;height:45px;line-height:45px;padding:0 10px;color:#000;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} -.gn li a em{font-weight:normal;color:#f60;font-size:12px} -.gn li a:visited{color:#666} -.gn li li a{padding:0 10px 0 20px} -.gn li li li a{padding:0 10px 0 30px} -.gn li li li li a{padding:0 10px 0 50px} +@charset "utf-8"; +/* Mobile XE Language (/modules/module/tpl/lang.html) */ +body{margin:0} +.bd{background:#f8f8f8;padding:1px 0} +/* Hx */ +.hx{position:relative;border-bottom:1px solid #ccc8be;padding:8px 10px;margin:0} +.hx:after{content:"";margin:0 -10px;position:relative;top:10px;display:block;clear:both;height:1px;background:#fff} +.hx.h2{background:#e5e5e5;} +.hx h2{margin:0 10px 0 0;display:inline;font-size:16px;line-height:1.4} +/* Global Navigation */ +.gn{margin:0;padding:0;list-style:none;background:#d3d1cc} +.gn li{background:#d3d1cc;border:1px solid #a3a09a;border-left:0;border-right:0;margin:0 0 -1px 0} +.gn li li{background:#f8f8f8;border:1px solid #c9c9c9;border-left:0;border-right:0} +.gn ul{margin:0 0 -1px 0;padding:0;list-style:none} +.gn a,.gn strong{position:relative;text-decoration:none;display:block;padding:10px;font-size:16px} +.gn li a{color:#333} +.gn li a:after{position:absolute;top:7px;right:10px;content:"›";color:#888;font-size:18px;font-weight:bold;font-family:Verdana, Geneva, sans-serif} +.gn li li a:before{content:"";display:inline-block;width:6px;height:6px;border:1px dotted #666;border-top:0;border-right:0;margin:0 4px 0 0;vertical-align:top} +.gn li li a{padding-left:15px} +.gn li li li a{padding-left:30px} +.gn li li li li a{padding-left:45px} +.gn li li li li li a{padding-left:60px} +.gn em{color:#f63;font-size:12px} diff --git a/modules/module/tpl/lang.html b/modules/module/tpl/lang.html index d53522374..35c350663 100644 --- a/modules/module/tpl/lang.html +++ b/modules/module/tpl/lang.html @@ -1,12 +1,15 @@ - -
-
    - - -
  • {$val}
  • - -
  • {$val}
  • - - -
-
+ +
+
+

Select Your Language

+
+
    + + +
  • {$val}
  • + +
  • {$val}
  • + + +
+
diff --git a/modules/spamfilter/queries/insertDeniedIP.xml b/modules/spamfilter/queries/insertDeniedIP.xml index 6fcdf5a7a..700844ae3 100644 --- a/modules/spamfilter/queries/insertDeniedIP.xml +++ b/modules/spamfilter/queries/insertDeniedIP.xml @@ -4,6 +4,7 @@ + diff --git a/modules/spamfilter/schemas/spamfilter_denied_ip.xml b/modules/spamfilter/schemas/spamfilter_denied_ip.xml index f19b3e87e..eba59c51d 100644 --- a/modules/spamfilter/schemas/spamfilter_denied_ip.xml +++ b/modules/spamfilter/schemas/spamfilter_denied_ip.xml @@ -1,4 +1,5 @@
+
diff --git a/modules/spamfilter/spamfilter.admin.controller.php b/modules/spamfilter/spamfilter.admin.controller.php index 40af70329..e30f978ad 100644 --- a/modules/spamfilter/spamfilter.admin.controller.php +++ b/modules/spamfilter/spamfilter.admin.controller.php @@ -32,9 +32,10 @@ **/ function procSpamfilterAdminInsertDeniedIP() { $ipaddress = Context::get('ipaddress'); + $description = Context::get('description'); $oSpamfilterController = &getController('spamfilter'); - return $oSpamfilterController->insertIP($ipaddress); + return $oSpamfilterController->insertIP($ipaddress, $description); } /** diff --git a/modules/spamfilter/spamfilter.class.php b/modules/spamfilter/spamfilter.class.php index c82be8e55..bdec7b821 100644 --- a/modules/spamfilter/spamfilter.class.php +++ b/modules/spamfilter/spamfilter.class.php @@ -50,6 +50,8 @@ if(!$oDB->isColumnExists('spamfilter_denied_word', 'hit')) return true; if(!$oDB->isColumnExists('spamfilter_denied_word', 'latest_hit')) return true; + if(!$oDB->isColumnExists('spamfilter_denied_ip', 'description')) return true; + return false; } @@ -90,6 +92,10 @@ $oDB->addIndex('spamfilter_denied_word','idx_latest_hit', 'latest_hit'); } + if(!$oDB->isColumnExists('spamfilter_denied_ip', 'description')) { + $oDB->addColumn('spamfilter_denied_ip','description','varchar', 250); + } + return new Object(0,'success_updated'); } diff --git a/modules/spamfilter/spamfilter.controller.php b/modules/spamfilter/spamfilter.controller.php index 30a779ae6..a4b1d9451 100644 --- a/modules/spamfilter/spamfilter.controller.php +++ b/modules/spamfilter/spamfilter.controller.php @@ -132,7 +132,7 @@ // 제목과 블로그이름이 동일할 경우 최근 6시간내의 ip를 조사하여 삭제하고 금지ip로 등록 if($obj->title == $obj->excerpt) { $oTrackbackController->deleteTrackbackSender(60*60*6, $ipaddress, $obj->url, $obj->blog_name, $obj->title, $obj->excerpt); - $this->insertIP($ipaddress.'.*'); + $this->insertIP($ipaddress.'.*', 'AUTO-DENIED : trackback.insertTrackback'); return new Object(-1,'msg_alert_trackback_denied'); } @@ -153,8 +153,9 @@ * @brief IP 등록 * 등록된 IP는 스패머로 간주 **/ - function insertIP($ipaddress) { + function insertIP($ipaddress, $description = null) { $args->ipaddress = $ipaddress; + if($description) $args->description = $description; return executeQuery('spamfilter.insertDeniedIP', $args); } diff --git a/modules/spamfilter/spamfilter.model.php b/modules/spamfilter/spamfilter.model.php index 70648d6ee..3f161e404 100644 --- a/modules/spamfilter/spamfilter.model.php +++ b/modules/spamfilter/spamfilter.model.php @@ -104,7 +104,7 @@ // 정해진 시간보다 클 경우 금지 ip로 등록 if($count>=$limit_count) { $oSpamFilterController = &getController('spamfilter'); - $oSpamFilterController->insertIP($ipaddress); + $oSpamFilterController->insertIP($ipaddress, 'AUTO-DENIED : Over limit'); return new Object(-1, 'msg_alert_registered_denied_ip'); } diff --git a/modules/spamfilter/tpl/denied_ip_list.html b/modules/spamfilter/tpl/denied_ip_list.html index 7df4ea4c2..750d0314a 100644 --- a/modules/spamfilter/tpl/denied_ip_list.html +++ b/modules/spamfilter/tpl/denied_ip_list.html @@ -18,6 +18,12 @@

{$lang->about_denied_ip}

+ +
{$lang->description}
+ + + + @@ -33,6 +39,7 @@
{$lang->no}
{$lang->ipaddress}
+
{$lang->description}
{$lang->regdate}
{$lang->cmd_delete}
@@ -41,7 +48,8 @@ {count($ip_list)-$no} - {$val->ipaddress} + {$val->ipaddress} + {$val->description} {zdate($val->regdate,"Y-m-d")} {$lang->cmd_delete} diff --git a/modules/syndication/conf/info.xml b/modules/syndication/conf/info.xml new file mode 100644 index 000000000..c870d3843 --- /dev/null +++ b/modules/syndication/conf/info.xml @@ -0,0 +1,12 @@ + + + Syndication + 검색서비스업체와 직접 통신을 통해 컨텐츠를 잘 검색되도록 하는 Syndication 규약을 따라 정보를 주고받는 모듈 + 1.0 + 2010-06-23 + interlock + + + NHN + + diff --git a/modules/syndication/conf/module.xml b/modules/syndication/conf/module.xml new file mode 100644 index 000000000..cafab0a95 --- /dev/null +++ b/modules/syndication/conf/module.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/modules/syndication/lang/en.lang.php b/modules/syndication/lang/en.lang.php new file mode 100644 index 000000000..9d17e03a1 --- /dev/null +++ b/modules/syndication/lang/en.lang.php @@ -0,0 +1,32 @@ +syndication = 'Syndication'; + $lang->about_syndication = 'Syndication communicates with search service providers with standard protocol called "syndication", and makes it much better to search any information.
It will synchronize contents with search service providers with the least requests.'; + + $lang->syndication_service = 'Syndication Service'; + $lang->about_syndication_service = 'Syndication Service provides syndication services according to standard protocol.
You will get Ping result of selected(deselected) services by applying.'; + + $lang->my_syndication_url = 'URL'; + $lang->about_my_syndication_url = 'Please input URL which will be used when providing syndication information. It would be better to use representative url and keep it as long as you can.'; + + $lang->except_module = 'Modules to exclude'; + $lang->about_except_module = 'Selected modules will not be synchronized with search service providers.'; + + $lang->msg_site_url_is_null = 'Please input URL'; + $lang->success_applied = 'Successfully Applied'; + + $lang->msg_ping_test_error = 'Ping test error found. Please check domain and server configurations.'; + $lang->msg_success_ping_test = 'Ping test works fine.'; + + $lang->cmd_check_syndication_echo = 'Check Syndication ariticle printing'; + $lang->cmd_check_syndication_status = 'Check connection status'; + + $lang->site = 'Site'; + $lang->syndication_synic_start_date = 'Server registered'; + $lang->syndication_synic_last_date = 'Latest updates'; + $lang->syndication_visit_ok_count = 'Ping successed'; + $lang->syndication_visit_fail_count = 'Ping failed'; + + $lang->syndication_status_result = 'Status'; + $lang->syndication_sync_article = 'Synchronized Articles'; + $lang->syndication_status = 'Synchronization Status'; +?> diff --git a/modules/syndication/lang/ko.lang.php b/modules/syndication/lang/ko.lang.php new file mode 100644 index 000000000..e0bfa080c --- /dev/null +++ b/modules/syndication/lang/ko.lang.php @@ -0,0 +1,32 @@ +syndication = '신디케이션'; + $lang->about_syndication = '신디케이션이란 검색 서비스 업체와 syndication 이라는 표준 규약을 통해서 보다 더 잘 검색되게 하는 기능입니다.
최소한의 요청만으로 효과적으로 컨텐츠를 검색 서비스 업체와 동기화합니다'; + + $lang->syndication_service = '신디케이션 서비스'; + $lang->about_syndication_service = '신디케이션 표준 규약에 맞춰 신디케이션 서비스를 제공하는 곳입니다.
[적용하기] 버튼을 선택하시면 선택 또는 해제된 서비스에 Ping 을 통해서 결과를 통보하게 됩니다'; + + $lang->my_syndication_url = '사이트 주소'; + $lang->about_my_syndication_url = '신디케이션 정보를 제공할때 사용되는 사이트의 주소를 입력해주세요. 이 주소는 대표 주소를 이용해주시고 가능한 바꾸시지 않는 것이 좋습니다'; + + $lang->except_module = '제외시킬 모듈'; + $lang->about_except_module = '신디케이션 대상에서 제외시켜 검색서비스 업체와 동기화를 시키지 않을 모듈을 선택해주세요'; + + $lang->msg_site_url_is_null = '사이트 주소를 입력해주세요'; + $lang->success_applied = '적용되었습니다'; + + $lang->msg_ping_test_error = 'Ping 테스트 에러입니다. 도메인 및 서버 설정을 확인해주세요'; + $lang->msg_success_ping_test = '정상적 동작으로 확인되었습니다.'; + + $lang->cmd_check_syndication_echo = 'Syndication 문서 출력 동작확인'; + $lang->cmd_check_syndication_status = '연결상태 확인'; + + $lang->site = '사이트'; + $lang->syndication_synic_start_date = '서버 등록일'; + $lang->syndication_synic_last_date = '마지막 업데이트'; + $lang->syndication_visit_ok_count = 'Ping 연속접속 성공 횟수'; + $lang->syndication_visit_fail_count = 'Ping 실패 횟수'; + + $lang->syndication_status_result = '상태정보'; + $lang->syndication_sync_article = '동기화 문서'; + $lang->syndication_status = '동기화 상태'; +?> diff --git a/modules/syndication/queries/deleteExceptModules.xml b/modules/syndication/queries/deleteExceptModules.xml new file mode 100644 index 000000000..981cf5149 --- /dev/null +++ b/modules/syndication/queries/deleteExceptModules.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/modules/syndication/queries/getDeletedList.xml b/modules/syndication/queries/getDeletedList.xml new file mode 100644 index 000000000..6dae7a09a --- /dev/null +++ b/modules/syndication/queries/getDeletedList.xml @@ -0,0 +1,19 @@ + + +
+ + + + + + + + + + + + + + + + diff --git a/modules/syndication/queries/getDocumentList.xml b/modules/syndication/queries/getDocumentList.xml new file mode 100644 index 000000000..79c2ea8b4 --- /dev/null +++ b/modules/syndication/queries/getDocumentList.xml @@ -0,0 +1,31 @@ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + +
diff --git a/modules/syndication/queries/getExceptModule.xml b/modules/syndication/queries/getExceptModule.xml new file mode 100644 index 000000000..68aec543d --- /dev/null +++ b/modules/syndication/queries/getExceptModule.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/modules/syndication/queries/getExceptModules.xml b/modules/syndication/queries/getExceptModules.xml new file mode 100644 index 000000000..583350185 --- /dev/null +++ b/modules/syndication/queries/getExceptModules.xml @@ -0,0 +1,14 @@ + + +
+
+ + + + + + + + + + diff --git a/modules/syndication/queries/getGrantedModule.xml b/modules/syndication/queries/getGrantedModule.xml new file mode 100644 index 000000000..4bb67c296 --- /dev/null +++ b/modules/syndication/queries/getGrantedModule.xml @@ -0,0 +1,17 @@ + + +
+ + + + + + + + + + + + + + diff --git a/modules/syndication/queries/getGrantedModules.xml b/modules/syndication/queries/getGrantedModules.xml new file mode 100644 index 000000000..c72bd0a8a --- /dev/null +++ b/modules/syndication/queries/getGrantedModules.xml @@ -0,0 +1,19 @@ + + +
+ + + + + + + + + + + + + + + + diff --git a/modules/syndication/queries/getLang.xml b/modules/syndication/queries/getLang.xml new file mode 100644 index 000000000..eb0c59672 --- /dev/null +++ b/modules/syndication/queries/getLang.xml @@ -0,0 +1,12 @@ + + +
+ + + + + + + + + diff --git a/modules/syndication/queries/getModuleSiteInfo.xml b/modules/syndication/queries/getModuleSiteInfo.xml new file mode 100644 index 000000000..921e33431 --- /dev/null +++ b/modules/syndication/queries/getModuleSiteInfo.xml @@ -0,0 +1,15 @@ + + +
+
+ + + + + + + + + + + diff --git a/modules/syndication/queries/getModules.xml b/modules/syndication/queries/getModules.xml new file mode 100644 index 000000000..ecb397cf4 --- /dev/null +++ b/modules/syndication/queries/getModules.xml @@ -0,0 +1,26 @@ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + +
diff --git a/modules/syndication/queries/getSiteUpdatedTime.xml b/modules/syndication/queries/getSiteUpdatedTime.xml new file mode 100644 index 000000000..4f902b736 --- /dev/null +++ b/modules/syndication/queries/getSiteUpdatedTime.xml @@ -0,0 +1,15 @@ + + + +
+ + + + + + + + + + + diff --git a/modules/syndication/queries/insertExceptModule.xml b/modules/syndication/queries/insertExceptModule.xml new file mode 100644 index 000000000..f50e0b818 --- /dev/null +++ b/modules/syndication/queries/insertExceptModule.xml @@ -0,0 +1,9 @@ + + +
+ + + + + + diff --git a/modules/syndication/queries/insertLog.xml b/modules/syndication/queries/insertLog.xml new file mode 100644 index 000000000..d8bd17086 --- /dev/null +++ b/modules/syndication/queries/insertLog.xml @@ -0,0 +1,13 @@ + + +
+ + + + + + + + + + diff --git a/modules/syndication/schemas/syndication_except_modules.xml b/modules/syndication/schemas/syndication_except_modules.xml new file mode 100644 index 000000000..afb5c516f --- /dev/null +++ b/modules/syndication/schemas/syndication_except_modules.xml @@ -0,0 +1,4 @@ +
+ + +
diff --git a/modules/syndication/schemas/syndication_logs.xml b/modules/syndication/schemas/syndication_logs.xml new file mode 100644 index 000000000..666c7b09e --- /dev/null +++ b/modules/syndication/schemas/syndication_logs.xml @@ -0,0 +1,8 @@ + + + + + + + +
diff --git a/modules/syndication/syndication.admin.controller.php b/modules/syndication/syndication.admin.controller.php new file mode 100644 index 000000000..c086d8760 --- /dev/null +++ b/modules/syndication/syndication.admin.controller.php @@ -0,0 +1,133 @@ +target_services = explode('|@|',Context::get('target_services')); + $config->site_url = preg_replace('/\/+$/is','',Context::get('site_url')); + $config->year = Context::get('year'); + if(!$config->site_url) return new Object(-1,'msg_site_url_is_null'); + + $oModuleController->insertModuleConfig('syndication',$config); + $oSyndicationController->ping($oSyndicationModel->getID('site'), 'site'); + + $except_module = Context::get('except_module'); + $output = executeQuery('syndication.deleteExceptModules'); + if(!$output->toBool()) return $output; + + $modules = explode(',',$except_module); + for($i=0,$c=count($modules);$i<$c;$i++) { + $args->module_srl = $modules[$i]; + $output = executeQuery('syndication.insertExceptModule',$args); + if(!$output->toBool()) return $output; + } + + $this->setMessage('success_applied'); + } + + function procSyndicationAdminCheckSitePingResult(){ + $site_url = trim(Context::get('site_url')); + if(!$site_url) return new Object(-1,'msg_invalid_request'); + + $oSyndicationModel = &getModel('syndication'); + + $id = $oSyndicationModel->getID('site'); + if(substr($site_url,-1)!='/') $site_url .= '/'; + $site_ping = sprintf('http://%s?module=syndication&act=getSyndicationList&id=%s&type=site', $site_url, $id); + + $headers = array(); + $headers['Connection'] = 'TE, close'; + $headers['User-Agent'] = 'Mozilla/4.0 (compatible; NaverBot/1.0; http://help.naver.com/customer_webtxt_02.jsp)'; + + $xml = FileHandler::getRemoteResource($site_ping, null, 3, 'GET', '', $headers); + if(!$xml) return new Object(-1, 'msg_ping_test_error'); + + $oXmlParser = new XmlParser(); + $oXml = $oXmlParser->parse($xml); + + if(!$oXml || !is_object($oXml) || !$oXml->entry || !$oXml->entry->id || !$oXml->entry->title) { + $this->setMessage('msg_ping_test_error'); + $this->add('ping_result',$xml); + }else{ + $this->setMessage('msg_success_ping_test'); + } + } + + function procSyndicationAdminCheckApiStatus(){ + $target_service = Context::get('target_service'); + if(!$target_service) return new Object(-1,'msg_invalid_request'); + + $status_url = trim($this->statuses[$target_service]); + if(!$status_url) return new Object(-1,'msg_syndication_status_not_support'); + + $oModuleModel = &getModel('module'); + + $config = $oModuleModel->getModuleConfig('syndication'); + $site_url = preg_replace('/^(http|https):\/\//i','',$config->site_url); + + $method = 'getSyndicationStatus' . ucfirst(strtolower($target_service)); + if(!method_exists(&$this, $method)) return new Object(-1,'msg_syndication_status_not_support'); + + $output = call_user_func(array(&$this,$method),$site_url); + if(!$output->toBool()) return $output; + + $this->add('result_status',$output->get('result_status')); + } + + function getSyndicationStatusNaver($site_url){ + $status_url = trim($this->statuses['Naver']); + + $xml = FileHandler::getRemoteResource(sprintf($status_url,$site_url), null, 3, 'GET', 'application/xml'); + $oXmlParser = new XmlParser(); + $oXml = $oXmlParser->parse($xml); + $oStatus = $oXml->syndication_status; + + if($oStatus->error->body != 0) return new Object(-1,$oStatus->message->body); + + $result->site_name = $oStatus->site_name->body; + $result->first_update = $oStatus->first_update->body; + $result->last_update = $oStatus->last_update->body; + $result->visit_ok_count = $oStatus->visit_ok_count->body; + $result->visit_fail_count = $oStatus->visit_fail_count->body; + $result->status = $oStatus->status->body; + + if(!$oStatus->sync || !$oStatus->sync->article){ + $oArticleList = array(); + }else{ + $oArticleList = $oStatus->sync->article; + if(!is_array($oArticleList)) $oArticleList = array($oArticleList); + } + + if(count($oArticleList)>0){ + $article_count = array(); + foreach($oArticleList as $article){ + $article_count[$article->attrs->date] = $article->body; + } + + $result->article_count = $article_count; + $result->max_article_count = max($result->article_count); + + } + + Context::set('result', $result); + $oTemplateHandler = &TemplateHandler::getInstance(); + $html = $oTemplateHandler->compile($this->module_path.'tpl', 'naver_result'); + + $output = new Object(); + $output->add('result_status', $html); + return $output; + } + } +?> diff --git a/modules/syndication/syndication.admin.view.php b/modules/syndication/syndication.admin.view.php new file mode 100644 index 000000000..dd93a34f7 --- /dev/null +++ b/modules/syndication/syndication.admin.view.php @@ -0,0 +1,50 @@ +getModuleConfig('syndication'); + if(!$module_config->target_services) $module_config->target_services = array(); + + foreach($this->services as $key => $val) { + unset($obj); + $obj->service = $key; + $obj->ping = $val; + $obj->selected = in_array($key, $module_config->target_services)?true:false; + $services[] = $obj; + } + Context::set('services', $services); + + if(!$module_config->site_url) { + $module_config->site_url = Context::getDefaultUrl()?Context::getDefaultUrl():getFullUrl(); + } + Context::set('site_url', preg_replace('/^(http|https):\/\//i','',$module_config->site_url)); + + if(!$module_config->year) { + $module_config->year = date("Y"); + } + Context::set('year', $module_config->year); + + $output = executeQueryArray('syndication.getExceptModules'); + $except_module_list = array(); + for($i=0,$c=count($output->data);$i<$c;$i++) { + $except_module_list[] = $output->data[$i]; + } + Context::set('except_module', $except_module_list); + + $this->setTemplatePath($this->module_path.'tpl'); + $this->setTemplateFile('config'); + } + + } +?> diff --git a/modules/syndication/syndication.class.php b/modules/syndication/syndication.class.php new file mode 100644 index 000000000..c311a9c6e --- /dev/null +++ b/modules/syndication/syndication.class.php @@ -0,0 +1,74 @@ + 'http://syndication.openapi.naver.com/ping/', + ); + + var $statuses = array( + 'Naver' => 'http://syndication.openapi.naver.com/status/?site=%s', + ); + + function moduleInstall() { + $oModuleController = &getController('module'); + $oModuleController->insertTrigger('document.insertDocument', 'syndication', 'controller', 'triggerInsertDocument', 'after'); + $oModuleController->insertTrigger('document.updateDocument', 'syndication', 'controller', 'triggerUpdateDocument', 'after'); + $oModuleController->insertTrigger('document.deleteDocument', 'syndication', 'controller', 'triggerDeleteDocument', 'after'); + $oModuleController->insertTrigger('module.deleteModule', 'syndication', 'controller', 'triggerDeleteModule', 'after'); + + $oModuleController->insertTrigger('document.moveDocumentToTrash', 'syndication', 'controller', 'triggerMoveDocumentToTrash', 'after'); + $oModuleController->insertTrigger('document.restoreTrash', 'syndication', 'controller', 'triggerRestoreTrash', 'after'); + + $oAddonAdminModel = &getAdminModel('addon'); + if($oAddonAdminModel->getAddonInfoXml('catpcha')){ + $oAddonAdminController = &addonAdminController::getInstance(); + $oAddonAdminController->doActivate('catpcha'); + $oAddonAdminController->makeCacheFile(); + } + } + + function checkUpdate() { + $oModuleModel = &getModel('module'); + if(!$oModuleModel->getTrigger('document.moveDocumentToTrash', 'syndication', 'controller', 'triggerMoveDocumentToTrash', 'after')) return true; + if(!$oModuleModel->getTrigger('document.restoreTrash', 'syndication', 'controller', 'triggerRestoreTrash', 'after')) return true; + + return false; + } + + function moduleUpdate() { + $oModuleModel = &getModel('module'); + $oModuleController = &getController('module'); + + if(!$oModuleModel->getTrigger('document.moveDocumentToTrash', 'syndication', 'controller', 'triggerMoveDocumentToTrash', 'after')){ + $oModuleController->insertTrigger('document.moveDocumentToTrash', 'syndication', 'controller', 'triggerMoveDocumentToTrash', 'after'); + } + if(!$oModuleModel->getTrigger('document.restoreTrash', 'syndication', 'controller', 'triggerRestoreTrash', 'after')){ + $oModuleController->insertTrigger('document.restoreTrash', 'syndication', 'controller', 'triggerRestoreTrash', 'after'); + } + + $oAddonAdminModel = &getAdminModel('addon'); + if($oAddonAdminModel->getAddonInfoXml('catpcha')){ + $oAddonAdminController = &addonAdminController::getInstance(); + $oAddonAdminController->doActivate('catpcha'); + $oAddonAdminController->makeCacheFile(); + } + + } + + function recompileCache() { + } + } +?> diff --git a/modules/syndication/syndication.controller.php b/modules/syndication/syndication.controller.php new file mode 100644 index 000000000..900429178 --- /dev/null +++ b/modules/syndication/syndication.controller.php @@ -0,0 +1,127 @@ +module_srl < 1) return new Object(); + + $oSyndicationModel = &getModel('syndication'); + $oModuleModel = &getModel('module'); + + if($oSyndicationModel->isExceptedModules($obj->module_srl)) return new Object(); + + $config = $oModuleModel->getModuleConfig('syndication'); + + $id = $oSyndicationModel->getID('channel', $obj->module_srl); + $this->ping($id, 'article'); + + return new Object(); + } + + function triggerUpdateDocument(&$obj) { + if($obj->module_srl < 1) return new Object(); + + $oSyndicationModel = &getModel('syndication'); + $oModuleModel = &getModel('module'); + + if($oSyndicationModel->isExceptedModules($obj->module_srl)) return new Object(); + + $config = $oModuleModel->getModuleConfig('syndication'); + + $id = $oSyndicationModel->getID('channel', $obj->module_srl); + $this->ping($id, 'article'); + + return new Object(); + } + + function triggerDeleteDocument(&$obj) { + if($obj->module_srl < 1) return new Object(); + + $oSyndicationModel = &getModel('syndication'); + $oModuleModel = &getModel('module'); + + if($oSyndicationModel->isExceptedModules($obj->module_srl)) return new Object(); + + $this->insertLog($obj->module_srl, $obj->document_srl, $obj->title, $obj->content); + + $id = $oSyndicationModel->getID('channel', $obj->module_srl); + $this->ping($id, 'deleted'); + + return new Object(); + } + + function triggerDeleteModule(&$obj) { + $oSyndicationModel = &getModel('syndication'); + $oModuleModel = &getModel('module'); + + if($oSyndicationModel->isExceptedModules($obj->module_srl)) return new Object(); + + $this->insertLog($obj->module_srl, $obj->document_srl, $obj->title, $obj->content); + + $output = executeQuery('syndication.getExceptModule', $obj); + if($output->data->count) return new Object(); + + $id = $oSyndicationModel->getID('site', $obj->module_srl); + $this->ping($id, 'deleted'); + + return new Object(); + } + + function triggerMoveDocumentToTrash(&$obj) { + $document_srl = $obj->document_srl; + $module_srl = $obj->module_srl; + + $oSyndicationModel = &getModel('syndication'); + $oModuleModel = &getModel('module'); + + if($oSyndicationModel->isExceptedModules($module_srl)) return new Object(); + + $id = $oSyndicationModel->getID('channel', $module_srl); + $this->ping($id, 'deleted'); + + return new Object(); + } + + function triggerRestoreTrash(&$obj) { + $document_srl = $obj->document_srl; + $module_srl = $obj->module_srl; + + $oSyndicationModel = &getModel('syndication'); + $oModuleModel = &getModel('module'); + + if($oSyndicationModel->isExceptedModules($module_srl)) return new Object(); + + $id = $oSyndicationModel->getID('article', $module_srl.'-'.$document_srl); + $this->ping($id, 'article'); + + return new Object(); + } + + function insertLog($module_srl, $document_srl, $title = null, $summary = null) { + $args->module_srl = $module_srl; + $args->document_srl = $document_srl; + $args->title = $title; + $args->summary = $summary; + $output = executeQuery('syndication.insertLog', $args); + } + + function ping($id, $type) { + $oModuleModel = &getModel('module'); + $config = $oModuleModel->getModuleConfig('syndication'); + + if(!count($config->target_services)) return; + if(substr($config->site_url,-1)!='/') $config->site_url .= '/'; + foreach($config->target_services as $key => $val) { + $ping_url = trim($this->services[$val]); + if(!$ping_url) continue; + $ping_body = sprintf('http://%s?module=syndication&act=getSyndicationList&id=%s&type=%s', $config->site_url, $id, $type); + FileHandler::getRemoteResource($ping_url, null, 3, 'POST', 'application/x-www-form-urlencoded', array(), array(), array('link'=>$ping_body)); + } + } + } +?> diff --git a/modules/syndication/syndication.model.php b/modules/syndication/syndication.model.php new file mode 100644 index 000000000..e7ca15ebf --- /dev/null +++ b/modules/syndication/syndication.model.php @@ -0,0 +1,363 @@ +getModuleConfig('syndication'); + $this->site_url = preg_replace('/\/+$/is','',$config->site_url); + $this->target_services = $config->target_services; + $this->year = $config->year; + + $output = executeQueryArray('syndication.getGrantedModules'); + if($output->data) { + foreach($output->data as $key => $val) { + $this->granted_modules[] = $val->module_srl; + } + } + } + + function isExceptedModules($module_srl) { + $args->module_srl = $module_srl; + $output = executeQuery('syndication.getExceptModule', $args); + if($output->data->count) return true; + $output = executeQuery('syndication.getGrantedModule', $args); + if($output->data->count) return true; + return false; + + } + + function getLang($key, $site_srl) + { + if(!$this->langs[$site_srl]) + { + $this->langs[$site_srl] = array(); + $args->site_srl = $site_srl; + $args->lang_code = Context::getLangType(); + $output = executeQueryArray("syndication.getLang", $args); + if(!$output->toBool() || !$output->data) return $key; + foreach($output->data as $value) + { + $this->langs[$site_srl][$value->name] = $value->value; + } + } + if($this->langs[$site_srl][$key]) + { + return $this->langs[$site_srl][$key]; + } + else return $key; + } + + function handleLang($title, $site_srl) + { + $matches = null; + if(!preg_match("/\\\$user_lang->(.+)/",$title, $matches)) return $title; + else + { + return $this->getLang($matches[1], $site_srl); + } + } + + function getSyndicationList() { + $oModuleModel = &getModel('module'); + $config = $oModuleModel->getModuleConfig('syndication'); + if(!$config->year || !$config->site_url) return new Object(-1,'msg_check_syndication_config'); + + $id = Context::get('id'); + $type = Context::get('type'); + $page = Context::get('page'); + if(!$id || !$type) return new Object(-1,'msg_invalid_request'); + + if(!preg_match('/^tag:([^,]+),([0-9]+):(site|channel|article)(.*)$/i',$id,$matches)) return new Object(-1,'msg_invalid_request'); + + $url = $matches[1]; + $year = $matches[2]; + $target = $matches[3]; + $id = $matches[4]; + if($id && $id{0}==':') $id = substr($id, 1); + + if($id && strpos($id,'-')!==false) list($module_srl, $document_srl) = explode('-',$id); + elseif($id) $module_srl = $id; + if(!$url || !$year || !$target) return new Object(-1,'msg_invalid_request'); + + $startTime = Context::get('start-time'); + $endTime = Context::get('end-time'); + + $time_zone = substr($GLOBALS['_time_zone'],0,3).':'.substr($GLOBALS['_time_zone'],3); + Context::set('time_zone', $time_zone); + + $site_module_info = Context::get('site_module_info'); + + if($target == 'channel' && !$module_srl) $target = 'site'; + if($target == 'channel' && $module_srl) { + $args->module_srls = $module_srl; + $output = executeQuery('syndication.getModules', $args); + $module_info = $output->data; + if($module_info) { + $args->module_srl = $module_srl; + $output = executeQuery('syndication.getExceptModules', $args); + if($output->data->count) $error = 'target is not founded'; + } else $error = 'target is not founded'; + + unset($args); + } + + if(!$error) { + Context::set('target', $target); + Context::set('type', $type); + switch($target) { + case 'site' : + $site_info->id = $this->getID('site'); + $site_info->title = $this->handleLang($site_module_info->browser_title, $site_module_info->site_srl); + + $output = executeQuery('syndication.getSiteUpdatedTime'); + if($output->data) $site_info->updated = date("Y-m-d\\TH:i:s", ztime($output->data->last_update)).$time_zone; + $site_info->self_href = $this->getSelfHref($site_info->id,$type); + $site_info->alternative_href =$this->getAlternativeHref(); + Context::set('site_info', $site_info); + + $this->setTemplateFile('site'); + switch($type) { + case 'channel' : + Context::set('channels', $this->getChannels()); + break; + case 'article' : + Context::set('articles', $this->getArticles(null, $page, $startTime, $endTime, 'article',$site_info->id)); + break; + case 'deleted' : + Context::set('deleted', $this->getDeleted(null, $page, $startTime, $endTime, 'deleted',$site_info->id)); + break; + default : + $this->setTemplateFile('site.info'); + break; + } + break; + case 'channel' : + $channel_info->id = $this->getID('channel', $module_info->module_srl); + $channel_info->title = $this->handleLang($module_info->browser_title, $module_info->site_srl); + $channel_info->updated = date("Y-m-d\\TH:i:s").$time_zone; + $channel_info->self_href = $this->getSelfHref($channel_info->id, $type); + $channel_info->alternative_href = $this->getAlternativeHref($module_info); + $channel_info->summary = $module_info->description; + if($module_info->module == "textyle") + { + $channel_info->type = "blog"; + $channel_info->rss_href = getFullSiteUrl($module_info->domain, '', 'mid', $module_info->mid, 'act', 'rss'); + } + else + { + $channel_info->type = "web"; + } + $output = executeQuery('syndication.getSiteUpdatedTime'); + if($output->data) $channel_info->updated = date("Y-m-d\\TH:i:s", ztime($output->data->last_update)).$time_zone; + Context::set('channel_info', $channel_info); + + $this->setTemplateFile('channel'); + switch($type) { + case 'article' : + Context::set('articles', $this->getArticles($module_srl, $page, $startTime, $endTime, 'article', $channel_info->id)); + break; + case 'deleted' : + Context::set('deleted', $this->getDeleted($module_srl, $page, $startTime, $endTime, 'deleted', $channel_info->id)); + break; + default : + $this->setTemplateFile('channel.info'); + break; + } + break; + + case 'article': + Context::set('article', $this->getArticle($document_srl)); + $this->setTemplateFile('include.articles'); + break; + } + } else { + Context::set('message', $error); + $this->setTemplateFile('error'); + } + + $this->setTemplatePath($this->module_path.'tpl'); + Context::setResponseMethod('XMLRPC'); + } + + function getChannels() { + if($module_srls) $args->module_srls = $module_srls; + if(count($this->granted_modules)) $args->except_module_srls = implode(',',$this->granted_modules); + $output = executeQueryArray('syndication.getModules', $args); + if($output->data) { + foreach($output->data as $module_info) { + unset($obj); + $obj->id = $this->getID('channel', $module_info->module_srl); + $obj->title = $this->handleLang($module_info->browser_title, $module_info->site_srl); + $obj->updated = date("Y-m-d\\TH:i:s").$time_zone; + $obj->self_href = $this->getSelfHref($obj->id, 'channel'); + $obj->alternative_href = $this->getAlternativeHref($module_info); + $obj->summary = $module_info->description; + if($module_info->module == "textyle") + { + $obj->type = "blog"; + $obj->rss_href = getFullSiteUrl($module_info->domain, '', 'mid', $module_info->mid, 'act', 'rss'); + } + else + { + $obj->type = "web"; + } + + $list[] = $obj; + } + } + return $list; + } + + function getArticle($document_srl) { + if($this->site_url==null) $this->init(); + + $oDocumentModel = &getModel('document'); + $oDocument = $oDocumentModel->getDocument($document_srl,false,false); + if(!$oDocument->isExists()) return; + + $val = $oDocument->getObjectVars(); + + $val->id = $this->getID('article', $val->module_srl.'-'.$val->document_srl); + $val->updated = date("Y-m-d\\TH:i:s", ztime($val->last_update)).$GLOBALS['_time_zone']; + $val->alternative_href = getFullSiteUrl($this->site_url, '', 'document_srl', $val->document_srl); + $val->channel_alternative_href = $this->getChannelAlternativeHref($val->module_srl); + $val->channel_id = $this->getID('channel', $val->module_srl.'-'.$val->document_srl); + if(!$val->nick_name) $val->nick_name = $val->user_name; + + return $val; + } + + function getArticles($module_srl = null, $page=1, $startTime = null, $endTime = null, $type = null, $id = null) { + if($this->site_url==null) $this->init(); + + if($module_srl) $args->module_srl = $module_srl; + if($startTime) $args->start_date = $this->getDate($startTime); + if($endTime) $args->end_date = $this->getDate($endTime); + if(count($this->granted_modules)) $args->except_module_srls = implode(',',$this->granted_modules); + $args->page = $page; + $output = executeQueryArray('syndication.getDocumentList', $args); + $cur_page = $output->page_navigation->cur_page; + $total_page = $output->page_navigation->last_page; + + $result->next_url = null; + $result->list = array(); + + if($cur_page<$total_page) { + $next_url = $this->getSelfHref($id, $type); + if($startTime) $next_url .= '&startTime='.$startTime; + if($endTime) $next_url .= '&endTime='.$endTime; + $result->next_url = $next_url.'&page='.($cur_page+1); + } + + if($output->data) { + foreach($output->data as $key => $val) { + $val->id = $this->getID('article', $val->module_srl.'-'.$val->document_srl); + $val->updated = date("Y-m-d\\TH:i:s", ztime($val->last_update)).$GLOBALS['_time_zone']; + $val->alternative_href = getFullSiteUrl($this->site_url, '', 'document_srl', $val->document_srl); + $val->channel_alternative_href = $this->getChannelAlternativeHref($val->module_srl); + $val->channel_id = $this->getID('channel', $val->module_srl.'-'.$val->document_srl); + if(!$val->nick_name) $val->nick_name = $val->user_name; + $output->data[$key] = $val; + } + $result->list = $output->data; + } + return $result; + } + + function getDeleted($module_srl = null, $page = 1, $startTime = null, $endTime = null, $type = null, $id = null) { + if($this->site_url==null) $this->init(); + + if($module_srl) $args->module_srl= $module_srl; + if($startTime) $args->start_date = $this->getDate($startTime); + if($endTime) $args->end_date = $this->getDate($endTime); + $args->page = $page; + + $output = executeQueryArray('syndication.getDeletedList', $args); + + $cur_page = $output->page_navigation->cur_page; + $total_page = $output->page_navigation->last_page; + + $result->next_url = null; + $result->list = array(); + + if($cur_page<$total_page) { + $next_url = $this->getSelfHref($id, $type); + if($startTime) $next_url .= '&startTime='.$startTime; + if($endTime) $next_url .= '&endTime='.$endTime; + $result->next_url = $next_url . '&page='.($cur_page+1); + } + + if($output->data) { + foreach($output->data as $key => $val) { + $val->id = $this->getID('article', $val->module_srl.'-'.$val->document_srl); + $val->deleted = date("Y-m-d\\TH:i:s", ztime($val->regdate)).$GLOBALS['_time_zone']; + $val->alternative_href = getFullSiteUrl($this->site_url, '', 'document_srl', $val->document_srl); + $val->channel_id = $this->getID('channel', $val->module_srl.'-'.$val->document_srl); + $output->data[$key] = $val; + } + $result->list = $output->data; + } + return $result; + } + + function getID($type, $target_id = null) { + if($this->site_url==null) $this->init(); + + return sprintf('tag:%s,%d:%s', $this->site_url, $this->year, $type) . ($target_id?':'.$target_id:''); + } + + function getChannelAlternativeHref($module_srl) { + static $module_info = array(); + if(!isset($module_info[$module_srl])) { + $args->module_srl = $module_srl; + $output = executeQuery('syndication.getModuleSiteInfo', $args); + if($output->data) $module_info[$module_srl] = $output->data; + else $module_info[$module_srl] = null; + } + + if(is_null($module_info[$module_srl])) return $this->site_url; + + $domain = $module_info[$module_srl]->domain; + $url = getFullSiteUrl($domain, '', 'mid', $module_info[$module_srl]->mid); + if(substr($url,0,1)=='/') $domain = 'http://'.$this->site_url.$url; + return $url; + } + + function getSelfHref($id, $type = null) { + if($this->site_url==null) $this->init(); + + return sprintf('http://%s/?module=syndication&act=getSyndicationList&id=%s&type=%s', $this->site_url, $id, $type); + } + + function getAlternativeHref($module_info = null) { + if($this->site_url==null) $this->init(); + + if(!$module_info) return sprintf('http://%s', $this->site_url); + if(!$module_info->site_srl) return getFullUrl('', 'mid', $module_info->mid); + + $domain = $module_info->domain; + $url = getFullSiteUrl($domain, '', 'mid', $module_info->mid); + + if(substr($url,0,1)=='/') $domain = 'http://'.$this->site_url.$url; + return $url; + } + + function getDate($date) { + $time = strtotime($date); + if($time == -1) $time = ztime(str_replace(array('-','T',':'),'',$date)); + return date('YmdHis', $time); + } + } +?> diff --git a/modules/syndication/tpl/channel.html b/modules/syndication/tpl/channel.html new file mode 100644 index 000000000..55cf2b34d --- /dev/null +++ b/modules/syndication/tpl/channel.html @@ -0,0 +1,16 @@ +{''} + + + + + + + + + + + + + + + diff --git a/modules/syndication/tpl/channel.info.html b/modules/syndication/tpl/channel.info.html new file mode 100644 index 000000000..c8543d979 --- /dev/null +++ b/modules/syndication/tpl/channel.info.html @@ -0,0 +1,5 @@ +{''} + + + + diff --git a/modules/syndication/tpl/config.html b/modules/syndication/tpl/config.html new file mode 100644 index 000000000..96c15e98d --- /dev/null +++ b/modules/syndication/tpl/config.html @@ -0,0 +1,60 @@ + + + + +

{$lang->syndication} {$lang->cmd_management}

+

{$lang->about_syndication}

+ +
+ + + + + + + + + + + + + + + + + +
{$lang->my_syndication_url}
+ http:// + +

{$lang->about_my_syndication_url}

+

+
{$lang->syndication_service}
+
    + +
  • + selected)-->checked="checked" /> + + +
  • + +
+ +

{$lang->about_syndication}

+
{$lang->except_module}
+ + +

{$lang->about_except_module}

+ +
+ +
+
diff --git a/modules/syndication/tpl/css/syndication.css b/modules/syndication/tpl/css/syndication.css new file mode 100644 index 000000000..1a6213680 --- /dev/null +++ b/modules/syndication/tpl/css/syndication.css @@ -0,0 +1,17 @@ +@charset "utf-8"; + +input.siteUrl { width:400px; } +ul.syndiService { list-style:none; margin:0; padding:0;} +ul.syndiService li { padding:10px 0; margin:0;} +select.exceptModuleList { width:400px; } +ul.midCommand { margin:20px 0 0 0; padding:0; list-style:none; } +ul.midCommand li { display:inline; margin:0 20px 0 0; padding:0;} + +/* Vertical Bar Graph */ +.vGraph{ padding:20px 0;} +.vGraph ul{ margin:0; padding:0; height:100px; border:1px solid #ddd; border-top:0; border-right:0; font-size:11px; font-family:Tahoma, Geneva, sans-serif; list-style:none;} +.vGraph ul:after{ content:""; display:block; clear:both;} +.vGraph li{ float:left; display:inline; width:8%; height:100%; margin:0 3%; position:relative; text-align:center; white-space:nowrap;} +.vGraph .gTerm{ position:relative; display:inline-block; width:100%; height:20px; line-height:20px; margin:0 -100% -20px 0; padding:100px 0 0 0; vertical-align:bottom; color:#767676; font-weight:bold;} +.vGraph .gBar{ position:relative; display:inline-block; width:100%; margin:-1px 0 0 0; border:1px solid #ccc; border-bottom:0; background:#e9e9e9; vertical-align:bottom;} +.vGraph .gBar span{ position:absolute; width:100%; top:-20px; left:0; color:#767676;} diff --git a/modules/syndication/tpl/error.html b/modules/syndication/tpl/error.html new file mode 100644 index 000000000..e641f1dcb --- /dev/null +++ b/modules/syndication/tpl/error.html @@ -0,0 +1,5 @@ +{''} + + -1 + {$message} + diff --git a/modules/syndication/tpl/filter/insert_service.xml b/modules/syndication/tpl/filter/insert_service.xml new file mode 100644 index 000000000..b81953e60 --- /dev/null +++ b/modules/syndication/tpl/filter/insert_service.xml @@ -0,0 +1,8 @@ + +
+ + + + + + diff --git a/modules/syndication/tpl/include.articles.html b/modules/syndication/tpl/include.articles.html new file mode 100644 index 000000000..2d501a39f --- /dev/null +++ b/modules/syndication/tpl/include.articles.html @@ -0,0 +1,14 @@ + + + {htmlspecialchars($article->id)} + {htmlspecialchars($article->title)} + {$article->updated} + + + + {date('Y-m-d\TH:i:s',ztime($article->regdate)).$time_zone} + + {htmlspecialchars($article->nick_name)} + + {htmlspecialchars($article->content)} + diff --git a/modules/syndication/tpl/include.channel.html b/modules/syndication/tpl/include.channel.html new file mode 100644 index 000000000..4ead02593 --- /dev/null +++ b/modules/syndication/tpl/include.channel.html @@ -0,0 +1,8 @@ + {htmlspecialchars($channel_info->id)} + {htmlspecialchars($channel_info->title)} + {$channel_info->updated} + + + + {$channel_info->type} + {htmlspecialchars($channel_info->summary)} diff --git a/modules/syndication/tpl/include.channels.html b/modules/syndication/tpl/include.channels.html new file mode 100644 index 000000000..76a6a42cb --- /dev/null +++ b/modules/syndication/tpl/include.channels.html @@ -0,0 +1,8 @@ + + {htmlspecialchars($channel_info->id)} + {htmlspecialchars($channel_info->title)} + {$channel_info->updated} + + + {htmlspecialchars($channel_info->summary)} + diff --git a/modules/syndication/tpl/include.deleted.html b/modules/syndication/tpl/include.deleted.html new file mode 100644 index 000000000..c3bce73a8 --- /dev/null +++ b/modules/syndication/tpl/include.deleted.html @@ -0,0 +1,8 @@ + + + {htmlspecialchars($delete->id)} + {htmlspecialchars($delete->title)} + {$delete->deleted} + + {$delete->deleted} + diff --git a/modules/syndication/tpl/include.site.html b/modules/syndication/tpl/include.site.html new file mode 100644 index 000000000..a8499e0c5 --- /dev/null +++ b/modules/syndication/tpl/include.site.html @@ -0,0 +1,5 @@ + {htmlspecialchars($site_info->id)} + {htmlspecialchars($site_info->title)} + {$site_info->updated} + + diff --git a/modules/syndication/tpl/js/syndication.js b/modules/syndication/tpl/js/syndication.js new file mode 100644 index 000000000..7af234ac8 --- /dev/null +++ b/modules/syndication/tpl/js/syndication.js @@ -0,0 +1,55 @@ +function insertSelectedModules(id, module_srl, mid, browser_title) { + var sel_obj = xGetElementById('_'+id); + for(var i=0;i8) sel_obj.size = sel_obj.options.length; + + doSyncExceptModules(id); +} + +function removeExceptModule(id) { + var sel_obj = xGetElementById('_'+id); + sel_obj.remove(sel_obj.selectedIndex); + if(sel_obj.options.length) sel_obj.selectedIndex = sel_obj.options.length-1; + doSyncExceptModules(id); +} + +function doSyncExceptModules(id) { + var selected_module_srls = new Array(); + var sel_obj = xGetElementById('_'+id); + for(var i=0;iNaver Syndication Status + +

{$lang->syndication_status_result}

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
{$lang->site}{$result->site_name}
{$lang->syndication_status}{$result->status}
{$lang->syndication_synic_start_date}{$result->first_update}
{$lang->syndication_synic_last_date}{$result->last_update}
{$lang->syndication_visit_ok_count}{number_format($result->visit_ok_count)}
{$lang->syndication_visit_fail_count}{number_format($result->visit_fail_count)}
+

{$lang->syndication_sync_article}

+
+ +
    + +
  • {$date}{number_format($count)}
  • + +
+ +
diff --git a/modules/syndication/tpl/site.html b/modules/syndication/tpl/site.html new file mode 100644 index 000000000..04fa4e46f --- /dev/null +++ b/modules/syndication/tpl/site.html @@ -0,0 +1,21 @@ +{''} + + + + + + + + + + + + + + + + + + + + diff --git a/modules/syndication/tpl/site.info.html b/modules/syndication/tpl/site.info.html new file mode 100644 index 000000000..d4aff8112 --- /dev/null +++ b/modules/syndication/tpl/site.info.html @@ -0,0 +1,4 @@ +{''} + + + diff --git a/widgets/mcontent/conf/info.xml b/widgets/mcontent/conf/info.xml new file mode 100644 index 000000000..0642daeb1 --- /dev/null +++ b/widgets/mcontent/conf/info.xml @@ -0,0 +1,490 @@ + + + 모바일 콘텐츠 위젯 + Mobile Content Widget + Nội dung + 全局内容控件 + 內容 + コンテンツウィジェット + 게시판, 코멘트, 첨부파일 등 Content를 출력하는 위젯입니다. + This widget displays Content such as articles, comments, or attached files. + Widget này sẽ hiển thị những bài viết, bình luận, File đính kèm. + 以各种样式显示主题,评论,附件等站内内容的全局控件。 + 這個 Widget 可輸出討論板、評論,附加檔案等內容。 + 掲示板の書き込み、コメント、添付ファイルなどコンテンツを出力するウィジェットです。 + 0.1 + 2009-03-16 + + + sol + sol + sol + sol + sol + sol + sol + sol + + + + + select + 추출대상 + Target + Khu vực + 对象 + 目標 + 抽出対象 + + document + 게시물 + Article + Bài viết + 主题 + 主題 + 書き込み + + + comment + 댓글 + Comment + Bình luận + 评论 + 評論 + コメント + + + image + 첨부이미지 + Attached Image + Hình đính kèm + 图片 + 圖片 + 添付イメージ + + + trackback + 트랙백 + Trackback + Liên kết Web + 引用 + 引用 + トラックバック + + + rss + 피드 (RSS/ATOM) + Feed (RSS/ATOM) + Feed (RSS/ATOM) + Feed (RSS/ATOM) + Feed (RSS/ATOM) + Feed (RSS/ATOM) + + + + select + 내용형태 + Content Type + Kiểu hiển thị + 内容样式 + 內容樣式 + 内容のタイプ + + normal + 제목 + Title + Tiêu đề + 标题 + 標題 + タイトル + + + image_title + 이미지+제목 + Image+Title + Hình ảnh+Tiêu đề + 图片+标题 + 圖片+標題 + 画像+タイトル + + + image_title_content + 이미지+제목+내용 + Image+Title+Content + Hình ảnh+Tiêu đề+Nội dung + 图片+标题+内容 + 圖片+標題+內容 + 画像+タイトル+内容 + + + + select-multi-order + 표시항목 + Display Target & Order + Hiển thị khu vực và thứ tự + 显示项及顺序 + 顯示項目順序 + 表示項目、および順番 + + title + 제목 + Title + Tiêu đề + 标题 + 標題 + タイトル + + + thumbnail + 섬네일 + Thumbnail + Hình nhỏ + 缩略图 + 縮圖 + サムネール + + + regdate + 등록일 + Regdate + Ngày gửi + 发布日期 + 發表日期 + 登録日 + + + nickname + 글쓴이 + Author + Người gửi + 发布者 + 作者 + 登録者 + + + content + 내용 + Content + Nội dung + 内容 + 內容 + 内容 + + + + select + 게시판 이름 표시 + Display Article Name + Tên bài viết + 显示版面名称 + 討論板名稱 + 掲示板名の表示 + + Y + 출력 + Display + Hiển thị + 显示 + 顯示 + 表示 + + + N + 출력하지 않음 + No Display + Không hiển thị + 不显示 + 不顯示 + 表示しない + + + + select + 댓글수 표시 + Comment Count + Số bình luận + 显示评论数 + 評論數 + コメント数 + + Y + 출력 + Display + Hiển thị + 显示 + 顯示 + 表示 + + + N + 출력하지 않음 + No Display + Không hiển thị + 不显示 + 不顯示 + 表示しない + + + + select + 엮인글수 표시 + Trackback + Liên kết Web + 显示引用数 + 引用數 + トラックバック数の表示 + + Y + 출력 + Display + Hiển thị + 显示 + 顯示 + 表示 + + + N + 출력하지 않음 + No Display + Không hiển thị + 不显示 + 不顯示 + 表示しない + + + + select + 분류 표시 + Category + Thể loại + 显示分类 + 分類 + カテゴリ表示 + + Y + 출력 + Display + Hiển thị + 显示 + 顯示 + 表示 + + + N + 출력하지 않음 + No Display + Không hiển thị + 不显示 + 不顯示 + 表示しない + + + + select + 정렬 대상 + 排序对象 + ソート対象 + Target to be sorted + Phân loại + Objetivo para ser ordenados + Назначение для сортировки + 排列順序 + 등록된 순서 또는 변경된 순서로 정렬을 할 수 있습니다. + 可以按照指定的顺序进行排序。 + 登録順、または変更順にソートします。 + The list of newewst articles may be sorted by submitted order or modified order. + Danh sách bài viết mới nhất có thể được được phân loại bởi danh sách đã gửi hay đã sửa. + La lista de los documentos recientes pueden ser ordenados en el orden del agregado o en el de modificados. + Список последних статей может быть отсортирован по дате размещения или изменения. + 按照指定的順序進行排列。 + + list_order + 최신 등록순 + 最新发表顺 + 最新登録順 + Newest Submitted Order + Bài mới gửi + Orden de agregados recientemente + Порядок размещенных статей + 最新發表 + + + update_order + 최근 변경순 + 最新修改顺 + 最新変更順 + Newest Modified Order + Bài mới sửa + Orden de modificados recientemente + Порядок измененных статей + 最新修改 + + + + select + 정렬 방법 + 排序方式 + ソートタイプ + Sorting Type + Kiểu sắp xếp + Tipo de ordenamiento + Тип сортировки + 排列方式 + 정렬대상을 내림차순 또는 올림차순으로 정렬할 수 있습니다. + 对其排序对象可进行升序/降序方式排序。 + ソートタイプを、降順、または昇順に設定します。 + You can sort target articles by ascending or descending order. + Bạn có thể phân loại bài viết theo kiểu tăng hay giảm. + Usted puede ordenar los documentos en orden acendente o en orden descendente. + Вы можете сортировать статьи в порядке возрастания или убывания. + 可選擇升冪/降冪的方式對所選目標進行排列。 + + desc + 내림차순 + 降序 + 降順 + Descending order + Giảm dần + Orden Descendente + По убыванию + 降冪 + + + asc + 올림차순 + 升序 + 昇順 + Ascending order + Tăng dần + Orden Acendente + По возрастанию + 升冪 + + + + text + 목록수 + 目录数 + リスト数 + The number of list + Số bài hiển thị + Número de la lista + Число списка + 目錄數 + 출력될 목록의 수를 정하실 수 있습니다. (기본 5개) + 可设置要显示的目录数。 (默认为5个) + 出力するリスト数を指定します(デフォルト5個)。 + You can set the number of articles to be displayed. (default is 5) + Bạn có thể đặt số bài hiển thị. (Mặc định là 5) + Usted puede definir el número de los documentos a mostrar. (predefinido: 5) + Вы можете выбрать число списка статей для отображения. (стандарт: 5) + 設置要顯示的目錄數。(預設是5個) + + + text + 제목 글자수 + タイトルの文字数 + 标题字数 + Length of Subject + Độ dài tiêu đề + Número de letras del título + Длина темы + 標題字數 + 제목 글자수를 지정할 수 있습니다. (0또는 비워주시면 자르지 않습니다) + タイトルの文字数を設定します(「0」または空欄の場合は、文字数を制限しません)。 + 可以设置标题的字数。(0或留空为不限) + Length of Subject can be assigned. (0 or blank value will not restrict the length) + Có thể tăng thêm chiều dài của tiêu đề. (Đặt là 0 hoặc để trống nếu không giới hạn tiêu đề). + El largo del título puede ser asignado. (valor 0 o en blanco no restringe el largo) + Длина темы может быть присвоена. (0 или пустое значение не будут ограничивать длину) + 可設置標題的字數。(0或留白為不限制) + + + text + 내용 글자수 + Content Length + Độ dài nội dung + 内容の文字数 + 内容摘要字数 + 內容字數 + + + module_srl_list + 대상 모듈 + 对象模块 + モジュール + Target Module + Chèn Module + Módulo Objetivo + Модуль назначения + 目標模組 + 선택하신 모듈에 등록된 글을 대상으로 합니다. + チェックされたモジュールに登録されたコンテンツ(書き込み)を対象とします。 + 将把所选模块当中的主题作为对象。 + The target articles to be sorted will be the ones submitted in the selected module. + Những bài viết sẽ được phân loại và hiển thị khi có bài mới gửi trong những Module đã chọn. + El objetivo de los documentos agregados serán los del módulo selccionado. + Статьи назначения для сортировки будут теми, что были размещены в выбранном модуле. + 把所選擇的模組作為目標。 + + + text + 피드(RSS/ATOM) 주소 + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + 피드 주소는 타입이 지원하는 문서 형식일 경우에만 등록 됩니다. + (지원 문서 형식 : RSS 2.0, RSS 1.0, ATOM 1.0) + 请输入RSS格式地址。 + (支持文档格式 : RSS 2.0, RSS 1.0, ATOM 1.0) + Chỉ hỗ trợ những định dạng được dăng kí. (RSS 2.0 RSS 1.0 ATOM 1.0). + RSS URLはタイプが RSSの時だけ登録出来ます。 + (サポートする文書形式 : RSS 2.0, RSS 1.0, ATOM 1.0) + 請輸入 RSS 位址。 + (支援檔案格式 : RSS 2.0, RSS 1.0, ATOM 1.0) + + + text + 피드(RSS/ATOM) 주소 + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + + + text + 피드(RSS/ATOM) 주소 + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + + + text + 피드(RSS/ATOM) 주소 + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + + + text + 피드(RSS/ATOM) 주소 + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + Feed(RSS/ATOM) URL + + + diff --git a/widgets/mcontent/mcontent.class.php b/widgets/mcontent/mcontent.class.php new file mode 100644 index 000000000..cf0c3a983 --- /dev/null +++ b/widgets/mcontent/mcontent.class.php @@ -0,0 +1,748 @@ +order_target, array('list_order','update_order'))) $args->order_target = 'list_order'; + + // 정렬 순서 + if(!in_array($args->order_type, array('asc','desc'))) $args->order_type = 'asc'; + + // 출력된 목록 수 + $args->list_count = (int)$args->list_count; + if(!$args->list_count) $args->list_count = 5; + + // 제목 길이 자르기 + if(!$args->subject_cut_size) $args->subject_cut_size = 0; + + // 내용 길이 자르기 + if(!$args->content_cut_size) $args->content_cut_size = 100; + + // 보기 옵션 + $args->option_view_arr = explode(',',$args->option_view); + + // markup 옵션 + if(!$args->markup_type) $args->markup_type = 'list'; + + // 내부적으로 쓰이는 변수 설정 + $oModuleModel = &getModel('module'); + $module_srls = $args->modules_info = $args->module_srls_info = $args->mid_lists = array(); + $site_module_info = Context::get('site_module_info'); + + // rss 인 경우 URL정리 + if($args->content_type == 'rss'){ + $args->rss_urls = array(); + $rss_urls = array_unique(array($args->rss_url0,$args->rss_url1,$args->rss_url2,$args->rss_url3,$args->rss_url4)); + for($i=0,$c=count($rss_urls);$i<$c;$i++) { + if($rss_urls[$i]) $args->rss_urls[] = $rss_urls[$i]; + } + + // rss가 아닌 XE모듈일 경우 모듈 번호 정리 후 모듈 정보 구함 + } else { + + // 대상 모듈이 선택되어 있지 않으면 해당 사이트의 전체 모듈을 대상으로 함 + if(!$args->module_srls){ + unset($obj); + $obj->site_srl = (int)$site_module_info->site_srl; + $output = executeQueryArray('widgets.content.getMids', $obj); + if($output->data) { + foreach($output->data as $key => $val) { + $args->modules_info[$val->mid] = $val; + $args->module_srls_info[$val->module_srl] = $val; + $args->mid_lists[$val->module_srl] = $val->mid; + $module_srls[] = $val->module_srl; + } + } + + $args->modules_info = $oModuleModel->getMidList($obj); + // 대상 모듈이 선택되어 있으면 해당 모듈만 추출 + } else { + $obj->module_srls = $args->module_srls; + $output = executeQueryArray('widgets.content.getMids', $obj); + if($output->data) { + foreach($output->data as $key => $val) { + $args->modules_info[$val->mid] = $val; + $args->module_srls_info[$val->module_srl] = $val; + $module_srls[] = $val->module_srl; + } + $idx = explode(',',$args->module_srls); + for($i=0,$c=count($idx);$i<$c;$i++) { + $srl = $idx[$i]; + if(!$args->module_srls_info[$srl]) continue; + $args->mid_lists[$srl] = $args->module_srls_info[$srl]->mid; + } + } + } + + // 아무런 모듈도 검색되지 않았다면 종료 + if(!count($args->modules_info)) return Context::get('msg_not_founded'); + $args->module_srl = implode(',',$module_srls); + } + + /** + * 컨텐츠 추출, 게시글/댓글/엮인글/RSS등 다양한 요소가 있어서 각 method를 따로 만듬 + **/ + // tab 형태 + if($args->tab_type == 'none' || $args->tab_type == '') { + switch($args->content_type){ + case 'comment': + $content_items = $this->_getCommentItems($args); + break; + case 'image': + $content_items = $this->_getImageItems($args); + break; + case 'rss': + $content_items = $this->getRssItems($args); + break; + case 'trackback': + $content_items = $this->_getTrackbackItems($args); + break; + default: + $content_items = $this->_getDocumentItems($args); + break; + } + // tab 형태가 아닐 경우 + } else { + $content_items = array(); + + switch($args->content_type){ + case 'comment': + foreach($args->mid_lists as $module_srl => $mid){ + $args->module_srl = $module_srl; + $content_items[$module_srl] = $this->_getCommentItems($args); + } + break; + case 'image': + foreach($args->mid_lists as $module_srl => $mid){ + $args->module_srl = $module_srl; + $content_items[$module_srl] = $this->_getImageItems($args); + } + break; + case 'rss': + $content_items = $this->getRssItems($args); + break; + case 'trackback': + foreach($args->mid_lists as $module_srl => $mid){ + $args->module_srl = $module_srl; + $content_items[$module_srl] = $this->_getTrackbackItems($args); + } + break; + default: + foreach($args->mid_lists as $module_srl => $mid){ + $args->module_srl = $module_srl; + $content_items[$module_srl] = $this->_getDocumentItems($args); + } + break; + } + } + + $output = $this->_compile($args,$content_items); + return $output; + } + + /** + * @brief 댓글 목록을 추출하여 mcontentItem으로 return + **/ + function _getCommentItems($args) { + // CommentModel::getCommentList()를 이용하기 위한 변수 정리 + $obj->module_srl = $args->module_srl; + $obj->sort_index = $args->order_target; + $obj->list_count = $args->list_count; + + // comment 모듈의 model 객체를 받아서 getCommentList() method를 실행 + $oCommentModel = &getModel('comment'); + $output = $oCommentModel->getNewestCommentList($obj); + + $content_items = array(); + + if(!count($output)) return; + + foreach($output as $key => $oComment) { + $attribute = $oComment->getObjectVars(); + $title = $oComment->getSummary($args->content_cut_size); + $thumbnail = $oComment->getThumbnail(); + $url = sprintf("%s#comment_%s",getUrl('','document_srl',$oComment->get('document_srl')),$oComment->get('comment_srl')); + + $attribute->mid = $args->mid_lists[$attribute->module_srl]; + $browser_title = $args->module_srls_info[$attribute->module_srl]->browser_title; + $domain = $args->module_srls_info[$attribute->module_srl]->domain; + + $content_item = new mcontentItem($browser_title); + $content_item->adds($attribute); + $content_item->setTitle($title); + $content_item->setThumbnail($thumbnail); + $content_item->setLink($url); + $content_item->setDomain($domain); + $content_item->add('mid', $args->mid_lists[$attribute->module_srl]); + $content_items[] = $content_item; + } + return $content_items; + } + + function _getDocumentItems($args){ + // document 모듈의 model 객체를 받아서 결과를 객체화 시킴 + $oDocumentModel = &getModel('document'); + + // 분류 구함 + $obj->module_srl = $args->module_srl; + $output = executeQueryArray('widgets.content.getCategories',$obj); + if($output->toBool() && $output->data) { + foreach($output->data as $key => $val) { + $category_lists[$val->module_srl][$val->category_srl] = $val; + } + } + + // 글 목록을 구함 + $obj->module_srl = $args->module_srl; + $obj->sort_index = $args->order_target; + $obj->order_type = $args->order_type=="desc"?"asc":"desc"; + $obj->list_count = $args->list_count; + $output = executeQueryArray('widgets.content.getNewestDocuments', $obj); + if(!$output->toBool() || !$output->data) return; + + // 결과가 있으면 각 문서 객체화를 시킴 + $content_items = array(); + $first_thumbnail_idx = -1; + if(count($output->data)) { + foreach($output->data as $key => $attribute) { + $oDocument = new documentItem(); + $oDocument->setAttribute($attribute, false); + $GLOBALS['XE_DOCUMENT_LIST'][$oDocument->document_srl] = $oDocument; + $document_srls[] = $oDocument->document_srl; + } + $oDocumentModel->setToAllDocumentExtraVars(); + + for($i=0,$c=count($document_srls);$i<$c;$i++) { + $oDocument = $GLOBALS['XE_DOCUMENT_LIST'][$document_srls[$i]]; + $document_srl = $oDocument->document_srl; + $module_srl = $oDocument->get('module_srl'); + $category_srl = $oDocument->get('category_srl'); + $thumbnail = $oDocument->getThumbnail(); + $content_item = new mcontentItem( $args->module_srls_info[$module_srl]->browser_title ); + $content_item->adds($oDocument->getObjectVars()); + $content_item->setTitle($oDocument->getTitle()); + $content_item->setCategory( $category_lists[$module_srl][$category_srl]->title ); + $content_item->setDomain( $args->module_srls_info[$module_srl]->domain ); + $content_item->setContent($oDocument->getSummary($args->content_cut_size)); + $content_item->setLink( getSiteUrl($domain,'','document_srl',$document_srl) ); + $content_item->setThumbnail($thumbnail); + $content_item->add('mid', $args->mid_lists[$module_srl]); + if($first_thumbnail_idx==-1 && $thumbnail) $first_thumbnail_idx = $i; + $content_items[] = $content_item; + } + + $content_items[0]->setFirstThumbnailIdx($first_thumbnail_idx); + } + return $content_items; + } + + function _getImageItems($args) { + $oDocumentModel = &getModel('document'); + + $obj->module_srls = $obj->module_srl = $args->module_srl; + $obj->direct_download = 'Y'; + $obj->isvalid = 'Y'; + + // 분류 구함 + $output = executeQueryArray('widgets.content.getCategories',$obj); + if($output->toBool() && $output->data) { + foreach($output->data as $key => $val) { + $category_lists[$val->module_srl][$val->category_srl] = $val; + } + } + + // 정해진 모듈에서 문서별 파일 목록을 구함 + $obj->list_count = $args->list_count; + $files_output = executeQueryArray("file.getOneFileInDocument", $obj); + $files_count = count($files_output->data); + if(!$files_count) return; + + $content_items = array(); + + for($i=0;$i<$files_count;$i++) $document_srl_list[] = $files_output->data[$i]->document_srl; + + $tmp_document_list = $oDocumentModel->getDocuments($document_srl_list); + + if(!count($tmp_document_list)) return; + + foreach($tmp_document_list as $oDocument){ + $attribute = $oDocument->getObjectVars(); + $browser_title = $args->module_srls_info[$attribute->module_srl]->browser_title; + $domain = $args->module_srls_info[$attribute->module_srl]->domain; + $category = $category_lists[$attribute->module_srl]->text; + $content = $oDocument->getSummary($args->content_cut_size); + $url = sprintf("%s#%s",$oDocument->getPermanentUrl() ,$oDocument->getCommentCount()); + $thumbnail = $oDocument->getThumbnail(); + $content_item = new mcontentItem($browser_title); + $content_item->adds($attribute); + $content_item->setCategory($category); + $content_item->setContent($content); + $content_item->setLink($url); + $content_item->setThumbnail($thumbnail); + $content_item->setExtraImages($extra_images); + $content_item->setDomain($domain); + $content_item->add('mid', $args->mid_lists[$attribute->module_srl]); + $content_items[] = $content_item; + } + + return $content_items; + } + + function getRssItems($args){ + + $content_items = array(); + $args->mid_lists = array(); + + foreach($args->rss_urls as $key => $rss){ + $args->rss_url = $rss; + $content_item = $this->_getRssItems($args); + if(count($content_item) > 0){ + $browser_title = $content_item[0]->getBrowserTitle(); + $args->mid_lists[] = $browser_title; + $content_items[] = $content_item; + } + } + + if($args->tab_type == 'none' || $args->tab_type == ''){ + $items = array(); + foreach($content_items as $key => $val){ + foreach($val as $k => $v){ + $date = $v->get('regdate'); + $i=0; + while(array_key_exists(sprintf('%s%02d',$date,$i), $items)) $i++; + $items[sprintf('%s%02d',$date,$i)] = $v; + } + } + if($args->order_type =='asc') ksort($items); + else krsort($items); + $content_items = array_slice(array_values($items),0,$args->list_count); + } return $content_items; + } + + function _getRssBody($value) { + if(!$value || is_string($value)) return $value; + if(is_object($value)) $value = get_object_vars($value); + $body = null; + if(!count($value)) return; + foreach($value as $key => $val) { + if($key == 'body') { + $body = $val; + continue; + } + if(is_object($val)||is_array($val)) $body = $this->_getRssBody($val); + if($body !== null) return $body; + } + return $body; + } + + function _getSummary($content, $str_size = 50) + { + $content = preg_replace('!([\s]*)+!is', ' ', $content); + + //

, , 등의 태그를 공백 문자로 치환 + $content = str_replace(array('

', '', ''), ' ', $content); + + // 태그 제거 + $content = preg_replace('!<([^>]*?)>!is','', $content); + + // < , > , " 를 치환 + $content = str_replace(array('<','>','"',' '), array('<','>','"',' '), $content); + + // 연속된 공백문자 삭제 + $content = preg_replace('/ ( +)/is', ' ', $content); + + // 문자열을 자름 + $content = trim(cut_str($content, $str_size, $tail)); + + // >, <, "를 다시 복구 + $content = str_replace(array('<','>','"'),array('<','>','"'), $content); + + // 영문이 연결될 경우 개행이 안 되는 문제를 해결 + $content = preg_replace('/([a-z0-9\+:\/\.\~,\|\!\@\#\$\%\^\&\*\(\)\_]){20}/is',"$0-",$content); + return $content; + } + + + /** + * @brief rss 주소로 부터 내용을 받아오는 함수 + * tistory 의 경우 원본 주소가 location 헤더를 뿜는다. (내용은 없음)이를 해결하기 위한 수정 - rss_reader 위젯과 방식 동일 + **/ + function requestFeedContents($rss_url) { + $rss_url = str_replace('&','&',Context::convertEncodingStr($rss_url)); + return FileHandler::getRemoteResource($rss_url, null, 3, 'GET', 'application/xml'); + } + + function _getRssItems($args){ + // 날짜 형태 + $DATE_FORMAT = $args->date_format ? $args->date_format : "Y-m-d H:i:s"; + + $buff = $this->requestFeedContents($args->rss_url); + + $encoding = preg_match("/<\?xml.*encoding=\"(.+)\".*\?>/i", $buff, $matches); + if($encoding && !preg_match("/UTF-8/i", $matches[1])) $buff = Context::convertEncodingStr($buff); + + $buff = preg_replace("/<\?xml.*\?>/i", "", $buff); + + $oXmlParser = new XmlParser(); + $xml_doc = $oXmlParser->parse($buff); + if($xml_doc->rss) { + $rss->title = $xml_doc->rss->channel->title->body; + $rss->link = $xml_doc->rss->channel->link->body; + + $items = $xml_doc->rss->channel->item; + + if(!$items) return; + if($items && !is_array($items)) $items = array($items); + + $content_items = array(); + + foreach ($items as $key => $value) { + if($key >= $args->list_count) break; + unset($item); + + foreach($value as $key2 => $value2) { + if(is_array($value2)) $value2 = array_shift($value2); + $item->{$key2} = $this->_getRssBody($value2); + } + + $content_item = new mcontentItem($rss->title); + $content_item->setContentsLink($rss->link); + $content_item->setTitle($item->title); + $content_item->setNickName(max($item->author,$item->{'dc:creator'})); + //$content_item->setCategory($item->category); + $item->description = preg_replace('!pubdate,$item->pubDate,$item->{'dc:date'}))); + $content_item->setRegdate($date); + + $content_items[] = $content_item; + } + } elseif($xml_doc->{'rdf:rdf'}) { + // rss1.0 지원 (Xml이 대소문자를 구분해야 하는데 XE의 XML파서가 전부 소문자로 바꾸는 바람에 생긴 case) by misol + $rss->title = $xml_doc->{'rdf:rdf'}->channel->title->body; + $rss->link = $xml_doc->{'rdf:rdf'}->channel->link->body; + + $items = $xml_doc->{'rdf:rdf'}->item; + + if(!$items) return; + if($items && !is_array($items)) $items = array($items); + + $content_items = array(); + + foreach ($items as $key => $value) { + if($key >= $args->list_count) break; + unset($item); + + foreach($value as $key2 => $value2) { + if(is_array($value2)) $value2 = array_shift($value2); + $item->{$key2} = $this->_getRssBody($value2); + } + + $content_item = new mcontentItem($rss->title); + $content_item->setContentsLink($rss->link); + $content_item->setTitle($item->title); + $content_item->setNickName(max($item->author,$item->{'dc:creator'})); + //$content_item->setCategory($item->category); + $item->description = preg_replace('!pubdate,$item->pubDate,$item->{'dc:date'}))); + $content_item->setRegdate($date); + + $content_items[] = $content_item; + } + } elseif($xml_doc->feed && $xml_doc->feed->attrs->xmlns == 'http://www.w3.org/2005/Atom') { + // Atom 1.0 spec 지원 by misol + $rss->title = $xml_doc->feed->title->body; + $links = $xml_doc->feed->link; + if(is_array($links)) { + foreach ($links as $value) { + if($value->attrs->rel == 'alternate') { + $rss->link = $value->attrs->href; + break; + } + } + } + elseif($links->attrs->rel == 'alternate') $rss->link = $links->attrs->href; + + $items = $xml_doc->feed->entry; + + if(!$items) return; + if($items && !is_array($items)) $items = array($items); + + $content_items = array(); + + foreach ($items as $key => $value) { + if($key >= $args->list_count) break; + unset($item); + + foreach($value as $key2 => $value2) { + if(is_array($value2)) $value2 = array_shift($value2); + $item->{$key2} = $this->_getRssBody($value2); + } + + $content_item = new mcontentItem($rss->title); + $links = $value->link; + if(is_array($links)) { + foreach ($links as $val) { + if($val->attrs->rel == 'alternate') { + $item->link = $val->attrs->href; + break; + } + } + } + elseif($links->attrs->rel == 'alternate') $item->link = $links->attrs->href; + + $content_item->setContentsLink($rss->link); + if($item->title) { + if(!preg_match("/html/i", $value->title->attrs->type)) $item->title = $value->title->body; + } + $content_item->setTitle($item->title); + $content_item->setNickName(max($item->author,$item->{'dc:creator'})); + $content_item->setAuthorSite($value->author->uri->body); + //$content_item->setCategory($item->category); + $item->description = preg_replace('!published,$item->updated,$item->{'dc:date'}))); + $content_item->setRegdate($date); + + $content_items[] = $content_item; + } + } + return $content_items; + } + + function _getTrackbackItems($args){ + // 분류 구함 + $output = executeQueryArray('widgets.content.getCategories',$obj); + if($output->toBool() && $output->data) { + foreach($output->data as $key => $val) { + $category_lists[$val->module_srl][$val->category_srl] = $val; + } + } + + $obj->module_srl = $args->module_srl; + $obj->sort_index = $args->order_target; + $obj->list_count = $args->list_count; + + // trackback 모듈의 model 객체를 받아서 getTrackbackList() method를 실행 + $oTrackbackModel = &getModel('trackback'); + $output = $oTrackbackModel->getNewestTrackbackList($obj); + + // 오류가 생기면 그냥 무시 + if(!$output->toBool() || !$output->data) return; + + // 결과가 있으면 각 문서 객체화를 시킴 + $content_items = array(); + foreach($output->data as $key => $item) { + $domain = $args->module_srls_info[$item->module_srl]->domain; + $category = $category_lists[$item->module_srl]->text; + $url = getSiteUrl($domain,'','document_srl',$item->document_srl); + $browser_title = $args->module_srls_info[$item->module_srl]->browser_title; + + $content_item = new mcontentItem($browser_title); + $content_item->adds($item); + $content_item->setTitle($item->title); + $content_item->setCategory($category); + $content_item->setNickName($item->blog_name); + $content_item->setContent($item->excerpt); ///<< + $content_item->setDomain($domain); ///<< + $content_item->setLink($url); + $content_item->add('mid', $args->mid_lists[$item->module_srl]); + $content_item->setRegdate($item->regdate); + $content_items[] = $content_item; + } + return $content_items; + } + + function _compile($args,$content_items){ + $oTemplate = &TemplateHandler::getInstance(); + + // 위젯에 넘기기 위한 변수 설정 + $widget_info->modules_info = $args->modules_info; + $widget_info->option_view_arr = $args->option_view_arr; + $widget_info->list_count = $args->list_count; + $widget_info->subject_cut_size = $args->subject_cut_size; + $widget_info->content_cut_size = $args->content_cut_size; + + $widget_info->thumbnail_type = $args->thumbnail_type; + $widget_info->thumbnail_width = $args->thumbnail_width; + $widget_info->thumbnail_height = $args->thumbnail_height; + $widget_info->mid_lists = $args->mid_lists; + + $widget_info->show_browser_title = $args->show_browser_title; + $widget_info->show_category = $args->show_category; + $widget_info->show_comment_count = $args->show_comment_count; + $widget_info->show_trackback_count = $args->show_trackback_count; + $widget_info->show_icon = $args->show_icon; + + $widget_info->list_type = $args->list_type; + $widget_info->tab_type = $args->tab_type; + + $widget_info->markup_type = $args->markup_type; + $widget_info->content_items = $content_items; + + unset($args->option_view_arr); + unset($args->modules_info); + + Context::set('colorset', $args->colorset); + Context::set('widget_info', $widget_info); + + $tpl_path = sprintf('%sskins/%s', $this->widget_path, $args->skin); + return $oTemplate->compile($tpl_path, "content"); + } + } + + class mcontentItem extends Object { + + var $browser_title = null; + var $has_first_thumbnail_idx = false; + var $first_thumbnail_idx = null; + var $contents_link = null; + var $domain = null; + + function mcontentItem($browser_title=''){ + $this->browser_title = $browser_title; + } + function setContentsLink($link){ + $this->contents_link = $link; + } + function setFirstThumbnailIdx($first_thumbnail_idx){ + if(is_null($this->first_thumbnail) && $first_thumbnail_idx>-1) { + $this->has_first_thumbnail_idx = true; + $this->first_thumbnail_idx= $first_thumbnail_idx; + } + } + function setExtraImages($extra_images){ + $this->add('extra_images',$extra_images); + } + function setDomain($domain) { + static $default_domain = null; + if(!$domain) { + if(is_null($default_domain)) $default_domain = Context::getDefaultUrl(); + $domain = $default_domain; + } + $this->domain = $domain; + } + function setLink($url){ + $this->add('url',$url); + } + function setTitle($title){ + $this->add('title',$title); + } + + function setThumbnail($thumbnail){ + $this->add('thumbnail',$thumbnail); + } + function setContent($content){ + $this->add('content',$content); + } + function setRegdate($regdate){ + $this->add('regdate',$regdate); + } + function setNickName($nick_name){ + $this->add('nick_name',$nick_name); + } + + // 글 작성자의 홈페이지 주소를 저장 by misol + function setAuthorSite($site_url){ + $this->add('author_site',$site_url); + } + function setCategory($category){ + $this->add('category',$category); + } + function getBrowserTitle(){ + return $this->browser_title; + } + function getDomain() { + return $this->domain; + } + function getContentsLink(){ + return $this->contents_link; + } + + function getFirstThumbnailIdx(){ + return $this->first_thumbnail_idx; + } + + function getLink(){ + return $this->get('url'); + } + function getModuleSrl(){ + return $this->get('module_srl'); + } + function getTitle($cut_size = 0, $tail='...'){ + $title = strip_tags($this->get('title')); + + if($cut_size) $title = cut_str($title, $cut_size, $tail); + + $attrs = array(); + if($this->get('title_bold') == 'Y') $attrs[] = 'font-weight:bold'; + if($this->get('title_color') && $this->get('title_color') != 'N') $attrs[] = 'color:#'.$this->get('title_color'); + + if(count($attrs)) $title = sprintf("%s", implode(';', $attrs), htmlspecialchars($title)); + + return $title; + } + function getContent(){ + return $this->get('content'); + } + function getCategory(){ + return $this->get('category'); + } + function getNickName(){ + return $this->get('nick_name'); + } + function getAuthorSite(){ + return $this->get('author_site'); + } + function getCommentCount(){ + $comment_count = $this->get('comment_count'); + return $comment_count>0 ? $comment_count : ''; + } + function getTrackbackCount(){ + $trackback_count = $this->get('trackback_count'); + return $trackback_count>0 ? $trackback_count : ''; + } + function getRegdate($format = 'Y.m.d H:i:s') { + return zdate($this->get('regdate'), $format); + } + function printExtraImages() { + return $this->get('extra_images'); + } + function haveFirstThumbnail() { + return $this->has_first_thumbnail_idx; + } + function getThumbnail(){ + return $this->get('thumbnail'); + } + function getMemberSrl() { + return $this->get('member_srl'); + } + } +?> diff --git a/widgets/mcontent/skins/default/content.html b/widgets/mcontent/skins/default/content.html new file mode 100644 index 000000000..0094232a9 --- /dev/null +++ b/widgets/mcontent/skins/default/content.html @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/widgets/mcontent/skins/default/image_title.html b/widgets/mcontent/skins/default/image_title.html new file mode 100644 index 000000000..912d4d40b --- /dev/null +++ b/widgets/mcontent/skins/default/image_title.html @@ -0,0 +1,51 @@ + +{@$__module_info=$widget_info->modules_info;} +{@$__module_info=array_pop($__module_info);} +
+

{$__module_info->browser_title}

+
+ + +
diff --git a/widgets/mcontent/skins/default/image_title_content.html b/widgets/mcontent/skins/default/image_title_content.html new file mode 100644 index 000000000..ccd49c4a1 --- /dev/null +++ b/widgets/mcontent/skins/default/image_title_content.html @@ -0,0 +1,54 @@ + +{@$__module_info=$widget_info->modules_info;} +{@$__module_info=array_pop($__module_info);} +
+

{$__module_info->browser_title}

+
+ + + diff --git a/widgets/mcontent/skins/default/mcontent.css b/widgets/mcontent/skins/default/mcontent.css new file mode 100644 index 000000000..cc52c6b21 --- /dev/null +++ b/widgets/mcontent/skins/default/mcontent.css @@ -0,0 +1,24 @@ +@charset "utf-8"; +/* Mobile XE (/widgets/mcontent/skins/default/) */ +/* Hx */ +.hx{position:relative;border-bottom:1px solid #ccc8be;padding:8px 10px;margin:0} +.hx:after{content:"";margin:0 -10px;position:relative;top:10px;display:block;clear:both;height:1px;background:#fff} +.hx.h2{background:#e5e5e5} +.hx.h2 em{font-size:12px;color:#f60} +.hx.h3{background:#868686;color:#fff} +.hx.h3 em{font-size:12px} +.hx h2, .hx h3{margin:0 10px 0 0;display:inline} +.hx h2{font-size:16px;line-height:1.4} +.hx h3{font-size:14px} +/* List */ +.lt{margin:0;padding:0;list-style:none;background:#f2f0ec;font-size:14px;} +.lt li{border-bottom:1px solid #ccc8be} +.lt a{display:block;text-decoration:none;color:#000;padding:10px;*zoom:1} +.lt a:after{content:"";display:block;clear:both} +.lt .th{float:left;margin:0 10px 5px 0;border:1px solid #fff;background:#666;color:#fff;text-align:center;line-height:80px;width:80px;height:80px;font-size:14px;box-shadow:0 0 3px #333;-moz-box-shadow:0 0 3px #333;-webkit-box-shadow:0 0 3px #333} +.lt .title{display:block;margin:0 0 5px 0} +.lt .title strong{font-size:14px;font-weight:bold} +.lt .title em{font-size:12px;color:#333;color:#f60} +.lt .text{display:block; color:#666;margin:0 0 5px 0} +.lt .auth{display:block;font-size:12px} +.lt .auth .time{padding:0 5px;border-left:1px solid #bfbfbf} diff --git a/widgets/mcontent/skins/default/normal.html b/widgets/mcontent/skins/default/normal.html new file mode 100644 index 000000000..758c0c9f3 --- /dev/null +++ b/widgets/mcontent/skins/default/normal.html @@ -0,0 +1,45 @@ + +{@$__module_info=$widget_info->modules_info;} +{@$__module_info=array_pop($__module_info);} +
+

{$__module_info->browser_title}

+
+ + + diff --git a/widgets/mcontent/skins/default/skin.xml b/widgets/mcontent/skins/default/skin.xml new file mode 100644 index 000000000..cb744a97f --- /dev/null +++ b/widgets/mcontent/skins/default/skin.xml @@ -0,0 +1,15 @@ + + + 모바일 콘텐츠 위젯 스킨 + 모바일 콘텐츠 전용 심플한 스킨 입니다. + 0.1 + 2009-08-20 + + Jeong, Chan Myeong + + + + 흰색 바탕용 + + +