diff --git a/addons/mobile/classes/hdml.class.php b/addons/mobile/classes/hdml.class.php new file mode 100644 index 000000000..827da8441 --- /dev/null +++ b/addons/mobile/classes/hdml.class.php @@ -0,0 +1,96 @@ + + **/ + class wap extends mobileXE { + + /** + * @brief hdml 헤더 출력 + **/ + function printHeader() { + header("Content-Type:text/x-hdml; charset=".$this->charset); + header("Cache-Control: no-store, no-cache, must-revalidate"); + header("Cache-Control: post-check=0, pre-check=0", false); + header("Pragma: no-cache"); + + print ''; + print "\n"; + print $this->hasChilds()?'':''; + print "\n"; + + if($this->upperUrl) { + $url = $this->upperUrl; + printf('%s', $url->url, $url->text, "\n"); + } + } + + /** + * @brief 제목을 출력 + **/ + function printTitle() { + if($this->totalPage > $this->mobilePage) $titlePageStr = sprintf("(%d/%d)",$this->mobilePage, $this->totalPage); + printf('<%s%s>%s', $this->title,$titlePageStr,"\n"); + } + + /** + * @brief 내용을 출력 + * hasChilds()가 있으면 목록형을 그렇지 않으면 컨텐츠를 출력 + **/ + function printContent() { + if($this->hasChilds()) { + foreach($this->getChilds() as $key => $val) { + if(!$val['link']) continue; + printf('%s%s',Context::getLang('cmd_select'), $val['href'], $val['text'], "\n"); + } + } else { + printf('%s
%s', $this->getContent(),"\n"); + } + } + + /** + * @brief 버튼을 출력함 + **/ + function printBtn() { + // 메뉴 형식 + if($this->hasChilds()) { + if($this->prevUrl) { + $url = $this->prevUrl; + printf('%s%s', $url->text, $url->url, $url->text, "\n"); + } + if($this->nextUrl) { + $url = $this->nextUrl; + printf('%s%s', $url->text, $url->url, $url->text, "\n"); + } + if($this->homeUrl) { + $url = $this->homeUrl; + printf('%s%s', $url->text, $url->url, $url->text, "\n"); + } + // 컨텐츠 형식 + } else { + if($this->prevUrl) { + $url = $this->prevUrl; + printf('%s', $url->text, $url->url, $url->text); + } + if($this->nextUrl) { + $url = $this->nextUrl; + printf('%s', $url->text, $url->url, $url->text); + } + if($this->homeUrl) { + $url = $this->homeUrl; + printf('%s', $url->text, $url->url, $url->text); + } + } + } + + /** + * @brief 푸터 정보를 출력 + **/ + function printFooter() { + print $this->hasChilds()?'
':''; + print "\n"; + print("
"); + } + + } +?> diff --git a/addons/mobile/classes/mhtml.class.php b/addons/mobile/classes/mhtml.class.php new file mode 100644 index 000000000..b78174b62 --- /dev/null +++ b/addons/mobile/classes/mhtml.class.php @@ -0,0 +1,63 @@ + + **/ + class wap extends mobileXE { + + /** + * @brief hdml 헤더 출력 + **/ + function printHeader() { + print("\n"); + } + + // 제목을 출력 + function printTitle() { + if($this->totalPage > $this->mobilePage) $titlePageStr = sprintf("(%d/%d)",$this->mobilePage, $this->totalPage); + printf('<%s%s>
%s', $this->title,$titlePageStr,"\n"); + } + + /** + * @brief 내용을 출력 + * hasChilds()가 있으면 목록형을 그렇지 않으면 컨텐츠를 출력 + **/ + function printContent() { + if($this->hasChilds()) { + foreach($this->getChilds() as $key => $val) { + if(!$val['link']) continue; + printf('%s
%s', $val['href'], $this->getNo(), $val['text'], "\n"); + } + } else { + print $this->getContent()."\n"; + } + } + + /** + * @brief 버튼을 출력함 + **/ + function printBtn() { + if($this->prevUrl) { + $url = $this->prevUrl; + printf('%s
%s', $url->url, $url->text, "\n"); + } + if($this->nextUrl) { + $url = $this->nextUrl; + printf('%s
%s', $url->url, $url->text, "\n"); + } + if($this->upperUrl) { + $url = $this->upperUrl; + printf('%s', $url->url, $url->text, "\n"); + } + if($this->homeUrl) { + $url = $this->homeUrl; + printf('%s%s', $url->text, $url->url, $url->text, "\n"); + } + } + + // 푸터 정보를 출력 + function printFooter() { + print("\n"); + } + } +?> diff --git a/addons/mobile/classes/mobile.class.php b/addons/mobile/classes/mobile.class.php new file mode 100644 index 000000000..fe1de3518 --- /dev/null +++ b/addons/mobile/classes/mobile.class.php @@ -0,0 +1,247 @@ + + * @brief WAP 태그 출력을 위한 라이브러리 + **/ + + class mobileXE { + + // 기본 url + var $homeUrl = NULL; + var $upperUrl = NULL; + var $nextUrl = NULL; + var $prevUrl = NULL; + + // 메뉴 네비게이션을 위한 변수 + var $childs = null; + + // 기본 변수 + var $title = NULL; + var $content = NULL; + var $mobilePage = 0; + var $totalPage = 1; + var $charset = 'euc-kr'; + var $no = 0; + + // Deck size + var $deckSize = 500; + + // getInstance + function &getInstance() { + static $instance = null; + + if(!$instance) { + + $browserType = mobileXE::getBrowserType(); + if(!$browserType) return; + + $class_file = sprintf('%saddons/mobile/classes/%s.class.php', _XE_PATH_, $browserType); + require_once($class_file); + + Context::loadLang(_XE_PATH_.'addons/mobile/lang'); + + $instance = new wap(); + + $mobilePage = (int)Context::get('mpage'); + if(!$mobilePage) $mobilePage = 1; + $instance->setMobilePage($mobilePage); + } + + return $instance; + } + + /** + * @brief 접속 브라우저의 헤더를 판단하여 브라우저 타입을 return + * 모바일 브라우저가 아닐 경우 null return + **/ + function getBrowserType() { + // 브라우저 타입을 판별 + $browserAccept = $_SERVER['HTTP_ACCEPT']; + $userAgent = $_SERVER['HTTP_USER_AGENT']; + $wap_sid = $_SERVER['HTTP_X_UP_SUBNO']; + + if(eregi("SKT11", $userAgent)) $browserType = "wml"; + elseif(eregi("hdml", $browserAccept)) $browserType = "hdml"; + elseif(eregi("CellPhone", $userAgent)) $browserType = "mhtml"; + else $browserType = "html"; + +$browserType = 'mhtml'; + // class 지정 (html일 경우 동작 하지 않도록 함) + if($browserType == 'html') return null; + + return $browserType; + } + + // charset 지정 + function setCharSet($charset = 'utf-8') { + if(!$charset) $charset = 'utf-8'; + $this->charset = $charset; + } + + // 모바일 기기의 용량 제한에 다른 가상 페이지 지정 + function setMobilePage($page=1) { + if(!$page) $page = 1; + $this->mobilePage = $page; + } + + // 목록형 데이터 설정을 위한 child menu지정 + function setChilds($childs) { + // menu개수가 9개 이상일 경우 자체 페이징 처리 + $menu_count = count($childs); + if($menu_count>9) { + $startNum = ($this->mobilePage-1)*9; + $idx = 0; + $new_childs = array(); + foreach($childs as $k => $v) { + if($idx >= $startNum && $idx < $startNum+9) { + $new_childs[$k] = $v; + } + $idx ++; + } + $childs = $new_childs; + + $this->totalPage = (int)(($menu_count-1)/9)+1; + + // next/prevUrl 지정 + if($this->mobilePage>1) { + $url = getUrl('mid',$_GET['mid'],'mpage',$this->mobilePage-1); + $text = sprintf('%s (%d/%d)', Context::getLang('cmd_prev'), $this->mobilePage-1, $this->totalPage); + $this->setPrevUrl($url, $text); + } + + if($this->mobilePage<$this->totalPage) { + $url = getUrl('mid',$_GET['mid'],'mpage',$this->mobilePage+1); + $text = sprintf('%s (%d/%d)', Context::getLang('cmd_next'), $this->mobilePage+1, $this->totalPage); + $this->setNextUrl($url, $text); + } + } + $this->childs = $childs; + } + + // menu 출력대상이 있는지 확인 + function hasChilds() { + return count($this->childs)?true:0; + } + + // child menu반환 + function getChilds() { + return $this->childs; + } + + // title 지정 + function setTitle($title) { + $this->title = $title; + } + + // title 반환 + function getTitle() { + return $this->title; + } + + // 컨텐츠 지정 + function setContent($content) { + $content = str_replace(array('&','<','>','"','&nbsp;'), array('&','<','>','"',' '), strip_tags($content)); + + // 모바일의 경우 한 덱에 필요한 사이즈가 적어서 내용을 모두 페이지로 나눔 + $contents = array(); + while($content) { + $tmp = cut_str($content, $this->deckSize, ''); + $contents[] = $tmp; + $content = substr($content, strlen($tmp)); + } + + $this->totalPage = count($contents); + + // next/prevUrl 지정 + if($this->mobilePage>1) { + $url = getUrl('mid',$_GET['mid'],'mpage',$this->mobilePage-1); + $text = sprintf('%s (%d/%d)', Context::getLang('cmd_prev'), $this->mobilePage-1, $this->totalPage); + $this->setPrevUrl($url, $text); + } + + if($this->mobilePage<$this->totalPage) { + $url = getUrl('mid',$_GET['mid'],'mpage',$this->mobilePage+1); + $text = sprintf('%s (%d/%d)', Context::getLang('cmd_next'), $this->mobilePage+1, $this->totalPage); + $this->setNextUrl($url, $text); + } + + $this->content = $contents[$this->mobilePage-1]; + } + + // 컨텐츠 반환 + function getContent() { + return $this->content; + } + + // home url 지정 + function setHomeUrl($url, $text) { + if(!$url) $url = '#'; + $this->homeUrl->url = $url; + $this->homeUrl->text = $text; + } + + // upper url 지정 + function setUpperUrl($url, $text) { + if(!$url) $url = '#'; + $this->upperUrl->url = $url; + $this->upperUrl->text = $text; + } + + // prev url 지정 + function setPrevUrl($url, $text) { + if(!$url) $url = '#'; + $this->prevUrl->url = $url; + $this->prevUrl->text = $text; + } + + // next url 지정 + function setNextUrl($url, $text) { + if(!$url) $url = '#'; + $this->nextUrl->url = $url; + $this->nextUrl->text = $text; + } + + // display + function display() { + ob_start(); + + // 헤더를 출력 + $this->printHeader(); + + // 제목을 출력 + $this->printTitle(); + + // 내용 출력 + $this->printContent(); + + // 버튼 출력 + $this->printBtn(); + + // 푸터를 출력 + $this->printFooter(); + + $content = ob_get_clean(); + + debugPrint($content); + // 변환 후 출력 + if(strtolower($this->charset) == 'utf-8') print $content; + else print iconv('UTF-8',$this->charset, $content); + + exit(); + } + + // 페이지 이동 + function movepage($url) { + header("location:$url"); + exit(); + } + + // 목록등에서 일련 번호를 리턴한다 + function getNo() { + $this->no++; + $str = $this->no; + return $str; + } + } +?> diff --git a/addons/mobile/classes/mobile.func.php b/addons/mobile/classes/mobile.func.php new file mode 100644 index 000000000..d286ac71c --- /dev/null +++ b/addons/mobile/classes/mobile.func.php @@ -0,0 +1,17 @@ + $item) { + if(preg_match('/^([a-zA-Z0-9\_\-]+)$/', $item['url'])) { + $mid = $item['mid'] = $item['url']; + $mid_list[$node_srl] = $mid; + } else { + $mid = $item['mid'] = null; + } + + $listed_items[$mid] = $item; + getListedItems($item['list'], $listed_items, $mid_list); + } + } + +?> diff --git a/addons/mobile/classes/wml.class.php b/addons/mobile/classes/wml.class.php new file mode 100644 index 000000000..6a1a5dbb6 --- /dev/null +++ b/addons/mobile/classes/wml.class.php @@ -0,0 +1,74 @@ + + **/ + class wap extends mobileXE { + + /** + * @brief wml 헤더 출력 + **/ + function printHeader() { + header("Content-Type: text/vnd.wap.wml"); + header("charset: ".$this->charset); + print("charset."\"?>\n"); + print("\n\n

\n"); + } + + /** + * @brief 제목을 출력 + **/ + function printTitle() { + if($this->totalPage > $this->mobilePage) $titlePageStr = sprintf("(%d/%d)",$this->mobilePage, $this->totalPage); + printf('<%s%s>
%s', $this->title,$titlePageStr,"\n"); + } + + /** + * @brief 내용을 출력 + * hasChilds()가 있으면 목록형을 그렇지 않으면 컨텐츠를 출력 + **/ + function printContent() { + if($this->hasChilds()) { + foreach($this->getChilds() as $key => $val) { + if(!$val['link']) continue; + printf('%s', $this->getNo(), $val['text'], $val['href'], "\n"); + } + } else { + printf('%s
%s', str_replace("
","
",$this->getContent()),"\n"); + } + } + + /** + * @brief 버튼을 출력함 + **/ + function printBtn() { + if($this->prevUrl) { + $url = $this->prevUrl; + printf('%s', $this->getNo(), $url->text, $url->url, "\n"); + } + if($this->nextUrl) { + $url = $this->nextUrl; + printf('%s', $this->getNo(), $url->text, $url->url, "\n"); + } + if($this->homeUrl) { + $url = $this->homeUrl; + printf('%s', $url->text, $url->url, "\n"); + } + if($this->upperUrl) { + $url = $this->upperUrl; + printf('%s', $url->text, $url->url, "\n"); + } + } + + // 푸터 정보를 출력 + function printFooter() { + print("

\n
\n
"); + } + + // 목록등에서 일련 번호를 리턴한다 + function getNo() { + return "vnd.skmn".parent::getNo(); + return $str; + } + } +?> diff --git a/addons/mobile/conf/info.xml b/addons/mobile/conf/info.xml new file mode 100644 index 000000000..e0a92e682 --- /dev/null +++ b/addons/mobile/conf/info.xml @@ -0,0 +1,21 @@ + + + 모바일XE 애드온 + + zero + + 모바일에서 접속시 헤더 정보를 분석하여 메뉴 - 모듈의 관계를 이용하여 WAP 태그로 출력하는 애드온입니다. + wml, hdml, mhtml를 지원하고 그 이외의 경우에는 동작하지 않습니다. + + + + + 문자셋 + + 모바일 기기의 경우 utf-8 문자셋을 인식하지 못할 수 있습니다. + 문자셋에 원하시는 문자셋을 입력하면 자동으로 변환하여 출력하여 모바일에서 이상없이 출력하도록 합니다. + 기본값은 utf-8입니다. + + + + diff --git a/addons/mobile/lang/ko.lang.php b/addons/mobile/lang/ko.lang.php new file mode 100644 index 000000000..43d0b4504 --- /dev/null +++ b/addons/mobile/lang/ko.lang.php @@ -0,0 +1,10 @@ +cmd_go_upper = '상위'; + $lang->cmd_go_home = '홈으로'; +?> diff --git a/addons/mobile/mobile.addon.php b/addons/mobile/mobile.addon.php new file mode 100644 index 000000000..b597804c6 --- /dev/null +++ b/addons/mobile/mobile.addon.php @@ -0,0 +1,155 @@ +module == 'board') { + $this->list_count = $this->module_info->list_count = 9; + return; + } + + /** + * 동작 조건 + * 1. called_position == after_module_proc 일 경우에만 동작 + * 2. 관리자 페이지가 아닐 경우 + * 3. Context::getRequestMethod()!=='XMLRPC' 일 경우에만 + * 4. Context::getResponseMethod()!=='XMLRPC' 일 경우에만 + **/ + if($called_position != 'after_module_proc') return; + + $oMobile = &mobileXE::getInstance(); + if(!$oMobile) return; + + $oMobile->setCharSet($addon_info->charset); + + // 모듈의 정보를 구함 + $module_info = $this->module_info; + + // 메뉴 정보가 있는지 검사 + if($module_info->menu_srl) { + + // menu php cache 파일을 호출 + $menu_cache_file = sprintf(_XE_PATH_.'files/cache/menu/%d.php', $module_info->menu_srl); + if(file_exists($menu_cache_file)) { + include $menu_cache_file; + + // 정리된 menu들을 1차원으로 변경 + getListedItems($menu->list, $listed_items, $mid_list); + + // url request parameter에 mid값이 없을 경우, 즉 첫페이지 인경우 전체 목록을 구함 + if(!isset($_GET['mid'])) $childs = $menu->list; + // mid가 명시되어 있으면 해당 mid의 childs를 구함 + else $childs = $listed_items[$module_info->mid]['list']; + + // 현재 메뉴의 depth가 1이상이면 상위 버튼을 지정 + if($module_info->is_default != 'Y') { + $cur_menu_item = $listed_items[$module_info->mid]; + if($cur_menu_item['parent_srl']) { + $parent_srl = $cur_menu_item['parent_srl']; + if($parent_srl && $mid_list[$parent_srl]) { + $parent_item = $listed_items[$mid_list[$parent_srl]]; + if($parent_item) $oMobile->setUpperUrl(getUrl('','mid',$parent_item['mid']), Context::getLang('cmd_go_upper') ); + } + } else { + $oMobile->setUpperUrl(getUrl(), Context::getLang('cmd_go_upper')); + } + } + + // childs 메뉴들을 지정 + $oMobile->setChilds($childs); + } + } + + // 만약 childs가 없을 경우 컨텐츠 입력 + if(!$oMobile->hasChilds()) { + + // 현재 모듈이 게시판일 경우 (다른 모듈의 경우는 차후에..) + if($module_info->module == 'board') { + + // 선택된 게시글이 있으면 게시글의 내용을 출력 + $oDocument = Context::get('oDocument'); + if($oDocument && $oDocument->isExists()) { + // 내용 지정 (태그를 모두 제거한 내용을 설정) + $content = strip_tags($oDocument->getContent(false,false,false)); + $oMobile->setContent( $content ); + + // 상위 페이지를 목록으로 돌아가기로 지정 + $oMobile->setUpperUrl( getUrl('document_srl',''), Context::getLang('cmd_list') ); + + // 선택된 게시글이 없으면 목록을 출력 + } else { + $document_list = Context::get('document_list'); + $childs = array(); + if($document_list && count($document_list)) { + foreach($document_list as $key => $val) { + $href = getUrl('mid',$_GET['mid'],'document_srl',$val->document_srl); + $text = $val->getTitleText(10); + $obj = null; + $obj['href'] = $href; + $obj['link'] = $obj['text'] = $text; + $childs[] = $obj; + } + $oMobile->setChilds($childs); + } + + $page_navigation = Context::get('page_navigation'); + $totalPage = $page_navigation->last_page; + $page = (int)Context::get('page'); + if(!$page) $page = 1; + + // next/prevUrl 지정 + if($page>1) $oMobile->setPrevUrl(getUrl('mid',$_GET['mid'],'page',$page-1), sprintf('%s (%d/%d)', Context::getLang('cmd_prev'), $page-1, $totalPage)); + + if($page<$totalPage) $oMobile->setNextUrl(getUrl('mid',$_GET['mid'],'page',$page+1), sprintf('%s (%d/%d)', Context::getLang('cmd_next'), $page+1, $totalPage)); + + $oMobile->mobilePage = $page; + $oMobile->totalPage = $totalPage; + } + // 게시판 이외의 경우 + } else { + // 레이아웃은 사용하지 않도록 함 + Context::set('layout','none'); + + // 템플릿 컴파일 + $oTemplate = new TemplateHandler(); + $oContext = &Context::getInstance(); + + $content = $oTemplate->compile($this->getTemplatePath(), $this->getTemplateFile()); + $content = $oContext->transContent($content); + $oMobile->setContent( $content); + } + } + + // 홈버튼 지정 + $oMobile->setHomeUrl(getUrl(), Context::getLang('cmd_go_home')); + + // 제목 지정 + $oMobile->setTitle(Context::getBrowserTitle()); + + // 출력 + $oMobile->display(); +?>