3월 11일수정
어떤분이 언어 파일이 빠진것같다고 하여 그게아니라고 답변하고 생각을 해보니 common/lang/ko.lang.php 파일을 수정한 것을 올리지 않았더군요 죄송합니다. 언어 파일을 포함하여 다시 올렸구요. 확장변수에 주소폼(똑띠님의팁)을 추가하여 보았습니다 언어파일을 적용하지 않으면 이미지 삽입, 및 라디오버튼이 확장변수에 나타나지 않았을텐데 죄송합니다.
3월 9일 본문
본문 삽입이 필요없는 확장 변수로만 글을 작성 하고자 할때 본문 작성 에디터가 거추장 스러울 때가 있습니다. 방법중 모듈에 소스를 추가하는 방법과 기본스킨에 소스를 추가 하는 방법이 있는데, 여기서는 최소한의 기본스킨 변형으로 가능한 방법을 소개 합니다. 소스를 적용하시면 확장변수에 라디오 버튼은 "똑띠님"의 소스가 포함 되었으며, 기본 기능에서 본문작성 작성시 이미지 파일을 업로드하면 미리보기가 지원 되는데 이미지를 클릭 하면 게시글의 위치가 복사 되는 소스는 "WOOYA님"의 소스가 적용 되었음을 미리 밝혀 드립니다. 첨부된 파일은 기본 모듈 스킨(게시판, 에디터)중 바뀐 부분만 골라서 올린것 이므로 반드시 덮어 쓰셔야 합니다. zbxe.zip 위의 파일을 덮어 쓰신후 아래의 과정을 거치셔야 합니다. 1.게시판설정>스킨관리>본문쓰기 허락에서 "N"을 선택 하시고.
만일 웹진형 스타일에서 썸네일 클릭시 해당 홈페이지로 바로 이동하게 하시려면 기본형태를 "link"로 선택하세요.
"link" 스타일 적용시 확장 변수에서 확장변수1은 반드시 홈페이지 형식이어야하고. 확장변수2는 "textarea"영역으로 지정하여 소개글을 올리 도록 하여 목록 에 나타 나게 하였습니다. 이외의 확장 변수는 임의 대로 사용하셔도 됩니다.
((-------IMAGE-------)) 2. 게시판설정>추가설정>에디터스킨에서 "only_upload"를 선택 하세요. ((-------IMAGE-------)) 3. 게시판 설정>게시판정보>수정에가서 확장변수의 형식을 눌러 보시면 그림 삽입과 단일 선택으로 라디오 버튼이 추가 된것을 확인 하실수 있습니다. 4.확장변수를 그림 삽입으로 선택하시고 본문작성을 하시면 확장변수에 그림을 삽입하는 형태가 확장 변수에서 직접 이미지 파일을 업로드하여 계정에 저장하는 기능이 아니고 단지 이미지 파일을 링크시키는 형태입니다.
이에 본문의 "파일 첨부"에서 이미지 파일을 업로드 하면 미리보기 창에 그림이 나타 나는데 이그림을 클릭하시면 파일의 주소가 복사 됩니다. 이 복사된 내용을 아래의 홈페이지 스크린 샷 박스에 붙여 넣기를 하시면 됩니다. ((-------IMAGE-------)) <<참고>> 글쓰기 폼에서 위와 같은 폼은 예를 든 화면으로 확장변수의 지정은 사용자 스스로 하셔야 합니다.
by Anna 안나 2008. 11. 16. 20:48
Planning 2

#1. 브라우저간 접근성 테스트

((-------IMAGE-------))Planning 1에서 설명했던 부분들을 통해 유효성 검사에 통과했다면 다음은 Acessibility에 대한 부분입니다. 웹 접근성이란 아시다시피 다수의 웹 브라우저에서 얼마만큼 동일한 Look이 보여지느냐 입니다. 대부분 이 접근성 문제를 해결하기 위해서 단일 CSS 파일에 언더바 Hack등을 사용해서 일괄처리하고 있습니다. 하지만 유효성 검사에서는 이 부분을 에러로 처리합니다. 따라서 에러 없이 접근성을 높게 유지시키려면 몇개의 CSS 파일을 추가로 이용해야 합니다.

주석문을 통해 5종류의 메이져급 브라우저의 접근성을 통제하는데, 기본적으로 FireFox에서 작업하고 1차 테스트는 IE 7, 2차 테스트는 Opera, Safari, 마지막으로 IE6순으로 진행합니다. 이미 알려진 브라우저간 호환성 문제들, 예를들면 IE6의 3px 마진이나 FireFox의 Float 부유 우선순위 무시등을 일일이 인지하고 호환성 작업을 한다는 것은 어려운 일입니다. 따라서 아래의 순서로 작업하면서 보여지는 부분들을 하나하나 해결하는 것이 좋습니다.

FireFox에서 제작한 레이아웃을 IE 7에서 테스트 한다. 차이가 나는 부분을 수정한다.

Opera와 Safari를 테스트한다. 차이가 나는 부분을 수정한다. Opera와 Safari는 FireFox 계열과 렌더링 방식이 비슷하기 때문에 FireFox에서 잡은 레이아웃은 거의 동일하게 보여진다.

IE 6에서 테스트한다. IE 6는 IE 7과 렌더링 방식이 비슷하지만 다른 브라우저와 달리 독자적인 버그를 가지고 있다. 하지만 위 3개의 브라우저에서 버그를 잡았다면 IE 6에서도 대부분 비슷한 렌더링을 보여준다. 하나의 컴퓨터에 IE 7과 6을 동시에 설치하여 테스트하려면 여기를 참조한다.

#2. 주석문을 이용한 추가 CSS 운용
위의 순서로 테스트를 진행하기 위해서는 먼저 제로보드 XE에 주석문을 삽입하고 IE 7과 IE 6에 대응하는 별도의 CSS 파일을 정의해 주어야합니다. /common/tpl/common_layout,html의 head 태그 맨 마지막에 아래와 같이 주석문을 넣습니다.

/common/tpl/common_layout.htmlIE 브라우저 대응 CSS 파일의 추가 view plaincopy to clipboardprint? <!--[if IE]> <link rel="stylesheet" href="/layouts/WTA/css/IE_default.css" type="text/css"> <link rel="stylesheet" href="/modules/board/skins/WTA/css/IE_common.css" type="text/css"> <![endif]--> <!--[if lte IE 6]> <link rel="stylesheet" href="/layouts/WTA/css/IE6_default.css" type="text/css"> <link rel="stylesheet" href="/modules/board/skins/WTA/css/IE6_common.css" type="text/css"> <![endif]--> <!--[if IE]> <link rel="stylesheet" href="/layouts/WTA/css/IE_default.css" type="text/css"> <link rel="stylesheet" href="/modules/board/skins/WTA/css/IE_common.css" type="text/css"> <![endif]--> <!--[if lte IE 6]> <link rel="stylesheet" href="/layouts/WTA/css/IE6_default.css" type="text/css"> <link rel="stylesheet" href="/modules/board/skins/WTA/css/IE6_common.css" type="text/css"> <![endif]-->
if IE는 인터넷 익스플로러 전체 버전에 대응하는 대 IE용 CSS 파일입니다. 여기에는 IE 7도 포함되어 있으므로 쉽게는 IE 7용으로 보아도 좋습니다. 접속자의 브라우저가 인터넷 익스플로러인 경우 이 스크립트가 작동되어 기본으로 사용하는 CSS 대신 이 구문에 정의된 CSS 파일을 읽어들입니다. 따라서 위 구문대로라면 레이아웃 스킨의 default.css 대신 IE_default.css가 읽어지고 보드 스킨의 common.css대신 IE_common.css가 읽혀집니다.

if lte IE 6 구문에서는 IE 중에서도 버전 6의 브라우저로 접속한 경우 읽혀집니다. 이 역시 기본으로 정의된 css 대신 새로 정의된 IE 6 전용 CSS가 읽혀집니다. 위의 두 구문을 사용하면 처음 구문에서는 IE7과 IE6 모두에게 공통으로 적용되는 CSS를 먼저 인식시키고, 아래 IE6 전용 구문에서는 마지막으로 IE6의 문제점만 따로 처리하므로 IE에 대한 대응은 거의 완벽하게 됩니다.

따라서 기본으로 정의 된 default.css는 FireFox, Opera, Safari용으로, 따로 정의 CSS는 IE 전용으로 대응한다고 보면 되겠습니다.


#3. CSS 작성요령
추가로 정의 된 IE용 CSS 파일은, 기본 default.css에서 바뀌어야 할 부분만 정의하면 됩니다. deafult.css의 내용을 모두 복사해서 새로 만들어 저장하는 것이 아니라, 변경할 클래스나 셀렉터만 기재해서 저장하면 됩니다. 예를들면 아래와 같은 코드가 있고 여기서 padding-bottom:10px로 정의된 부분이 다른 브라우저에서는 제대로 보이는데 IE에서만 너무 하단 여백이 넓어진다고 치면(마진 3px 버그 발생)

/layouts/스킨폴더명/css/default.css기본 정의된 CSS 파일 view plaincopy to clipboardprint? .halfbar .customListLink ul {padding-bottom:10px; padding-top:10px} .halfbar .customListLink li {font: 8pt 돋움;letter-spacing: -1px; line-height: 150%; list-style:none; padding-bottom: 10px;} .halfbar .customListLink li a {text-decoration:none;} .halfbar .customListLink ul {padding-bottom:10px; padding-top:10px} .halfbar .customListLink li {font: 8pt 돋움;letter-spacing: -1px; line-height: 150%; list-style:none; padding-bottom: 10px;} .halfbar .customListLink li a {text-decoration:none;}
아래와 같이 문제의 클래스와 셀렉터만 기재해서 아래와 같이 넣어주고 저장하면 됩니다.

/layouts/스킨폴더명/css/IE_default.css변경 된 부분만 적용된 추가 CSS view plaincopy to clipboardprint? .halfbar .customListLink ul {padding-bottom:7px;} .halfbar .customListLink ul {padding-bottom:7px;}
CSS는 먼저 default.css에서 정의된 부분을 읽고 난 후, 접속자의 브라우저가 IE6면 default.css에는 없거나 수정된 부분만을 IE_default.css에서 불러옵니다. 따라서 기본 CSS 파일에서 IE에 어긋나는 구문만 옮겨와서 추가 CSS에 넣어주면 됩니다. 이렇듯 Planning 1과 2에서 다룬 웹 표준 유효성 통과와 브라우저 접근성 부분은 기획 초반에 잡아두면 거의 끝까지 유지/관리 할 수 있는 반면, 처음에 무시하고 시작하면 중간에 바로잡기가 무척 힘듭니다.

유효성과 접근성 부분, 귀찮다고만 생각하지 말고 초반에 사이트 작성할 때 한번만 바로 잡아 놓으면 된다는 점 기억해 주세요.
by Anna 안나 2008. 11. 16. 20:23
안녕하세요 hammer입니다. 이번에 제로보드로 만든 사이트 링크 겔러리가 대강 모습을 갖춰서 몇가지 팁들을 공유합니다. 이전에 블로그 스킨인 Xesta때 느낀 것이지만 스킨 제작은 너무 많은 시간과 노력이 소요되는대 반해 새로운 기술들의 도입에 대해 유지관리가 어려워서 앞으로는 팁 공유쪽에 노력을 할애하는 편이 낫다고 생각했습니다.

이 내용은 사이트 링크 겔러리에 어울리는 팁들이 많지만 일반적인 사이트의 구성에도 필요하거나 유용한 것들이니 나름대로 참고하시면 좀 더 완성도 있는 사이트를 만드시는데 도움이 되리라 봅니다. 팁의 예제로 사용되는 사이트는 WTA(Web Trend Awards)입니다. 이 사이트에서 사용되고 있는 오픈소스 플러그인이나 제로보드 팁들을 차근차근 소개하도록 하겠습니다.

이 어드바이스의 첫 부분인 Planning과 같은 부분은 내용이 다소 난해 할 수도 있습니다. 어느 특정 기능의 상세설명보다는 표준 인프라에 관한 내용이라 그럴 수 있으나 이후에 작성 할 세세한 기능성 팁들은 훨씬 이해하기 쉽게 쓰겠습니다.


Planning 1

#1. Generator와 Javascript Library 인스톨
Generator로는 당연히 제로보드 XE를 사용하기 때문에 이것을 설치합니다. 팁이나 애드온에 보면 제로보드가 설치된 폴더의 이름을 없애고 도메인 루트로 이동하는 내용들에 대해 여러가지 있는데, Wordpress처 럼 Rewrite 모드에서 퍼머링크 설정하는 부분에 대해 제로보드에서는 아직 정식 메뉴얼로 나와있는 내용이 없기 때문에 WTA에서는 최상위 루트에 그대로 ZBXE를 설치했습니다. 이렇게 최상위 루트에 제로보드의 여러 폴더들이 설치되는것이 싫다면 다른 팁들을 찾아보시기 바랍니다.

Javascript Library는 크게 Jquery와 Prototype 둘 중 어느것을 선택 할지 결정하면 됩니다. 그밖에도 여러가지 라이브러리들이 있지만 WTA에서는 Jquery를 선택했습니다. 특별한 이유는 없고 단지 원하는 기능들을 찾을때 Prototype보다는 Jquery에서 원하는 소스들이 더 많이 나왔기 때문입니다.

가장 최신의 Jquery 파일을 다운로드 받고 설치합니다. 이때 라이브러리를 레이아웃 스킨에 넣을지 보드 스킨에 넣을지 판단하세요. 단일 스킨을 지속적으로 사용 할 생각이고 사이트 전체적으로 Jquery가 사용되고 싶다면 Layout 스킨에 넣는 것이 좋습니다. 만일 특정 보드 스킨에서만 작동하던가 혹은 Jquery와 Prototype을 번갈아 가면서 스킨에 맞게 사용하고 싶다면 해당 보드 스킨에 넣으세요. Jquery와 Prototype은 동시에 작동하지 않기 때문에 레이아웃 스킨에 동시에 넣게되면 충돌이 일어납니다. WTA에서는 스킨을 막론하고 사이트 전체적으로 Jquery가 동작하길 바랬기 때문에 레이아웃 스킨에 Jquery를 설치했고 보드에는 아무런 라이브러리도 설치하지 않았습니다.

레이아웃 스킨에 Jquery를 설치하려면 아래와 같이 코드를 넣어주세요. xe_official.js는 기존에 있던 부분입니다. 그 밑에 추가가 됩니다.

zbxe/layouts/스킨폴더명/layout.html레이아웃 스킨에 Jquery를 설치합니다 view plaincopy to clipboardprint? <!-- js 파일 import --> <!--%import("js/xe_official.js")--> <!--%import("js/jquery.js")--> <!-- js 파일 import --> <!--%import("js/xe_official.js")--> <!--%import("js/jquery.js")-->
#2. W3C Markup & CSS 유효성 통과를 위한 커스터마이징
((-------IMAGE-------)) 혹시 이 글을 보시는 분이 유효성 검사에 대해 완벽주의자라면 제로보드 기본 파일에서 몇가지 수정이 필요합니다. 아시다시피 제로보드는 기본적으로 웹 표준을 아주 잘 지키고 있고 CSS에서 에러가 나는 부분도 브라우저 접근성 때문에 필요악으로 생긴 Hack 부분에 한합니다. 하지만 이것마저도 눈에 거슬린다면 아래의 지침을 따라보세요. 만일 CSS Validator나 Markup Validator에서 "축하합니다! 이 페이지는 유효성을 통과한 검증된 페이지입니다!"라는 메세지 따윈 신경쓰지 않는다면 이 파트는 읽지않고 그냥 넘어가세요.

기 본적으로 CSS Validaotr에서 여러분의 제로보드 페이지를 검사했을 때 검출되는 에러에 해당되는 부분들(button.css라던가 iePngFix와 같은 부분)은 모두 CSS 파일에서 삭제해도 제로보드 작동에는 아무런 문제가 없습니다. button.css의 경우에는 제로보드 전체적으로 사용하는 각종 버튼들을 라운드 형식으로 예쁘게 꾸민 CSS 파일입니다. 이 파일에는 IE, Firefox, Opera, Safari등과 같은 메이져 브라우저들에 대해 동일한 Look이 보여질 수 있도록 접근성용 Hack 부분을 설정해 놓았는데, 이러한 Hack이 유효성 검사기에서 에러를 냅니다.

한가 지 분명히 알고 넘어갈 것은, Hack을 쓰지 않고도 모든 메이져급 브라우저에서 동일한 접근성을 유지 시키는 방법은 분명히 있습니다. 하지만 이것은 유저가 직접 추가적인 CSS를 작성해서 사용해야 하기 때문에 제로보드에서는 편의를 위해 하나의 CSS에서 해결하고 있는 것 입니다. 만일 애드온 자료실의 ButtonChange와 같은 좋은 애드온등의 사용을 포기하면서까지 유효성을 지키고 싶다면 button.css의 CSS 에러 구문을 모두 삭제하십시오. 이것을 삭제하므로 해서 여러분은 무척 귀찮은 작업들을 해야만 합니다. 제로보드 전반에 걸쳐 이 파일의 셀렉터로 사용되고 있는 button이라는 클래스를 모두 별도의 클래스로 바꾸어 지정하던가 혹은 /common/css/button.css를 직접 수정해서 일괄적으로 사용 할 버튼을 만들어야 합니다.

button.css에서 에러를 발생시키는 CSS 에러구문을 모두 없애면서 제로보드 페이지 전반적으로 동일 한 Look의 버튼을 사용하고 싶다면 직접 button.css 파일을 수정해서 하세요. WTA의 경우는 때에 따라 서로 모양이 다른 버튼을 써야 할 때가 있기 때문에 button.css 파일은 단순한 모양을 지닌 Dummy 파일로만 사용하고 HTML 페이지에 정의된 ,button 클래스명을 바꿔서 사용하고 있습니다. WTA에서 사용하는 Dummy 파일이 필요하다면 button.zip을 다운받으세요. 이 CSS 파일은 모든 CSS 에러구문이 삭제되고 기존의 버튼을 회색의 단조로운 버튼으로 바꿉니다. 관리자 페이지등에서도 이 버튼이 나타나게되고 제가 깔끔하게 다듬지 않아 모양이 좋지 않습니다. 어차피 관리자 페이지는 자신만 보는 것이므로 이와같이 더미 버튼을 사용하고, 방문자들이 보게 될 부분의 버튼들은 각 HTML 파일의 .button 클래스를 여러분이 새로 지정한 버튼 모양의 클래스로 변경하세요.

이런 일련의 작업들이 너무나도 귀찮고 번거롭다면 유효성 검사에 뜻을 두지 마시고 그냥 사용하세요.

/common /css/default.css에서도 에러 구문이 있습니다. CSS Validator에서 보여주는 에러 구문들을 찾아 모두 삭제하면 PNG 투명 이미지의 사용에 문제가 발생합니다. 이 문제는 Jquery 기반에서 동작하는 PNG-Transparency for Windows IE 5.5 & 6을 사용해서 CSS 에러 없이 해결 할 수 있습니다. 이 PNG 핵은 웹사이트 전체적으로 사용되는 것이니 common 파트에 넣는 것이 좋습니다. 다운로드 받은 파일을 /common/js폴더에 넣은 후 common/tpl/common_layout.html에 아래와 같이 추가하세요. 아래의 코드에서 추가되는 구문은 9번째 줄 이 한줄 입니다.

/common/tpl/common_layout.htmlCSS 에러가 없는 PNG 핵을 설치합니다 view plaincopy to clipboardprint? <meta http-equiv="imagetoolbar" content="no" /> <title>{Context::getBrowserTitle()}</title> {@ $js_files = Context::getJsFile() } <!--@foreach($js_files as $key => $js_file)--> <!--@if($js_file['targetie'])--> <!--[if {$js_file['targetie']}]> <!--@end--> <script type="text/javascript" src="{$js_file['file']}"></script> <script type="text/javascript" src="../common/js/jquery.pngFix.js"></script> <!--@if($js_file['targetie'])--> <![endif]--> <!--@end--> <!--@end--> <meta http-equiv="imagetoolbar" content="no" /> <title>{Context::getBrowserTitle()}</title> {@ $js_files = Context::getJsFile() } <!--@foreach($js_files as $key => $js_file)--> <!--@if($js_file['targetie'])--> <!--[if {$js_file['targetie']}]> <!--@end--> <script type="text/javascript" src="{$js_file['file']}"></script> <script type="text/javascript" src="../common/js/jquery.pngFix.js"></script> <!--@if($js_file['targetie'])--> <![endif]--> <!--@end--> <!--@end-->
button.css 와 default.css 그리고 common_layout.html 파일 3가지의 파일을 수정함으로해서 여러분은 제로보드 XE에서 발생하는 모든 CSS 에러 구문을 없애고 유효성 검사에 통과하면서도 기존과 동일한 브라우저 접근성을 유지 할 수 있습니다. 물론 위의 내용들이 조금 난해할수도 있습니다. 각자의 작업중에 발생하는 문제점은 따로 알려주시면 이곳에서 함께 처리 하는 것으로 하고 기초 Planning에 대한 부분은 여기까지만 적겠습니다.

다음에는 웹 브라우저 접근성을 위한 CSS 분리 관리를 시작으로 Planning의 다음 부분 이야기 해드리겠습니다.
by Anna 안나 2008. 11. 16. 20:22
수정파일 /zbxe/modules/board/skins/xe_board/css/common.css를 열어서 112줄 부터 있는 reply사항에 배경을 넣어 주시면 됩니다.
.replyBox { padding:10px; color:#666666; border:1px solid #e0e1db; margin-top:.5em;}
.replyBox .replyItem { background-color:#FFFFFF; padding:.6em .8em .6em .6em; line-height:1.25em; clear:both; border-bottom:1px dotted #EEEEEE; list-style:none;} // 칸 전체를 차지
.replyBox p { display:inline; margin-bottom:1em;}
.replyBox .author { float:left; padding:0 .3em 0 0; font-size:.9em; color:#3074a5; margin:0 .3em .5em 0;}
.replyBox .author a { color:#3074a5; margin-right:.3em; text-decoration:none; }
.replyBox .voted { float:left; font-size:.9em; color:#AAAAAA; margin:0 .3em .5em 1em;}
.replyBox .date { float:right; font:.8em Tahoma; color:#cccccc; margin:.3em 0 .5em 0;}

.replyBox .replyOption { height:20px; float:right; white-space:nowrap; margin-left:.2em;}
.replyBox .replyOption img { vertical-align:middle;}

.replyBox .replyContent { clear:left; } // 아이콘 아래부분 차지
.replyBox .replyContent p { display:block; }
.replyBox .reply { background-color:#F4F4F4; border-bottom:1px dotted #DDDDDD;} // 댓글의 댓글에만 적용
.replyBox .replyIndent { background:url(../images/common/iconReplyArrow.gif) no-repeat .0em .3em; padding-left:1.3em;} 위에 빨간색으로 보이는 행에 배경을 넣어 주시면 됩니다.
두 곳중 한군데를 선택해서 넣어시면 되는데 차이점은 한번 해보시면 아실 수 있을 것입니다.

아래에 있는 예제를 보기삼아서 repeat나 위치를 조절하세요.
.replyBox .replyItem { background:#ffffff url(../images/image.gif) no-repeat left top; padding:.6em .8em .6em .6em; line-height:1.25em; clear:both; border-bottom:1px dotted #f60; list-style:none;}

.replyBox .replyContent { clear:left; background:#ffffff url(../images/image.gif) no-repeat right top; }
by Anna 안나 2008. 11. 15. 16:06
페이지 숫자 나타나는 부분에 아래처럼 사각형을 씌워보겠습니다.
1번은 선택되어진 페이지 이고 3번은 마우스 오버(레인보우 링크 때문에 분홍색) 했을때도 사각형이 생깁니다.

((-------IMAGE-------))

/zbxe/modules/board/skins/보드스킨/css 열고 아래 빨간색 코드를 수정합니다.
/* pageNavigation */
.pageNavigation { text-align:center; font:bold 11px Tahoma; margin-top:5px;}
.pageNavigation a { font:bold 1em Tahoma; color:#666666; text-decoration:none; margin:0 10px 0 0; }
.pageNavigation .current { font:bold 1em Tahoma; text-decoration:none; margin:0 10px 0 0; }
.pageNavigation a:hover { background:#F7F7F7; text-decoration:none; }
.pageNavigation a:visited { color:#999999; }
.pageNavigation a.goToFirst img, .pageNavigation a.goToLast img { margin-bottom:2px;} ↓
/* pageNavigation */
.pageNavigation { text-align:center; font:bold 11px Tahoma; margin-top:5px;}
.pageNavigation a { font:bold 1em Tahoma; color:#666666; text-decoration:none; margin:0 6px 0 6px;}
.pageNavigation .current { border:1px solid #e0e1db; padding:2px 5px 2px 5px; background:#F7F7F7; font:bold 1em Tahoma; text-decoration:none; }
.pageNavigation a:hover { border:1px solid #e0e1db; padding:2px 5px 2px 5px; margin: 0 0 0 0; background:#F7F7F7; text-decoration:none; }
.pageNavigation a:visited { color:#999999; }
.pageNavigation a.goToFirst img, .pageNavigation a.goToLast img { margin-bottom:2px;}테두리 색은 #e0e1db, 크기는 padding을 자신에 맞게 2개다 수정해 주시면됩니다. (↑→↓← 순입니다)
by Anna 안나 2008. 11. 15. 16:05
moudules/board/skin/ xe_list/view_document.html
을 열고 구글 소스를 넣으면 됩니다.

A. 본문 상단에 출력
</div>
<!--@end-->
구글애드센스 소스
<div class="replyAndTrackback">

B. 본문 아래 첨부파일 위에 출력

<!--@end-->
구글애드센스 소스
<!--@if($grant->is_admin)-->
<div class="ipaddress">ipaddress : {$oDocument->get('ipaddress')}</div>


C. 본문창 아래 댓글 위에 출력

<!--#include("./comment.html")-->
구글애드센스 소스
<!-- 댓글 입력 폼 -->
<!--@if($grant->write_comment && !$oDocument->isLocked() && $oDocument->allowComment() )-->
by Anna 안나 2008. 11. 15. 16:04
Planning 2

#1. 브라우저간 접근성 테스트

Planning 1에서 설명했던 부분들을 통해 유효성 검사에 통과했다면 다음은 Acessibility에 대한 부분입니다. 웹 접근성이란 아시다시피 다수의 웹 브라우저에서 얼마만큼 동일한 Look이 보여지느냐 입니다. 대부분 이 접근성 문제를 해결하기 위해서 단일 CSS 파일에 언더바 Hack등을 사용해서 일괄처리하고 있습니다. 하지만 유효성 검사에서는 이 부분을 에러로 처리합니다. 따라서 에러 없이 접근성을 높게 유지시키려면 몇개의 CSS 파일을 추가로 이용해야 합니다.

주석문을 통해 5종류의 메이져급 브라우저의 접근성을 통제하는데, 기본적으로 FireFox에서 작업하고 1차 테스트는 IE 7, 2차 테스트는 Opera, Safari, 마지막으로 IE6순으로 진행합니다. 이미 알려진 브라우저간 호환성 문제들, 예를들면 IE6의 3px 마진이나 FireFox의 Float 부유 우선순위 무시등을 일일이 인지하고 호환성 작업을 한다는 것은 어려운 일입니다. 따라서 아래의 순서로 작업하면서 보여지는 부분들을 하나하나 해결하는 것이 좋습니다.

FireFox에서 제작한 레이아웃을 IE 7에서 테스트 한다. 차이가 나는 부분을 수정한다.

Opera와 Safari를 테스트한다. 차이가 나는 부분을 수정한다. Opera와 Safari는 FireFox 계열과 렌더링 방식이 비슷하기 때문에 FireFox에서 잡은 레이아웃은 거의 동일하게 보여진다.

IE 6에서 테스트한다. IE 6는 IE 7과 렌더링 방식이 비슷하지만 다른 브라우저와 달리 독자적인 버그를 가지고 있다. 하지만 위 3개의 브라우저에서 버그를 잡았다면 IE 6에서도 대부분 비슷한 렌더링을 보여준다. 하나의 컴퓨터에 IE 7과 6을 동시에 설치하여 테스트하려면 여기를 참조한다.

#2. 주석문을 이용한 추가 CSS 운용
위의 순서로 테스트를 진행하기 위해서는 먼저 제로보드 XE에 주석문을 삽입하고 IE 7과 IE 6에 대응하는 별도의 CSS 파일을 정의해 주어야합니다. /common/tpl/common_layout,html의 head 태그 맨 마지막에 아래와 같이 주석문을 넣습니다.

/common/tpl/common_layout.htmlIE 브라우저 대응 CSS 파일의 추가view plaincopy to clipboardprint? <!--[if IE]> <link rel="stylesheet" href="/layouts/WTA/css/IE_default.css" type="text/css"> <link rel="stylesheet" href="/modules/board/skins/WTA/css/IE_common.css" type="text/css"> <![endif]--> <!--[if lte IE 6]> <link rel="stylesheet" href="/layouts/WTA/css/IE6_default.css" type="text/css"> <link rel="stylesheet" href="/modules/board/skins/WTA/css/IE6_common.css" type="text/css"> <![endif]--> <!--[if IE]> <link rel="stylesheet" href="/layouts/WTA/css/IE_default.css" type="text/css"> <link rel="stylesheet" href="/modules/board/skins/WTA/css/IE_common.css" type="text/css"> <![endif]--> <!--[if lte IE 6]> <link rel="stylesheet" href="/layouts/WTA/css/IE6_default.css" type="text/css"> <link rel="stylesheet" href="/modules/board/skins/WTA/css/IE6_common.css" type="text/css"> <![endif]-->
if IE는 인터넷 익스플로러 전체 버전에 대응하는 대 IE용 CSS 파일입니다. 여기에는 IE 7도 포함되어 있으므로 쉽게는 IE 7용으로 보아도 좋습니다. 접속자의 브라우저가 인터넷 익스플로러인 경우 이 스크립트가 작동되어 기본으로 사용하는 CSS 대신 이 구문에 정의된 CSS 파일을 읽어들입니다. 따라서 위 구문대로라면 레이아웃 스킨의 default.css 대신 IE_default.css가 읽어지고 보드 스킨의 common.css대신 IE_common.css가 읽혀집니다.

if lte IE 6 구문에서는 IE 중에서도 버전 6의 브라우저로 접속한 경우 읽혀집니다. 이 역시 기본으로 정의된 css 대신 새로 정의된 IE 6 전용 CSS가 읽혀집니다. 위의 두 구문을 사용하면 처음 구문에서는 IE7과 IE6 모두에게 공통으로 적용되는 CSS를 먼저 인식시키고, 아래 IE6 전용 구문에서는 마지막으로 IE6의 문제점만 따로 처리하므로 IE에 대한 대응은 거의 완벽하게 됩니다.

따라서 기본으로 정의 된 default.css는 FireFox, Opera, Safari용으로, 따로 정의 CSS는 IE 전용으로 대응한다고 보면 되겠습니다.


#3. CSS 작성요령
추가로 정의 된 IE용 CSS 파일은, 기본 default.css에서 바뀌어야 할 부분만 정의하면 됩니다. deafult.css의 내용을 모두 복사해서 새로 만들어 저장하는 것이 아니라, 변경할 클래스나 셀렉터만 기재해서 저장하면 됩니다. 예를들면 아래와 같은 코드가 있고 여기서 padding-bottom:10px로 정의된 부분이 다른 브라우저에서는 제대로 보이는데 IE에서만 너무 하단 여백이 넓어진다고 치면(마진 3px 버그 발생)

/layouts/스킨폴더명/css/default.css기본 정의된 CSS 파일view plaincopy to clipboardprint?.halfbar .customListLink ul {padding-bottom:10px; padding-top:10px} .halfbar .customListLink li {font: 8pt 돋움;letter-spacing: -1px; line-height: 150%; list-style:none; padding-bottom: 10px;} .halfbar .customListLink li a {text-decoration:none;} .halfbar .customListLink ul {padding-bottom:10px; padding-top:10px} .halfbar .customListLink li {font: 8pt 돋움;letter-spacing: -1px; line-height: 150%; list-style:none; padding-bottom: 10px;} .halfbar .customListLink li a {text-decoration:none;}
아래와 같이 문제의 클래스와 셀렉터만 기재해서 아래와 같이 넣어주고 저장하면 됩니다.

/layouts/스킨폴더명/css/IE_default.css변경 된 부분만 적용된 추가 CSSview plaincopy to clipboardprint? .halfbar .customListLink ul {padding-bottom:7px;} .halfbar .customListLink ul {padding-bottom:7px;}
CSS는 먼저 default.css에서 정의된 부분을 읽고 난 후, 접속자의 브라우저가 IE6면 default.css에는 없거나 수정된 부분만을 IE_default.css에서 불러옵니다. 따라서 기본 CSS 파일에서 IE에 어긋나는 구문만 옮겨와서 추가 CSS에 넣어주면 됩니다. 이렇듯 Planning 1과 2에서 다룬 웹 표준 유효성 통과와 브라우저 접근성 부분은 기획 초반에 잡아두면 거의 끝까지 유지/관리 할 수 있는 반면, 처음에 무시하고 시작하면 중간에 바로잡기가 무척 힘듭니다.

유효성과 접근성 부분, 귀찮다고만 생각하지 말고 초반에 사이트 작성할 때 한번만 바로 잡아 놓으면 된다는 점 기억해 주세요.
by Anna 안나 2008. 11. 14. 21:28
이 내용은 사이트 링크 겔러리에 어울리는 팁들이 많지만 일반적인 사이트의 구성에도 필요하거나 유용한 것들이니 나름대로 참고하시면 좀 더 완성도 있는 사이트를 만드시는데 도움이 되리라 봅니다. 팁의 예제로 사용되는 사이트는 WTA(Web Trend Awards)입니다. 이 사이트에서 사용되고 있는 오픈소스 플러그인이나 제로보드 팁들을 차근차근 소개하도록 하겠습니다.

이 어드바이스의 첫 부분인 Planning과 같은 부분은 내용이 다소 난해 할 수도 있습니다. 어느 특정 기능의 상세설명보다는 표준 인프라에 관한 내용이라 그럴 수 있으나 이후에 작성 할 세세한 기능성 팁들은 훨씬 이해하기 쉽게 쓰겠습니다.


Planning 1

#1. Generator와 Javascript Library 인스톨
Generator로는 당연히 제로보드 XE를 사용하기 때문에 이것을 설치합니다. 팁이나 애드온에 보면 제로보드가 설치된 폴더의 이름을 없애고 도메인 루트로 이동하는 내용들에 대해 여러가지 있는데, Wordpress처 럼 Rewrite 모드에서 퍼머링크 설정하는 부분에 대해 제로보드에서는 아직 정식 메뉴얼로 나와있는 내용이 없기 때문에 WTA에서는 최상위 루트에 그대로 ZBXE를 설치했습니다. 이렇게 최상위 루트에 제로보드의 여러 폴더들이 설치되는것이 싫다면 다른 팁들을 찾아보시기 바랍니다.

Javascript Library는 크게 Jquery와 Prototype 둘 중 어느것을 선택 할지 결정하면 됩니다. 그밖에도 여러가지 라이브러리들이 있지만 WTA에서는 Jquery를 선택했습니다. 특별한 이유는 없고 단지 원하는 기능들을 찾을때 Prototype보다는 Jquery에서 원하는 소스들이 더 많이 나왔기 때문입니다.

가장 최신의 Jquery 파일을 다운로드 받고 설치합니다. 이때 라이브러리를 레이아웃 스킨에 넣을지 보드 스킨에 넣을지 판단하세요. 단일 스킨을 지속적으로 사용 할 생각이고 사이트 전체적으로 Jquery가 사용되고 싶다면 Layout 스킨에 넣는 것이 좋습니다. 만일 특정 보드 스킨에서만 작동하던가 혹은 Jquery와 Prototype을 번갈아 가면서 스킨에 맞게 사용하고 싶다면 해당 보드 스킨에 넣으세요. Jquery와 Prototype은 동시에 작동하지 않기 때문에 레이아웃 스킨에 동시에 넣게되면 충돌이 일어납니다. WTA에서는 스킨을 막론하고 사이트 전체적으로 Jquery가 동작하길 바랬기 때문에 레이아웃 스킨에 Jquery를 설치했고 보드에는 아무런 라이브러리도 설치하지 않았습니다.

레이아웃 스킨에 Jquery를 설치하려면 아래와 같이 코드를 넣어주세요. xe_official.js는 기존에 있던 부분입니다. 그 밑에 추가가 됩니다.

zbxe/layouts/스킨폴더명/layout.html레이아웃 스킨에 Jquery를 설치합니다view plaincopy to clipboardprint?<!-- js 파일 import --> <!--%import("js/xe_official.js")--> <!--%import("js/jquery.js")--> <!-- js 파일 import --> <!--%import("js/xe_official.js")--> <!--%import("js/jquery.js")-->
#2. W3C Markup & CSS 유효성 통과를 위한 커스터마이징
혹시 이 글을 보시는 분이 유효성 검사에 대해 완벽주의자라면 제로보드 기본 파일에서 몇가지 수정이 필요합니다. 아시다시피 제로보드는 기본적으로 웹 표준을 아주 잘 지키고 있고 CSS에서 에러가 나는 부분도 브라우저 접근성 때문에 필요악으로 생긴 Hack 부분에 한합니다. 하지만 이것마저도 눈에 거슬린다면 아래의 지침을 따라보세요. 만일 CSS Validator나 Markup Validator에서 "축하합니다! 이 페이지는 유효성을 통과한 검증된 페이지입니다!"라는 메세지 따윈 신경쓰지 않는다면 이 파트는 읽지않고 그냥 넘어가세요. 기본적으로 CSS Validaotr에서 여러분의 제로보드 페이지를 검사했을 때 검출되는 에러에 해당되는 부분들(button.css라던가 iePngFix와 같은 부분)은 모두 CSS 파일에서 삭제해도 제로보드 작동에는 아무런 문제가 없습니다. button.css의 경우에는 제로보드 전체적으로 사용하는 각종 버튼들을 라운드 형식으로 예쁘게 꾸민 CSS 파일입니다. 이 파일에는 IE, Firefox, Opera, Safari등과 같은 메이져 브라우저들에 대해 동일한 Look이 보여질 수 있도록 접근성용 Hack 부분을 설정해 놓았는데, 이러한 Hack이 유효성 검사기에서 에러를 냅니다.

한가지 분명히 알고 넘어갈 것은, Hack을 쓰지 않고도 모든 메이져급 브라우저에서 동일한 접근성을 유지 시키는 방법은 분명히 있습니다. 하지만 이것은 유저가 직접 추가적인 CSS를 작성해서 사용해야 하기 때문에 제로보드에서는 편의를 위해 하나의 CSS에서 해결하고 있는 것 입니다. 만일 애드온 자료실의 ButtonChange와 같은 좋은 애드온등의 사용을 포기하면서까지 유효성을 지키고 싶다면 button.css의 CSS 에러 구문을 모두 삭제하십시오. 이것을 삭제하므로 해서 여러분은 무척 귀찮은 작업들을 해야만 합니다. 제로보드 전반에 걸쳐 이 파일의 셀렉터로 사용되고 있는 button이라는 클래스를 모두 별도의 클래스로 바꾸어 지정하던가 혹은 /common/css/button.css를 직접 수정해서 일괄적으로 사용 할 버튼을 만들어야 합니다.

button.css에서 에러를 발생시키는 CSS 에러구문을 모두 없애면서 제로보드 페이지 전반적으로 동일 한 Look의 버튼을 사용하고 싶다면 직접 button.css 파일을 수정해서 하세요. WTA의 경우는 때에 따라 서로 모양이 다른 버튼을 써야 할 때가 있기 때문에 button.css 파일은 단순한 모양을 지닌 Dummy 파일로만 사용하고 HTML 페이지에 정의된 ,button 클래스명을 바꿔서 사용하고 있습니다. WTA에서 사용하는 Dummy 파일이 필요하다면 button.zip을 다운받으세요. 이 CSS 파일은 모든 CSS 에러구문이 삭제되고 기존의 버튼을 회색의 단조로운 버튼으로 바꿉니다. 관리자 페이지등에서도 이 버튼이 나타나게되고 제가 깔끔하게 다듬지 않아 모양이 좋지 않습니다. 어차피 관리자 페이지는 자신만 보는 것이므로 이와같이 더미 버튼을 사용하고, 방문자들이 보게 될 부분의 버튼들은 각 HTML 파일의 .button 클래스를 여러분이 새로 지정한 버튼 모양의 클래스로 변경하세요.

이런 일련의 작업들이 너무나도 귀찮고 번거롭다면 유효성 검사에 뜻을 두지 마시고 그냥 사용하세요.

/common/css/default.css에서도 에러 구문이 있습니다. CSS Validator에서 보여주는 에러 구문들을 찾아 모두 삭제하면 PNG 투명 이미지의 사용에 문제가 발생합니다. 이 문제는 Jquery 기반에서 동작하는 PNG-Transparency for Windows IE 5.5 & 6을 사용해서 CSS 에러 없이 해결 할 수 있습니다. 이 PNG 핵은 웹사이트 전체적으로 사용되는 것이니 common 파트에 넣는 것이 좋습니다. 다운로드 받은 파일을 /common/js폴더에 넣은 후 common/tpl/common_layout.html에 아래와 같이 추가하세요. 아래의 코드에서 추가되는 구문은 9번째 줄 이 한줄 입니다.


<meta http-equiv="imagetoolbar" content="no" />
<title>{Context::getBrowserTitle()}</title>
{@ $js_files = Context::getJsFile() }
<!--@foreach($js_files as $key => $js_file)-->
<!--@if($js_file['targetie'])-->
<!--[if {$js_file['targetie']}]>
<!--@end-->
<script type="text/javascript" src="{$js_file['file']}"></script>
<script type="text/javascript" src="../common/js/jquery.pngFix.js"></script>
<!--@if($js_file['targetie'])-->
<![endif]-->
12. <!--@end-->
<!--@end-->


button.css와 default.css 그리고 common_layout.html 파일 3가지의 파일을 수정함으로해서 여러분은 제로보드 XE에서 발생하는 모든 CSS 에러 구문을 없애고 유효성 검사에 통과하면서도 기존과 동일한 브라우저 접근성을 유지 할 수 있습니다.
by Anna 안나 2008. 11. 14. 21:27
수정할 파일은 2개, 추가할 파일은 2개입니다.

먼저 추가할 파일부터 추가합니다.

추가할 파일 view_document_fold.html<!--@if(($document_srl || $rnd)&&count($document_list)==1)-->
{@ $block_class = "blog_not_fold"; }
{@ $display_style = "block"; }
<!--@else-->
{@ $block_class = "blog_auto_fold"; }
{@ $display_style = "none"; }
<!--@end-->

<div class="boardRead">
<div class="originalContent">
<div class="readHeader">
<div class="titleAndUser">

<div class="title">
<h4><a href="{$oDocument->getPermanentUrl()}">{$oDocument->getTitle()}</a></h4>
</div>

<!--@if($module_info->display_author!='N')-->
<div class="userInfo">
<!--@if(!$oDocument->getMemberSrl())-->
<div class="author">
<!--@if($oDocument->isExistsHomepage())-->
<a href="{$oDocument->getHomepageUrl()}" onclick="window.open(this.href);return false;">{$oDocument->getNickName()}</a>
<!--@else-->
{$oDocument->getNickName()}
<!--@end-->
</div>
<!--@else-->
<div class="author"><span class="member_{$oDocument->get('member_srl')}">{$oDocument->getNickName()}</span></div>
<!--@end-->
</div>
<!--@end-->

<div class="clear"></div>

</div>

<div class="dateAndCount">
<div class="uri" title="{$lang->document_url}"><a href="{$oDocument->getPermanentUrl()}">{$oDocument->getPermanentUrl()}</a></div>

<div class="date" title="{$lang->regdate}">
<strong>{$oDocument->getRegdate('Y.m.d')}</strong> {$oDocument->getRegdate('H:i:s')} <!--@if($grant->is_admin || $module_info->display_ip_address!='N')-->({$oDocument->getIpaddress()})<!--@end-->
</div>

<div class="readedCount" title="{$lang->readed_count}">{$oDocument->get('readed_count')}</div>

<!--@if($oDocument->get('voted_count')!=0 || $oDocument->get('blamed_count')!=0)-->
<div class="votedCount" title="{$lang->voted_count}">
<strong>{$oDocument->get('voted_count')} / {$oDocument->get('blamed_count')}</strong>
</div>
<!--@end-->

<div class="replyAndTrackback">
<!--@if($grant->write_comment && $oDocument->allowComment()) -->
<div class="replyCount"><a href="#comment" title="{$lang->comment}"><strong>{$oDocument->getCommentcount()}</strong></a></div>
<!--@end-->
<!--@if($oDocument->allowTrackback() && $oDocument->getTrackbackCount() )-->
<div class="trackbackCount"><a href="#trackback" title="{$lang->trackback}"><strong>{$oDocument->getTrackbackCount()}</strong></a></div>
<!--@end-->
</div>

<!--@if($module_info->use_category == "Y" && $oDocument->get('category_srl'))-->
<div class="category" title="{$lang->category}"><a href="{getUrl('category',$oDocument->get('category_srl'), 'document_srl', '')}">{$category_list[$oDocument->get('category_srl')]->title}</a></div>
<!--@end-->

<div class="clear"></div>
</div>

<div class="clear"></div>
</div>

<div class="clear"></div>

<!--@if($oDocument->isExtraVarsExists() && (!$oDocument->isSecret() || $oDocument->isGranted()) )-->
<table cellspacing="0" summary="" class="extraVarsList">
<col width="150" />
<col />
<!--@foreach($module_info->extra_vars as $key => $val)-->
<!--@if($val->name)-->
<tr>
<th scope="row">{$val->name}</th>
<td>
<!--// 확장변수(extra_var)의 type에 따른 값을 출력하기 위해서 특별히 제작된 파일을 include 한다 -->
<!--#include("./extra_var_value.html")-->
</td>
</tr>
<!--@end-->
<!--@end-->
</table>
<!--@end-->

<div class="readBody">
<div class="contentBody">

<!--@if($oDocument->isSecret() && !$oDocument->isGranted())-->
<!--%import("filter/input_password.xml")-->
<div class="secretContent">
<form action="./" method="get" onsubmit="return procFilter(this, input_password)">
<input type="hidden" name="mid" value="{$mid}" />
<input type="hidden" name="page" value="{$page}" />
<input type="hidden" name="document_srl" value="{$oDocument->document_srl}" />

<div class="title">{$lang->msg_is_secret}</div>
<div class="content"><input type="password" name="password" id="cpw" class="inputTypeText" /><span class="button"><input type="submit" value="{$lang->cmd_input}" accesskey="s" /></span></div>

</form>
</div>
<!--@else-->

<!-- 썸네일 출력 -->
<!--@if($oDocument->thumbnailExists($t[1], $t[2], $t[0]))-->
{@ $val->value = $oDocument->getExtraValue($module_info->link_thumbnail)}
{@ $val->type = $module_info->extra_vars[$module_info->link_thumbnail]->type}

<!--@if($module_info->link_thumbnail=='content' && !$val->type && !$val->value)-->
<a href="{$oDocument->getPermanentUrl()}">

<!--@elseif($module_info->link_thumbnail=='view_image' && !$val->type && !$val->value)-->
{@ $uploaded_list = $oDocument->getUploadedFiles() }
<!--@foreach($uploaded_list as $key => $file)-->
{@$file_explode=explode(".",strtoupper($file->source_filename))}
<!--@if($file_explode[1]=="GIF" || $file_explode[1]=="JPG" || $file_explode[1]=="PNG" || $file_explode[1]=="BMP")-->
<a href="#view" onClick="gonyImgWin('{$file->uploaded_filename}')">
<!--@end-->
<!--@end-->

<!--@elseif($val->type && $val->value)-->
<!--#include("./extra_var_list_thumbnail.html")-->

<!--@else-->
<a href="{$oDocument->getPermanentUrl()}">

<!--@end-->
<img src="{$oDocument->getThumbnail($t[1], $t[2], $t[0])}" border="0" alt="" /></a><br /><br />

<!--@end-->
<!-- 썸네일 출력 out-->

<!-- Summary 출력-->
<!--@if($module_info->display_author=='Y' || !$module_info->extra_vars[$module_info->display_content]->type)-->
{@$i=1}
{$oDocument->getSummary($s[$i])}
<!--@elseif($module_info->extra_vars[$module_info->display_content]->type)-->
{@ $val->value = $oDocument->getExtraValue($module_info->display_content)}
{@ $val->type = $module_info->extra_vars[$module_info->display_content]->type}
<!--@if($oDocument->isSecret() && !$oDocument->isGranted())-->
{$lang->msg_is_secret}
<!--@else-->
<!--@if($val->type == 'homepage' || $val->type == 'email_address' || $val->type == 'image' || $val->type == 'media')-->
<!--@if(!$grant->view || $oDocument->isSecret() && !$oDocument->isGranted())--><!--@else--> {cut_str(htmlspecialchars($val->value),$s[1], '...')}<!--@end-->
<!--@else-->
{@$i=1}
<!--@if(!$grant->view || $oDocument->isSecret() && !$oDocument->isGranted())--><!--@else--> <!--#include("./extra_var_list.html")--><!--@end-->
<!--@end-->
<!--@end-->
<!--@end-->
<!-- Summary 출력 out-->

<span class="moreInfo"><a href="{$oDocument->getPermanentUrl()}">More..</a></span>
<!--@end-->

<div class="clear"></div>

<!-- 서명 / 프로필 이미지 출력 -->

</div>
</div>
</div>

<!-- 목록, 수정/삭제 버튼 -->
<div class="contentButton">
<!--@if($module_info->default_style != 'blog')-->
<a href="{getUrl('document_srl','')}" class="button"><span>{$lang->cmd_list}</span></a>
<!--@end-->
<!--@if($oDocument->isEditable())-->
<a href="{getUrl('act','dispBoardWrite','document_srl',$oDocument->document_srl,'comment_srl','')}" class="button"><span>{$lang->cmd_modify}</span></a>
<a href="{getUrl('act','dispBoardDelete','document_srl',$oDocument->document_srl,'comment_srl','')}" class="button"><span>{$lang->cmd_delete}</span></a>
<!--@end-->
</div>

</div>

<!-- 엮인글 -->
<!--@if($oDocument->allowTrackback())-->
<!--#include("./trackback.html")-->
<!--@end-->

<!-- 댓글 -->

<!-- 댓글 입력 폼 --><!-- 글 내용 보여주기 -->


view_document_nofold.html
<!-- 글 내용 보여주기 -->
<!--@if(($document_srl || $rnd)&&count($document_list)==1)-->
{@ $block_class = "blog_not_fold"; }
{@ $display_style = "block"; }
<!--@else-->
{@ $block_class = "blog_auto_fold"; }
{@ $display_style = "none"; }
<!--@end-->

<div class="boardRead">
<div class="originalContent">
<div class="readHeader">
<div class="titleAndUser">

<div class="title">
<h4><a href="{$oDocument->getPermanentUrl()}">{$oDocument->getTitle()}</a></h4>
</div>

<!--@if($module_info->display_author!='N')-->
<div class="userInfo">
<!--@if(!$oDocument->getMemberSrl())-->
<div class="author">
<!--@if($oDocument->isExistsHomepage())-->
<a href="{$oDocument->getHomepageUrl()}" onclick="window.open(this.href);return false;">{$oDocument->getNickName()}</a>
<!--@else-->
{$oDocument->getNickName()}
<!--@end-->
</div>
<!--@else-->
<div class="author"><span class="member_{$oDocument->get('member_srl')}">{$oDocument->getNickName()}</span></div>
<!--@end-->
</div>
<!--@end-->

<div class="clear"></div>

</div>

<div class="dateAndCount">
<div class="uri" title="{$lang->document_url}"><a href="{$oDocument->getPermanentUrl()}">{$oDocument->getPermanentUrl()}</a></div>

<div class="date" title="{$lang->regdate}">
<strong>{$oDocument->getRegdate('Y.m.d')}</strong> {$oDocument->getRegdate('H:i:s')} <!--@if($grant->is_admin || $module_info->display_ip_address!='N')-->({$oDocument->getIpaddress()})<!--@end-->
</div>

<div class="readedCount" title="{$lang->readed_count}">{$oDocument->get('readed_count')}</div>

<!--@if($oDocument->get('voted_count')!=0 || $oDocument->get('blamed_count')!=0)-->
<div class="votedCount" title="{$lang->voted_count}">
<strong>{$oDocument->get('voted_count')} / {$oDocument->get('blamed_count')}</strong>
</div>
<!--@end-->

<div class="replyAndTrackback">
<!--@if($grant->write_comment && $oDocument->allowComment()) -->
<div class="replyCount"><a href="#comment" title="{$lang->comment}"><strong>{$oDocument->getCommentcount()}</strong></a></div>
<!--@end-->
<!--@if($oDocument->allowTrackback() && $oDocument->getTrackbackCount() )-->
<div class="trackbackCount"><a href="#trackback" title="{$lang->trackback}"><strong>{$oDocument->getTrackbackCount()}</strong></a></div>
<!--@end-->
</div>

<!--@if($module_info->use_category == "Y" && $oDocument->get('category_srl'))-->
<div class="category" title="{$lang->category}"><a href="{getUrl('category',$oDocument->get('category_srl'), 'document_srl', '')}">{$category_list[$oDocument->get('category_srl')]->title}</a></div>
<!--@end-->

<div class="clear"></div>
</div>

<div class="clear"></div>
</div>

<div class="clear"></div>

<!--@if($oDocument->isExtraVarsExists() && (!$oDocument->isSecret() || $oDocument->isGranted()) )-->
<table cellspacing="0" summary="" class="extraVarsList">
<col width="150" />
<col />
<!--@foreach($module_info->extra_vars as $key => $val)-->
<!--@if($val->name)-->
<tr>
<th scope="row">{$val->name}</th>
<td>
<!--// 확장변수(extra_var)의 type에 따른 값을 출력하기 위해서 특별히 제작된 파일을 include 한다 -->
<!--#include("./extra_var_value.html")-->
</td>
</tr>
<!--@end-->
<!--@end-->
</table>
<!--@end-->

<div class="readBody">
<div class="contentBody">

<!--@if($oDocument->isSecret() && !$oDocument->isGranted())-->
<!--%import("filter/input_password.xml")-->
<div class="secretContent">
<form action="./" method="get" onsubmit="return procFilter(this, input_password)">
<input type="hidden" name="mid" value="{$mid}" />
<input type="hidden" name="page" value="{$page}" />
<input type="hidden" name="document_srl" value="{$oDocument->document_srl}" />

<div class="title">{$lang->msg_is_secret}</div>
<div class="content"><input type="password" name="password" id="cpw" class="inputTypeText" /><span class="button"><input type="submit" value="{$lang->cmd_input}" accesskey="s" /></span></div>

</form>
</div>
<!--@else-->
{$oDocument->getContent()}
<!--@end-->

<!-- 서명 / 프로필 이미지 출력 -->
<!--@if($oDocument->getProfileImage() || $oDocument->getSignature())-->
<div class="memberSignature">
<!--@if($oDocument->getProfileImage())-->
<div class="profile"><img src="{$oDocument->getProfileImage()}" alt="profile" /></div>
<!--@end-->
<!--@if($oDocument->getSignature())-->
<div class="signature">{$oDocument->getSignature()}</div>
<!--@end-->
<div class="clear"></div>
</div>
<!--@end-->
</div>
</div>

{@ $tag_list = $oDocument->get('tag_list') }
<!--@if(count($tag_list))-->
<div class="tag">
<ul>
<!--@for($i=0;$i<count($tag_list);$i++)-->
{@ $tag = $tag_list[$i]; }
<li><a href="{getUrl('search_target','tag','search_keyword',$tag,'document_srl','')}" rel="tag">{htmlspecialchars($tag)}</a><!--@if($i<count($tag_list)-1)-->,&nbsp;<!--@end--></li>
<!--@end-->
</ul>
</div>
<!--@end-->

<!--@if($oDocument->hasUploadedFiles())-->
<div class="fileAttached">
{@ $uploaded_list = $oDocument->getUploadedFiles() }
<ul>
<!--@foreach($uploaded_list as $key => $file)-->
<li><a href="{getUrl('')}{$file->download_url}">{$file->source_filename} ({FileHandler::filesize($file->file_size)})({number_format($file->download_count)})</a></li>
<!--@end-->
</ul>
<div class="clear"></div>
</div>
<!--@end-->
</div>

<!-- 목록, 수정/삭제 버튼 -->
<div class="contentButton">
<a href="{getUrl('','mid',$mid,'page',$page,'document_srl','','listStyle',$listStyle)}" class="button"><span>{$lang->cmd_list}</span></a>
<!--@if($oDocument->isEditable())-->
<a href="{getUrl('act','dispBoardWrite','document_srl',$oDocument->document_srl,'comment_srl','')}" class="button"><span>{$lang->cmd_modify}</span></a>
<a href="{getUrl('act','dispBoardDelete','document_srl',$oDocument->document_srl,'comment_srl','')}" class="button"><span>{$lang->cmd_delete}</span></a>
<!--@end-->
</div>

</div>

<!-- 엮인글 -->
<!--@if($oDocument->allowTrackback())-->
<!--#include("./trackback.html")-->
<!--@end-->

<!-- 댓글 -->
<a name="comment"></a>
<!--#include("./comment.html")-->

<!-- 댓글 입력 폼 -->
<!--@if($grant->write_comment && $oDocument->isEnableComment() )-->
<!--%import("filter/insert_comment.xml")-->
<form action="./" method="post" onsubmit="return procFilter(this, insert_comment)" class="boardEditor" >
<input type="hidden" name="mid" value="{$mid}" />
<input type="hidden" name="document_srl" value="{$oDocument->document_srl}" />
<input type="hidden" name="comment_srl" value="" />
<input type="hidden" name="content" value="" />
<div class="boardWrite commentEditor">
<div class="userNameAndPw">
<!--@if(!$is_logged)-->
<label for="userName">{$lang->writer}</label>
<input type="text" name="nick_name" value="" class="userName inputTypeText" id="userName"/>

<label for="userPw">{$lang->password}</label>
<input type="password" name="password" value="" id="userPw" class="userPw inputTypeText" />

<label for="emailAddress">{$lang->email_address}</label>
<input type="text" name="email_address" value="" id="emailAddress" class="emailAddress inputTypeText"/>

<label for="homePage">{$lang->homepage}</label>
<input type="text" name="homepage" value="" id="homePage" class="homePage inputTypeText"/>
<!--@else-->
<input type="checkbox" name="notify_message" value="Y" id="notify_message" />
<label for="notify_message">{$lang->notify}</label>
<!--@end-->

<input type="checkbox" name="is_secret" value="Y" id="is_secret" />
<label for="is_secret">{$lang->secret}</label>

</div>

<div class="editor">{$oDocument->getCommentEditor()}</div>
</div>

<div class="commentButton tRight">
<span class="button"><input type="submit" value="{$lang->cmd_comment_registration}" accesskey="s" /></span>
</div>
</form>
<!--@end-->
수정할 파일style_blog.html <!--#include("./view_document_nofold.html")-->_nofold 를 추가



수정전
<!--// 글이 선택되어 있거나 검색어가 있으면 목록을 출력 -->
<!--#include("./style.list.html")-->수정후
<!--// 글이 선택되어 있거나 검색어가 있으면 목록을 출력 -->
<!--@foreach($document_list as $no => $oDocument)-->
<div class="viewDocument">
<!--#include("./view_document_fold.html")-->
</div>
<!--@end-->

수정전
<div class="viewDocument">
<!--#include("./view_document.html")-->
</div>수정후
<div class="viewDocument">
<!--#include("./view_document_nofold.html")-->
</div>
수정전
<div class="viewDocument">
<!--#include("./view_document.html")-->
</div>
수정후
<div class="viewDocument">
<!--#include("./view_document_fold.html")-->
</div>
style_blog.html 수정된 파일(zbXE 1.0.6기준)



<!-- 검색된 글 목록이 있고 권한이 있을 경우 출력 -->
<!--@if($grant->list)-->

<!--@if($category || $search_keyword)-->

<!--@if($oDocument->isExists())-->
<div class="viewDocument">
<!--#include("./view_document_nofold.html")-->
</div>
<!--@end-->

<!--// 글이 선택되어 있거나 검색어가 있으면 목록을 출력 -->
<!--@foreach($document_list as $no => $oDocument)-->
<div class="viewDocument">
<!--#include("./view_document_fold.html")-->
</div>
<!--@end-->

<!--@elseif($oDocument->isExists())-->

<div class="viewDocument">
<!--#include("./view_document_nofold.html")-->
</div>

<!--@else-->

<!--// 공지사항 -->
<!--@if($notice_list)-->
<div class="blogNotice">
<!--@foreach($notice_list as $no => $document)-->
<div class="item">
<span class="date">[{$document->getRegdate("Y-m-d")}]</span>
<a href="{getUrl('document_srl',$document->document_srl,'cpage','')}">{$document->getTitle()}</a>

<!--@if($document->getCommentCount())-->
<span class="replyAndTrackback" title="Replies"><img src="./images/{$module_info->colorset}/iconReply.gif" alt="" width="12" height="12" class="icon" /> <strong>{$document->getCommentCount()}</strong></span>
<!--@end-->

<!--@if($document->getTrackbackCount())-->
<span class="replyAndTrackback" title="Trackbacks"><img src="./images/{$module_info->colorset}/iconTrackback.gif" alt="" width="12" height="13" class="trackback icon" /> <strong>{$document->getTrackbackCount()}</strong></span>
<!--@end-->

{$document->printExtraImages(60*60*$module_info->duration_new)}
</div>
<!--@end-->
</div>
<!--@end-->

<!--// 일반글 -->
<!--@foreach($document_list as $no => $oDocument)-->
<div class="viewDocument">
<!--#include("./view_document_fold.html")-->
</div>
<!--@end-->

<!--@end-->

<!--@end-->



**.css (style file)
.boardRead .readBody .contentBody span.moreInfo a {}
위처럼 지정해줍니다. 예시는 아래와 같습니다.
.boardRead .readBody .contentBody span.moreInfo a { float:right; padding-top:5px; padding-left:16px; }
.boardRead .readBody .contentBody span.moreInfo a {color:#6b9228; font:bold 11px Arial, Helvetica, sans-serif; background:url("../images/glossary/iconTrackback.gif") no-repeat left 8px;}


이렇게만 잘 따라하셔도.. More 은 조심스럽게 추가됩니다.

블로그 메인에, 사용자에게 불필요한 메모리를 주는것을 막읍시다~^_^
어서들 적용하세요♡
by Anna 안나 2008. 11. 9. 01:56
본 자료는 제로보드 게시판(블로그용) 스킨인 'itheme' 를 기반으로 작성되었습니다.
'itheme' 게시판스킨은 'bomijoa.com' 님의 레이아웃에 포함된 게시판스킨입니다.
지금 쓰는 이 글은 제로보드 1.0.6 버전 기준으로 작성합니다.
띄어쓰기 등의 쓸데없는 것은 당연히 뺐구요.

서두는 이만으로.. 본격적으로 연구(?)자료 발표를 시작합니다.



■ view_document_blog.html - 0
먼저 view_document.html를 복사한 후
복사된 파일 이름을 view_document_blog.html로 수정합니다.
그다음, 다음의 작업을 실행해주세요.

■ view_document_blog.html - 1
변경전
<div class="dateAndCount">
<div class="uri" title="{$lang->document_url}"><a href="{$oDocument->getPermanentUrl()}">{$oDocument->getPermanentUrl()}</a></div>

<div class="date" title="{$lang->regdate}">
<strong>{$oDocument->getRegdate('Y.m.d')}</strong> {$oDocument->getRegdate('H:i:s')} <!--@if($grant->is_admin || $module_info->display_ip_address!='N')-->({$oDocument->getIpaddress()})<!--@end-->
</div>
변경후
<div class="dateAndCount">
<!--@if($module_info->use_category == "Y" && $oDocument->get('category_srl'))-->
<div class="category" title="{$lang->category}"><a href="{getUrl('category',$oDocument->get('category_srl'), 'document_srl', '')}">{$category_list[$oDocument->get('category_srl')]->title}</a></div>
<!--@end-->
<!--@if($module_info->display_link_message=="Y") -->
<div class="uri" title="{$lang->document_url}"><a href="{$oDocument->getPermanentUrl()}">{$oDocument->getPermanentUrl()}</a></div>
<!--@end-->
<div class="date" title="{$lang->regdate}">
{$oDocument->getRegdate('m/d/Y')} {$oDocument->getRegdate('H:i')}
<!--@if(($module_info->display_ip_address=="Y")||($grant->is_admin)) -->
({$oDocument->getIpaddress()})
<!--@end-->
</div>
■ view_document_blog.html - 2
변경전
<strong>{$oDocument->get('voted_count')} / {$oDocument->get('blamed_count')}</strong>
변경후
{$oDocument->get('voted_count')} / {$oDocument->get('blamed_count')}
■ view_document_blog.html - 3
변경전
<div class="replyCount"><a href="#comment" title="{$lang->comment}"><strong>{$oDocument->getCommentcount()}</strong></a></div>
변경후
<div class="replyCount"><a href="{$oDocument->getPermanentUrl()}#comment" title="{$lang->comment}"><strong>{$oDocument->getCommentcount()}</strong></a></div>
■ view_document_blog.html - 4
변경전
<!--@if($module_info->use_category == "Y" && $oDocument->get('category_srl'))-->
<div class="category" title="{$lang->category}"><a href="{getUrl('category',$oDocument->get('category_srl'), 'document_srl', '')}">{$category_list[$oDocument->get('category_srl')]->title}</a></div>
<!--@end-->

변경후
삭제

■ view_document_blog.html - 5
변경전
{$oDocument->getContent()}
변경후
<!--@if(($module_info->display_document_popup_menu=="Y") ||($grant->is_admin))-->
{$oDocument->getContent(true)}
<!--@else-->
{$oDocument->getSummary2($module_info->display_lines_blog)}
<br>
<br>
<a href="{$oDocument->getPermanentUrl()}"> <STRONG> MORE &gt;&gt;&gt; </STRONG> </a>
<br>
<!--@end-->
■ view_document_blog.html - 6
변경전
<!--@if($oDocument->hasUploadedFiles())-->
<div class="fileAttached">
{@ $uploaded_list = $oDocument->getUploadedFiles() }
<ul>
<!--@foreach($uploaded_list as $key => $file)-->
<li><a href="{getUrl('')}{$file->download_url}">{$file->source_filename} ({FileHandler::filesize($file->file_size)})({number_format($file->download_count)})</a></li>
<!--@end-->
</ul>
<div class="clear"></div>
</div>
<!--@end-->
변경후
삭제

■ view_document_blog.html - 7
변경전
<!-- 목록, 수정/삭제 버튼 -->
<div class="contentButton">
<!--@if($module_info->default_style != 'blog')-->
<a href="{getUrl('document_srl','')}" class="button"><span>{$lang->cmd_list}</span></a>
<!--@end-->
<!--@if($oDocument->isEditable())-->
<a href="{getUrl('act','dispBoardWrite','document_srl',$oDocument->document_srl,'comment_srl','')}" class="button"><span>{$lang->cmd_modify}</span></a>
<a href="{getUrl('act','dispBoardDelete','document_srl',$oDocument->document_srl,'comment_srl','')}" class="button"><span>{$lang->cmd_delete}</span></a>
<!--@end-->
</div>

</div>

<!-- 엮인글 -->
<!--@if($oDocument->allowTrackback())-->
<!--#include("./trackback.html")-->
<!--@end-->
변경후
<!-- 목록, 수정/삭제 버튼 -->
<!--@if(($module_info->default_style != 'blog')||($oDocument->isEditable()))-->
<div class="contentButton">
<!--@if($module_info->default_style != 'blog')-->
<a href="{getUrl('document_srl','')}" class="button"><span>{$lang->cmd_list}</span></a>
<!--@end-->
<!--@if($oDocument->isEditable())-->
<a href="{getUrl('act','dispBoardWrite','document_srl',$oDocument->document_srl,'comment_srl','')}" class="button"><span>{$lang->cmd_modify}</span></a>
<a href="{getUrl('act','dispBoardDelete','document_srl',$oDocument->document_srl,'comment_srl','')}" class="button"><span>{$lang->cmd_delete}</span></a>
<!--@end-->
</div>
<!--@end-->

</div>


<!--@if($module_info->display_comment_enable=="Y")-->
■ view_document_blog.html - 8
변경전
<!-- 댓글 입력 폼 -->
<!--@if($grant->write_comment && $oDocument->isEnableComment() )-->
<!--%import("filter/insert_comment.xml")-->
<form action="./" method="post" onsubmit="return procFilter(this, insert_comment)" class="boardEditor" >
<input type="hidden" name="mid" value="{$mid}" />
<input type="hidden" name="document_srl" value="{$oDocument->document_srl}" />
<input type="hidden" name="comment_srl" value="" />
<input type="hidden" name="content" value="" />
<div class="boardWrite commentEditor">
<div class="userNameAndPw">
<!--@if(!$is_logged)-->
<label for="userName">{$lang->writer}</label>
<input type="text" name="nick_name" value="" class="userName inputTypeText" id="userName"/>

<label for="userPw">{$lang->password}</label>
<input type="password" name="password" value="" id="userPw" class="userPw inputTypeText" />

<label for="emailAddress">{$lang->email_address}</label>
<input type="text" name="email_address" value="" id="emailAddress" class="emailAddress inputTypeText"/>

<label for="homePage">{$lang->homepage}</label>
<input type="text" name="homepage" value="" id="homePage" class="homePage inputTypeText"/>
<!--@else-->
<input type="checkbox" name="notify_message" value="Y" id="notify_message" />
<label for="notify_message">{$lang->notify}</label>
<!--@end-->

<input type="checkbox" name="is_secret" value="Y" id="is_secret" />
<label for="is_secret">{$lang->secret}</label>

</div>

<div class="editor">{$oDocument->getCommentEditor()}</div>
</div>

<div class="commentButton tRight">
<span class="button"><input type="submit" value="{$lang->cmd_comment_registration}" accesskey="s" /></span>
</div>
</form>
변경후
<!-- 댓글 입력 폼 -->
■ style_blog.html - 1
변경전
<!--@if($category || $search_keyword)-->

<!--@if($oDocument->isExists())-->
<div class="viewDocument">
<!--#include("./view_document.html")-->
</div>
<!--@end-->

<!--// 글이 선택되어 있거나 검색어가 있으면 목록을 출력 -->
<!--#include("./style.list.html")-->
변경후
<!--@if($category)-->

<!--@foreach($document_list as $no => $oDocument)-->
<div class="viewDocument">
<!--#include("./view_document_blog.html")-->
</div>
<!--@end-->

<!--@elseif($search_keyword)-->
■ style_blog.html - 2
변경전
<!--#include("./view_document.html")-->
변경후
<!--#include("./view_document_blog.html")-->
맺음글
■ 맺음
맺음글
* 본 글은 작성중입니다. *
by Anna 안나 2008. 11. 8. 21:18
제로보드 사이트에서 몇몇 분들이 소스를 공개해 달라고 하셔서 원리를 설명 드릴까 합니다.

근데 참 어려운게 페이지 원리 이전에 위젯의 원리부터 설명해야할 필요가 있다는게... ㅠㅠ

위젯 프로그램은 ./widgets 라는 폴더안에 들어가 있으며, 이곳에 있어야지 실행가능 합니다.

newest_document 스킨을 이용한 페이지 기능 설치 방법을 설명 드리겠습니다.

추가, 수정에 필요한 파일들(실행 순서대로 나열합니다.)
newest_document/conf/info.xml <- 입력을 받기 위한 입력창
: 관리자페이지에서 코드 실행하기전에 이곳으로부터 정보를 입력 받습니다.
newest_document/newest_document.class.php <- 입력 받은 정보를 처리
: 입력 받은 정보를 적절히 정리해서 DB로 부터 결과값들을 받고 스킨 처리를 하는 파일
newest_document/queries/getNewestDocuments.xml <- DB Query용 XML 파일
: $page 번호 값에 따라서 결과를 출럭하기 위해 <navigation>에 내용을 추가 해야 합니다.
newest_document/queries/getNewestDocumentsCount.xml <- DB Query용 XML 파일
: 결과값용 Query와 다르게 페이지 기능을 만들기 위해 하나의 Query를 더 해야합니다.
newest_document/skins/default/list.html <- DB로 부터의 결과를 이용하여 표현하는 스킨 파일


- info.xml -
<var id="page_count">
<name xml:lang="ko">페이지 목록수</name>
<type>text</type>
<description xml:lang="ko">출력될 페이지의 수를 정하실 수 있습니다. (기본 5개)</description>
</var>
<var id="page_type">
<name xml:lang="ko">페이지 출력 여부</name>
<type>select</type>
<description xml:lang="ko">페이지를 출력할지 선택하세요.</description>
<options>
<name xml:lang="ko">N</name>
<value></value>
</options>
<options>
<name xml:lang="ko">Y</name>
<value>Y</value>
</options>
</var>
xml용으로 된 정보 입력 방식입니다. 위의 page_count와 page_type이라는 정보를 받고
페이지 네비게이션 출력 여부나 출력 시 몇개 까지 출력할지 등을 정할 수 있도록 추가합니다.


- newest_document.class.php [중요] -

이 파일에서 거의 모든 기능을 하기 때문에 이곳에서의 진행내용을 이해하지 못하면 만들기 어렵습니다.
우선, 페이지 기능을 만들기 위해서는 약간의 산수가 필요합니다.
그리고 계산을 위한 값이 만들어져야 겠지요.
$output = executeQueryArray('widgets.newest_document.getNewestDocuments', $obj);
이것을 기준점으로 위쪽은 정보를 어떻게 DB로 보낼지 입력 받은걸 처리하는 과정이며,
아래쪽은 DB에서로 부터 나온 결과물을 어떻게 처리할지의 과정이라고 보시면 됩니다.

/* 페이지 네비게이션 기능 추가 */
// 페이지 목록 수 (1,2,3,4....)
$page_count = $args->page_count;
if(!$page_count) $page_count = 5;
$obj->page_count = $page_count;

// 페이지 출력 여부
$page_type = $args->page_type;

// 페이지 번호 구하기
if($page_type=='Y') $obj->page = (Context::get('page'))? Context::get('page'): 1;
/* 페이지 네비게이션 기능 추가 끝 */
간단히 설명 들어갑니다.
info.xml로 부터 입력 받은 값들은 상단에 function proc($args) {} 선언으로 부터 넘어오게 됩니다.
$args에는 아까 입력했던 page_count나 page_type 등이 포함하여 많은 정보들이 넘어오게 됩니다.

$page_count = $args->page_count;
if(!$page_count) $page_count = 5;
$obj->page_count = $page_count;

넘어온 page_count에 값이 없으면 기본값을 생성하기 위해 위와 같은 처리를 해줍니다.
(넘어온 데이터를 굳이 $page_count로 불필요하게 만들어서 담는 이유는 DB처리 후에
페이지 계산을 위해서 필요하기 때문에 마 본인이 별도로 담아 놓은 것이니 큰 신경쓰지마시길 바랍니다.)

$page_type = $args->page_type;
DB로 넘어가는 값이 아닌 skin과 함수상의 처리이기 때문에 $obj로 넘기지 않습니다.
if($page_type=='Y') $obj->page = (Context::get('page'))? Context::get('page'): 1;

페이지를 사용하기로 했다면 현재 주소에 페이지가 있는지 검사 후 없으면 기본값 1로 대처하도록 합니다.
(Context::get('변수')는 주소창에서 index.php?aaa=bbb&ccc=ddd 등의 매개변수의 값을 뽑아오는 방법 입니다.)
$output = executeQueryArray('widgets.newest_document.getNewestDocuments', $obj);
$output_count = executeQueryArray('widgets.newest_document.getNewestDocumentsCount', $obj);
widgets.newest_document.getNewestDocuments 는
widgets/newest_document/getNewestDocuments.xml 의 정보를 불러오는 의미 입니다.


$output과 또 하나 $output_count 부분을 하나더 만들어서 페이지 계산을 위해
위젯의 결과물을 뽑으려고 하는 대상의 전체 게시물 수를 뽑습니다.
// 페이지용 Query에 오류가 생기면 그냥 무시
if(!$output_count->toBool()) return;
/* 페이지 네비게이션 기능 추가 */
$widget_info->page_type = $page_type;
$widget_info->total_count = $output_count->data[0]->count; // 전체 개시물 수
$widget_info->page = (!Context::get('page'))? 1:Context::get('page'); // 현재 페이지
// 총 페이지 수
$total_count = $widget_info->total_count/$list_count;
if($widget_info->total_count%$list_count != 0) $total_count+=1;
$widget_info->total_page = floor($total_count); // 총 페이지 수
$widget_info->page_count = $page_count; // 총 페이지 수
/* 페이지 네비게이션 기능 추가 끝 */
본격적으로 페이지 기능 구현을 위한 정보들을 뽑아 정리 합니다.
$widget_info->page_type = $page_type;

아까전에 $page_type으로 저장했던 info.xml에서 받아온 출력여부를 저장합니다.
(별도로 $widget_info로 저장한 이유는 skins파일에 한번에 모아서 정보를 보낼려고 하는 겁니다.)
$widget_info->total_count = $output_count->data[0]->count; // 전체 개시물 수
$output_count에서의 결과물이 단일일(한줄) 경우에는 위와 같이 직접 그 값에 접근시키면 됩니다.
$widget_info->page = (!Context::get('page'))? 1:Context::get('page'); // 현재 페이지

위에 DB로 넘기기전에 선언했던 방식인데 이곳에서도 선언하도록 했습니다.(페이지 계산을 위해)

페이지 기능 계산을 위해서는 총 게시물의 수, 한페이지당 출력 수, 페이지번호 수 등의 값이 필요합니다.
$total_count = $widget_info->total_count/$list_count;
전체 게시물수/현재 페이지 수 = 총 페이지번호가 나오겠지요.

if($widget_info->total_count%$list_count != 0) $total_count+=1;
변수는 0부터 시작하기 때문에 표현을 위해서 0이 나오면 1이 되도록 하나씩 더 합니다.

$widget_info->total_page = floor($total_count); // 총 페이지 수
floor() 함수를 이용해서 혹시나 나오는 소수점을 제거 합니다.
$widget_info->page_count = $page_count; // 총 페이지 수

페이지 갯수를 skin처리를 위해 넘깁니다.



다음은 skin파일에서 역으로 newest_document.class.php안의 함수를 호출하여 page 내용을 받아오기 위한 함수들 입니다.
/**
* @brief 다음 페이지 요청
**/
function WD_getNextPage($total_count, $total_page, $cur_page, $page_count = 10) {

$first_page = $cur_page - (int)($page_count/2);
if($first_page<1) $first_page = 1;
$last_page = $total_page;
if($last_page>$total_page) $last_page = $total_page;
if($total_page < $page_count) $page_count = $total_page;

$GLOBALS['wd_total_page'] = $total_page;
$GLOBALS['wd_first_page'] = $first_page;
$GLOBALS['wd_page_count'] = $page_count;
$GLOBALS['wd_last_page'] = $last_page;

$page->first_page = $first_page;
$page->last_page = $last_page;

return $page;
}

function WD_getNextPage2() {
$page = $GLOBALS['wd_first_page']+$GLOBALS['wd_i']++;
if($GLOBALS['wd_i'] > $GLOBALS['wd_page_count'] || $page > $GLOBALS['wd_last_page']) $page = 0;
return $page;
}

function WD_getNextClear() {
$GLOBALS['wd_i'] = 0;
}
($GLOBALS['변수'] 를 이용한 이유는 원래 제로XE에서 만들어져 있는 곳을 보면, $this->변수로 써 처리 되어있는데 저는 이게 이상하게 못불러오더라고요. 위젯이라서 그런가?? 아무튼, 그래서 어쩔 수 없이 저리 처리했으며 $GLOBALS로 들어간 변수는 처리할때만이 아니라 그 해당 페이지에서의 완전한 종결까지 누적되어야 하기 때문에 저렇게 사용하였습니다.)



- getNewestDocuments.xml -
<query id="getNewestDocuments" action="select">
<tables>
<table name="documents" />
</tables>
<columns>
<column name="*" />
</columns>
<conditions>
<condition operation="in" column="module_srl" var="module_srl" filter="number" />
<condition operation="equal" column="category_srl" var="category_srl" pipe="and" />
</conditions>
<navigation>
<index var="sort_index" default="list_order" order="order_type" />
<list_count var="list_count" default="20" />
<page_count var="page_count" default="10" />
<page var="page" default="1" />
</navigation>
</query>
페이지별로의 결과를 뽑기 위해서 아래의 내용을 추가합니다.
<navigation> 안에
<page_count var="page_count" default="10" />
<page var="page" default="1" />
를 추가해주세요.

- getNewestDocumentsCount.xml -
<query id="getNewestDocumentsCount" action="select">
<tables>
<table name="documents" />
</tables>
<columns>
<column name="count(*)" alias="count" />
</columns>
<conditions>
<condition operation="in" column="module_srl" var="module_srl" filter="number" />
<condition operation="equal" column="category_srl" var="category_srl" pipe="and" />
</conditions>
<navigation>
<index var="sort_index" default="list_order" order="order_type" />
</navigation>
</query>
getNewestDocuments.xml 의 정보와는 다르게 전체 게시물 수를 구하기 위해
<column name="*" /> 을
<column name="count(*)" alias="count" /> 으로

<navigation> 에서 아래의 것을 제거합니다.
<list_count var="list_count" default="20" />


- list.html -
<!--@if($widget_info->page_type=='Y')-->
<!-- 페이지 네비게이션 -->
<div class="pageNavigation">
<a href="{getUrl('page','','document_srl','','division',$division,'last_division',$last_division)}" class="goToFirst">
<img src="./images/common/bottomGotoFirst.gif" alt="{$lang->first_page}" width="7" height="5" /></a>
<!-- 페이지 정보 구하기 위해 선언 -->
{@$page_view = WD_getNextPage($widget_info->total_count,$widget_info->total_page,$widget_info->page,$widget_info->page_count)}
<!-- 중복 페이지 정보 출력을 위해 사전 초기화 -->
{@WD_getNextClear()}
<!--@while($page_no = WD_getNextPage2())-->
<!--@if($widget_info->page == $page_no)-->
<span class="current">{$page_no}</span>
<!--@else-->
<span class="pageNavigations"><a href="{getUrl('page',$page_no,'document_srl','','division',$division,'last_division',$last_division)}" class="pageNavigation2">{$page_no}</a></span>
<!--@end-->
<!--@end-->
<a href="{getUrl('page',$page_view->last_page,'document_srl','','division',$division,'last_division',$last_division)}" class="goToLast">
<img src="./images/common/bottomGotoLast.gif" alt="{$lang->last_page}" width="7" height="5" /></a>
</div>
<!--@end-->
중요한 부분만 설명하겠습니다.

view plaincopy to clipboardprint?{@$page_view = WD_getNextPage($widget_info->total_count,$widget_info->total_page,$widget_info->page,$widget_info->page_count)} {@$page_view = WD_getNextPage($widget_info->total_count,$widget_info->total_page,$widget_info->page,$widget_info->page_count)}
아까 넘겼던 전체 게시물 수, 전체 페이지 갯수, 현재 페이지, 출력될 페이지상의 번호 갯수 를 WD_getNextPage로 넘겨 처리 받아서 $page_view로 결과를 담습니다.

해당 함수에서 결과로 나오는 값은

view plaincopy to clipboardprint? $GLOBALS['wd_total_page'] = $total_page; $GLOBALS['wd_first_page'] = $first_page; $GLOBALS['wd_page_count'] = $page_count; $GLOBALS['wd_last_page'] = $last_page; $page->first_page = $first_page; $page->last_page = $last_page; $GLOBALS['wd_total_page'] = $total_page; $GLOBALS['wd_first_page'] = $first_page; $GLOBALS['wd_page_count'] = $page_count; $GLOBALS['wd_last_page'] = $last_page; $page->first_page = $first_page; $page->last_page = $last_page;
이것들이며 $GLOBALS은 누적, 다른곳에서의 호출을 위해 사용하고 $page는 최초 페이지 번호(당연히 1이겠죠), 마지막 페이지 번호를 담습니다.

view plaincopy to clipboardprint?{@WD_getNextClear()} {@WD_getNextClear()}
상하로 중복 출력을 위해서 항상 시작전 결과값 중에 $GLOBALS['wd_i'] 횟수가 남아있다면 이를 0으로 초기화 합니다.

view plaincopy to clipboardprint?<!--@while($page_no = WD_getNextPage2())--> <!--@if($widget_info->page == $page_no)--> <span class="current">{$page_no}</span> <!--@else--> <span class="pageNavigations"><a href="{getUrl('page',$page_no,'document_srl','','division',$division,'last_division',$last_division)}" class="pageNavigation2">{$page_no}</a></span> <!--@end--> <!--@end--> <!--@while($page_no = WD_getNextPage2())--> <!--@if($widget_info->page == $page_no)--> <span class="current">{$page_no}</span> <!--@else--> <span class="pageNavigations"><a href="{getUrl('page',$page_no,'document_srl','','division',$division,'last_division',$last_division)}" class="pageNavigation2">{$page_no}</a></span> <!--@end--> <!--@end-->
이제 while 문을 써서 $page_no가 나올때까지 반복합니다.

view plaincopy to clipboardprint?function WD_getNextPage2() { $page = $GLOBALS['wd_first_page']+$GLOBALS['wd_i']++; if($GLOBALS['wd_i'] > $GLOBALS['wd_page_count'] || $page > $GLOBALS['wd_last_page']) $page = 0; return $page; } function WD_getNextPage2() { $page = $GLOBALS['wd_first_page']+$GLOBALS['wd_i']++; if($GLOBALS['wd_i'] > $GLOBALS['wd_page_count'] || $page > $GLOBALS['wd_last_page']) $page = 0; return $page; }
한번 실행할때 마다 $GLOBALS['wd_i'] 증가와 함께 WD_getNextPage을 선언했을때의 페이지 관련 정보를 더해서 그 마지막 페이지 이상인지 이하인지를 계산해서 결과를 보냅니다.
여기서 전체페이지번호 수와 증가 페이지번호수를 비교, 마지막 페이지번호를 비교해서 while 계속을 진행할지 멈출지를 계산합니다.

d
df



by Anna 안나 2008. 11. 6. 00:42
예전에 zbXE 퍼머링크 달기라고 팁을 하나 올렸었는데요.

그걸 중심내용을 건드리지 않고 애드온으로 제작해 보았습니다.

위 제목이 무슨 말이냐 하면

http://www.animeclub.net/zbXE/57279 의 주소를

http://www.animeclub.net/zbXE/entry/문자-퍼머링크-주소로-사용하기 의 주소로 사용 할 수 있도록 해주는 겁니다.
(여기서 출력하면 주소창에는 urldecode() 처리가 되질 않아서 깨지네요... 복사해서 붙여넣기 후 열어보세요)

이런 방식은 '텍스트큐브' 에서 사용 하는 방식으로 zbXE에서도 사용할 수 있도록 구현해 봤습니다.





특수문자 제거 위 설정 화면 처럼 기본 특수문자 설정 이외의 문자들을 잘라낼수 있도록 특수문자를 추가할 수 있도록 하였습니다.
구분은 <> 으로 해주시면 됩니다.
(특수문자 구분 기호를 처음에 |@|로 하였는데 a|@|b 이렇게 적어놓으면 Array로 변해버리네요.)

Entry 구분기호 기본적으로 entry/ 라는 이름이 무난하다고 봤습니다.
@나 : 등 다른 특수문자등도 사용 가능합니다.
그리고 이 기능을 설정 후에는 .htaccess 의 제일 하단에 아래의 내용을 추가해주세요.
# Entry link
RewriteRule ^구분기호(.*)$ ./index.php?entry=$1 [L]
RewriteRule ^([a-zA-Z0-9_]+)/구분기호(.*)$ ./index.php?mid=$1&entry=$2 [L]

주소 접근식은 'http://도메인/모듈/구분기호Entry이름' 입니다.
또한, rewrite mod가 사용 불가능한 계정에서는 'http://도메인/?구분기호Entry이름' 이런식으로 접근 하실 수 있습니다.


위 부분이 설정이 되셨다면 게시판 등에서 위 주소로 바뀔 수 있도록 한가지 더 소스를 수정해주셔야 합니다.

예) 게시판 리스트 출력 소스
제로XE/modules/board/skins/xe_board/style_list.html
기존 : getUrl 로 검색해서 찾아봐주세요 ^^
{getUrl('document_srl',$document->document_srl, 'listStyle', $listStyle, 'cpage','')}
변경 : 애드온에 함수가 있으며 위 getUrl 함수를 적절히 변형시켜줍니다.
{procEntryTitle($module_info->mid, $document->get('extra_vars20'), $document->document_srl, $listStyle, $page)}

위 방식으로 공지사항 주소 및 게시물 링크 주소를 바꿔주시면 입력 주소형태 및 rewrite mod 여부에 따라 출력 되도록 하였습니다.


Entry 주소는 일단 xe_modules 테이블 에서 extra_vars20으로 임의로 설정하였습니다.
게시판 설정에서 20번째를 활성화하시면 제목이 아닌 원하시는 이름으로 퍼머링크 주소를 만드실 수 있습니다.
만약 활성화가 되지 않았다면 글 작성 시 게시물의 제목이 퍼머링크로 변형되어 입력 됩니다.

주의1) procEntryTitle() 함수를 쓴상태에서 애드온이 '미사용'일 경우 화면이 출력되지 않습니다.
주의2) 타 애드온 등과의 호환성은 아직 제대로 확인이 되질 않았습니다. 버그등이 있다면 알려주시면 수정하도록 하겠습니다.
by Anna 안나 2008. 11. 6. 00:31


밑에 실시간 애드온에서 기능을 조금 손 봤습니다.

- 기능 추가 -
1. 쪽지 도착시 음성 발생 기능 추가
( 님의 팁을 참조했습니다. ^^ 팁 잘쓸게요)
2. confirm 여부
( 쪽지 도착할때 바로 팝업을 뜨게 할지 confirm에서 확인을 거쳐 뜨게할지를 정할 수 있게 했습니다. )

ps : 음성파일(memo_on_swf)은 제로보드4 에서 사용한 음성을 첨부했습니다.

아래는 설치법 입니다.

-------------------
현재 쪽지기능을 창을 새로고침하거나 페이지를 이동하지 않더라도 체크해서 표시해주는 애드온 입니다.

첨부파일을 애드온(addons) 폴더에 복사하여 주시고 XML.request.php은 외부페이지로 연결 시켜줘야 합니다.


설치 방법
1. real_message.zip 파일을 압축울 풀면 real_message 폴더와 XML.request.php 파일이 나온다.
- [폴더] real_message
- [파일] XML.request.php

2. [폴더] real_message는 addons 폴더 안에 복사한다.

3. [파일] XML.request.php은 외부페이지 연동을 시키기 위한 파일이므로 임의의 곳에 복사한다.
(외부페이지로 사용할 임의의 폴더에 복사해두세요)

4. 관리자페이지에서 외부페이지를 하나 설정하여 레이아웃이나 기타 설정을 최소(아무것도 설정하지말고)로 설정하고
해당 XML.request.php파일의 경로를 입력하여 외부페이지를 만든다.

5. 관리자페이지에서 애드온 real_message 설정을 눌러 위 그림대로 XML request용 으로 만든 외부페이지 이름을 적는다.
(이름이 잘못되거나 형식이 잘못되면 오류납니다.)

6. 시간 설정은 제로XE를 이용하여 결과물 출력시 최소용량이 1.5KB가 나왔기 때문에 10초보단 30초 정도면 무난할 것 같습니다.

7. 사용하려는 모듈을 체크(이때 꼭 외부페이지로 만든 것도 체크해주어야 한다.)

8. 애드온 실행

- 추가 -
9. 커뮤니케이션 애드온에서 외부페이지로 만든 모듈을 체크풀어주시기 바랍니다.
( 고로 전체 체크 안되어 있는 상태에서 전체 체크 하시고 XML_request용 모듈만 체크 푸세요)

(※ 9번 항목은 버그 개선 전 까지 진행하지 마십시오.)


ps : 애드온 처리 1.0.5 지금 버그 있는거 아시죠?
한군대를 세팅하면 딴대가 다 초기화 되어 버립니다. -ㅅ-;;
또한 구 버젼에도 그랬지만 커뮤니케이션 애드온 에서 모듈 선택을 지정해버리면
'쪽지 보내기' 가 활성화 되지 않는 문제가 있습니다.

하여, 커뮤니케이션 애드온 패치를 알려드립니다.(오류가 개선될때까지 임시로 사용하세요)
./제로XE/addons/member_communication/member_communication.addon.php 파일을 엽니다.

그리고 제일 위에서 아래의 소스를 삽입해주세요.
-----------------
<?php
if(!defined("__ZBXE__")) exit();

// 실시간 애드온용 외부페이지 모듈이라면 패스
if(Context::get('mid') == 'XML_request') return;

밑줄 친 부분은 외부페이지로 설정하였던 모듈명을 적어주시기 바랍니다.

ps : 역시나 어김없이 실수가 있었군요 ^^;
( 3명 받으셨는데 다시 받아주세요. )
by Anna 안나 2008. 11. 6. 00:31
기본 구성 설명에 이어서 이번에는 간단히 위젯 소스를 적용시키는 과정만을 알려드리겠습니다.

최근 이미지 위젯에 페이지 기능을 위한 추가, 수정 파일

./widgets/newest_image/conf/info.xml <- 입력을 받기 위한 입력창
: 관리자페이지에서 코드 실행하기전에 이곳으로부터 정보를 입력 받습니다.
./widgets/newest_image/newest_images.class.php <- 입력 받은 정보를 처리
: 입력 받은 정보를 적절히 정리해서 DB로 부터 결과값들을 받고 스킨 처리를 하는 파일
./widgets/newest_image/queries/getOneFileInDocument.xml<- DB Query용 XML 파일
: $page 번호 값에 따라서 결과를 출럭하기 위해 <navigation>에 내용을 추가 해야 합니다.
: 또한 기존 files 모듈에 있던 내용을 위젯에 생성이 필요합니다.
./widgets/newest_image/queries/getOneFileInDocumentCount.xml <- DB Query용 XML 파일
: 결과값용 Query와 다르게 페이지 기능을 만들기 위해 하나의 Query를 더 해야합니다.
./widgets/newest_image/skin/default/list.html <- DB로 부터의 결과를 이용하여 표현하는 스킨 파일

(※ 이미 설명드린 부분(하단참조) 있기 때문에 아래부터는 존칭은 생략 하겠습니다.)

- info.xml -
........ XML 선언 문들......
<options>
<name xml:lang="ko">표시하지 않음</name>
<name xml:lang="jp">非表示</name>
<name xml:lang="zh-CN">不?示</name>
<name xml:lang="en">Hide</name>
<name xml:lang="es">Ocultar</name>
<name xml:lang="ru">Скрывать</name>
<value>N</value>
</options>
</var>
<var id="page_count">
<name xml:lang="ko">페이지 목록수</name>
<type>text</type>
<description xml:lang="ko">출력될 페이지의 수를 정하실 수 있습니다. (기본 5개)</description>
</var>
<var id="page_type">
<name xml:lang="ko">페이지 출력 여부</name>
<type>select</type>
<description xml:lang="ko">페이지를 출력할지 선택하세요.</description>
<options>
<name xml:lang="ko">N</name>
<value></value>
</options>
<options>
<name xml:lang="ko">Y</name>
<value>Y</value>
</options>
</var>
</extra_vars>
</widget>


한 페이지 당 출력할 페이지 번호 갯수와, 페이지 출력 여부 설정 값을 입력 받기 위해
page_count, page_type 항목을 선언


- newest_images.class.php -
/* 페이지 네비게이션 기능 추가 */
// 페이지 목록 수 (1,2,3,4....)
$page_count = $args->page_count;
if(!$page_count) $page_count = 5;
$obj->page_count = $page_count;

// 페이지 출력 여부
$page_type = $args->page_type;

// 페이지 번호 구하기
if($page_type=='Y') $obj->page = (Context::get('page'))? Context::get('page'): 1;
// 기존 변수 추가로 저장
$list_count = $obj->list_count;

/* 페이지 네비게이션 기능 추가 끝 */

// 정해진 모듈에서 문서별 파일 목록을 구함
$files_output = executeQueryArray("widgets.newest_images.getOneFileInDocument", $obj);
$output_count = executeQueryArray('widgets.newest_images.getOneFileInDocumentCount', $obj);

...중략...

$z=0;
foreach($files_output->data as $key => $val) {
$files_output->data[$z] = $files_output->data[$key];
unset($files_output->data[$key]);
$z++;
}

...중략...

/* 페이지 네비게이션 기능 추가 */
$widget_info->page_type = $page_type;
$widget_info->total_count = $output_count->data[0]->count; // 전체 개시물 수
$widget_info->page = (!Context::get('page'))? 1:Context::get('page'); // 현재 페이지
// 총 페이지 수
$total_count = $widget_info->total_count/$list_count;
if($widget_info->total_count%$list_count != 0) $total_count+=1;
$widget_info->total_page = floor($total_count); // 총 페이지 수
$widget_info->page_count = $page_count; // 총 페이지 수
/* 페이지 네비게이션 기능 추가 끝 */

...중략...

/**
* @brief 다음 페이지 요청
**/
function WD_getNextPage($total_count, $total_page, $cur_page, $page_count = 10) {

$first_page = $cur_page - (int)($page_count/2);
if($first_page<1) $first_page = 1;
$last_page = $total_page;
if($last_page>$total_page) $last_page = $total_page;
if($total_page < $page_count) $page_count = $total_page;

$GLOBALS['wd_total_page'] = $total_page;
$GLOBALS['wd_first_page'] = $first_page;
$GLOBALS['wd_page_count'] = $page_count;
$GLOBALS['wd_last_page'] = $last_page;

$page->first_page = $first_page;
$page->last_page = $last_page;

return $page;
}

function WD_getNextPage2() {
$page = $GLOBALS['wd_first_page']+$GLOBALS['wd_i']++;
if($GLOBALS['wd_i'] > $GLOBALS['wd_page_count'] || $page > $GLOBALS['wd_last_page']) $page = 0;
return $page;
}

function WD_getNextClear() {
$GLOBALS['wd_i'] = 0;
}


newest_images.class.php 파일안에 구석구석 위의 변수가 들어가면 페이지 기능이 완성 된다.


1. 첫번째 페이지 기능을 위한 정보 입력 및 처리
/* 페이지 네비게이션 기능 추가 */
// 페이지 목록 수 (1,2,3,4....)
$page_count = $args->page_count;
if(!$page_count) $page_count = 5;
$obj->page_count = $page_count;

// 페이지 출력 여부
$page_type = $args->page_type;

// 페이지 번호 구하기
if($page_type=='Y') $obj->page = (Context::get('page'))? Context::get('page'): 1;
// 기존 변수 추가로 저장
$list_count = $obj->list_count;

/* 페이지 네비게이션 기능 추가 끝 */

XML로 만들었던 page_count와 page_type을 DB로 보내기 위해 위와 같이 선언 한다.
(※ 다른 위젯과 다르게 $list_count 변수가 없어서 마지막에 $list_count = $obj->list_count;을 추가 선언해준다.)

2. DB로 보낼때 페이지 기능에서 필요로 하는 값중에는 전체 게시물수가 필요함.
전체 게시물 수를 구할 수 있도록 아래와 같이 선언
// 정해진 모듈에서 문서별 파일 목록을 구함
$files_output = executeQueryArray("widgets.newest_images.getOneFileInDocument", $obj);
$output_count = executeQueryArray('widgets.newest_images.getOneFileInDocumentCount', $obj);

기 존 $files_output = executeQueryArray("file.getOneFileInDocument", $obj); 를 수정하게 되면 중심 모듈을 건드리게 되기 때문에 아래와 같이 위젯 폴더안에 queries라는 폴더를 하나더 만들어서 새로이 생성해준다.
전체 게시물 수를 구하도록 끝에 Count를 더 달아서 파일을 생성해준다.


3. 결과값의 순서를 수정
$z=0;
foreach($files_output->data as $key => $val) {
$files_output->data[$z] = $files_output->data[$key];
unset($files_output->data[$key]);
$z++;
}

다른 위젯과 다르게 임의의 page( limit 0, 5 ) 가 선언되면
$files_output->data[0] ..[1]..[2]..... 가 아니라 $files_output->data[343]... [344]...[345].....
순으로 저장 되기에 이를 0번 부터 사용하도록 수를 수정 한다.


4. 페이지 계산에 필요한 정보를 list.html로 보내기 위해 아래와 같이 정리 한다.
/* 페이지 네비게이션 기능 추가 */
$widget_info->page_type = $page_type;
$widget_info->total_count = $output_count->data[0]->count; // 전체 개시물 수
$widget_info->page = (!Context::get('page'))? 1:Context::get('page'); // 현재 페이지
// 총 페이지 수
$total_count = $widget_info->total_count/$list_count;
if($widget_info->total_count%$list_count != 0) $total_count+=1;
$widget_info->total_page = floor($total_count); // 총 페이지 수
$widget_info->page_count = $page_count; // 총 페이지 수
/* 페이지 네비게이션 기능 추가 끝 */
Context::set('widget_info', $widget_info);
...중략...

5. list.html에서 호출에 오는 함수 정보.
/**
* @brief 다음 페이지 요청
**/
function WD_getNextPage($total_count, $total_page, $cur_page, $page_count = 10) {

$first_page = $cur_page - (int)($page_count/2);
if($first_page<1) $first_page = 1;
$last_page = $total_page;
if($last_page>$total_page) $last_page = $total_page;
if($total_page < $page_count) $page_count = $total_page;

$GLOBALS['wd_total_page'] = $total_page;
$GLOBALS['wd_first_page'] = $first_page;
$GLOBALS['wd_page_count'] = $page_count;
$GLOBALS['wd_last_page'] = $last_page;

$page->first_page = $first_page;
$page->last_page = $last_page;

return $page;
}

function WD_getNextPage2() {
$page = $GLOBALS['wd_first_page']+$GLOBALS['wd_i']++;
if($GLOBALS['wd_i'] > $GLOBALS['wd_page_count'] || $page > $GLOBALS['wd_last_page']) $page = 0;
return $page;
}

function WD_getNextClear() {
$GLOBALS['wd_i'] = 0;
}

위와 함수를 이용하여 페이지 계산, 초기화 등의 정보를 구한다.


- getOneFileInDocument.xml -
<query id="getOneFileInDocument" action="select">
<tables>
<table name="files" alias="files"/>
<table name="documents" alias="documents"/>
</tables>
<columns>
<column name="files.upload_target_srl" alias="document_srl"/>
</columns>
<conditions>
<condition operation="in" column="files.module_srl" var="module_srls" notnull="notnull" filter="numbers" />
<condition operation="equal" column="files.direct_download" var="direct_download" pipe="and" />
<condition operation="equal" column="files.isvalid" var="isvalid" pipe="and" />
<condition operation="equal" column="files.upload_target_srl" var="documents.document_srl" pipe="and" />
</conditions>
<groups>
<group column="files.upload_target_srl" />
</groups>
<navigation>
<index var="list_order" default="documents.list_order" order="asc" />
<list_count var="list_count" default="20" />
<page_count var="page_count" default="10" />
<page var="page" default="1" />
</navigation>
</query>

기존의 기본 XML에서 아래의 내용을 추가한다. (페이지 별로 내용 축출을 위해 필요)
<page_count var="page_count" default="10" />
<page var="page" default="1" />


- getOneFileInDocumentCount.xml -
<query id="getOneFileInDocumentCount" action="select">
<tables>
<table name="files" alias="files"/>
<table name="documents" alias="documents"/>
</tables>
<columns>
<column name="count(files.upload_target_srl)" alias="count"/>
</columns>
<conditions>
<condition operation="in" column="files.module_srl" var="module_srls" notnull="notnull" filter="numbers" />
<condition operation="equal" column="files.direct_download" var="direct_download" pipe="and" />
<condition operation="equal" column="files.isvalid" var="isvalid" pipe="and" />
<condition operation="equal" column="files.upload_target_srl" var="documents.document_srl" pipe="and" />
</conditions>
<groups>
<group column="files.upload_target_srl" />
</groups>
<navigation>
<index var="list_order" default="documents.list_order" order="asc" />
</navigation>
</query>

내용은 그대로 getOneFileInDocument.xml에서 가져오돼 바꿔줘야 할 부분
<query id="getOneFileInDocumentCount" action="select">id명을 파일명과 일치시킨다.
<column name="count(files.upload_target_srl)" alias="count"/><column name="count(files.upload_target_srl)" alias="count"/>count()로 감싸고 alias="count" 라는 이름으로 명시.
<list_count var="list_count" default="20" />해당 내용 삭제하여 전체 게시물로써의 게시물수를 구한다.


- list.html -<!--@if($widget_info->page_type=='Y')--> <!-- 페이지 네비게이션 --> <div class="pageNavigation"> <a href="{getUrl('page','','document_srl','','division',$division,'last_division',$last_division)}" class="goToFirst"> <img src="./images/common/bottomGotoFirst.gif" alt="{$lang->first_page}" width="7" height="5" /></a> <!-- 페이지 정보 구하기 위해 선언 --> {@$page_view = WD_getNextPage($widget_info->total_count,$widget_info->total_page,$widget_info->page,$widget_info->page_count)} <!-- 중복 페이지 정보 출력을 위해 사전 초기화 --> {@WD_getNextClear()} <!--@while($page_no = WD_getNextPage2())--> <!--@if($widget_info->page == $page_no)--> <span class="current">{$page_no}</span> <!--@else--> <span class="pageNavigations"><a href="{getUrl('page',$page_no,'document_srl','','division',$division,'last_division',$last_division)}" class="pageNavigation2">{$page_no}</a></span> <!--@end--> <!--@end--> <a href="{getUrl('page',$page_view->last_page,'document_srl','','division',$division,'last_division',$last_division)}" class="goToLast"> <img src="./images/common/bottomGotoLast.gif" alt="{$lang->last_page}" width="7" height="5" /></a> </div> <!--@end-->

<!--@if($widget_info->page_type=='Y')-->
<!-- 페이지 네비게이션 -->
<div class="pageNavigation">
<a href="{getUrl('page','','document_srl','','division',$division,'last_division',$last_division)}" class="goToFirst">
<img src="./images/common/bottomGotoFirst.gif" alt="{$lang->first_page}" width="7" height="5" /></a>
<!-- 페이지 정보 구하기 위해 선언 -->
{@$page_view = WD_getNextPage($widget_info->total_count,$widget_info->total_page,$widget_info->page,$widget_info->page_count)}
<!-- 중복 페이지 정보 출력을 위해 사전 초기화 -->
{@WD_getNextClear()}
<!--@while($page_no = WD_getNextPage2())-->
<!--@if($widget_info->page == $page_no)-->
<span class="current">{$page_no}</span>
<!--@else-->
<span class="pageNavigations"><a href="{getUrl('page',$page_no,'document_srl','','division',$division,'last_division',$last_division)}" class="pageNavigation2">{$page_no}</a></span>
<!--@end-->
<!--@end-->
<a href="{getUrl('page',$page_view->last_page,'document_srl','','division',$division,'last_division',$last_division)}" class="goToLast">
<img src="./images/common/bottomGotoLast.gif" alt="{$lang->last_page}" width="7" height="5" /></a>
</div>
<!--@end-->

중요한 선언만 설명
{@$page_view =
WD_getNextPage($widget_info->total_count,$widget_info->total_page,$widget_info->page,$widget_info->page_count)}
$widget_info로 넘겨받은 페이지 계산을 위한 전체 게시물 수, 전체 페이지 수, 현재 페이지 번호, 한페이지에 출력될 페이지 번호의 수를 WD_getNextPage로 호출하여 $page_view에 결과를 저장한다.

{@WD_getNextClear()}

상 하로 중복 선언이 될 경우 기존에 이용되었던 $GLOBALS 변수를 초기화 시킨다.
<!--@while($page_no = WD_getNextPage2())-->
...내용...
<!--@end-->

WD_getNextPage2() 를 호출시마다 반복시켜서 내용이 없을때까지 수행한다.




위 설명은 왠만한 위젯에서 공통적으로 적용가능합니다. (리스트형)
1~5번의 위치만 제대로 잡아주시고 DB용 xml만 제대로 선언해주신다면 페이지 네비게이션 이용에
문제가 없을 걸로 봅니다.

전체 소스결과를 출력하긴 좀 그래서 newest_images 위젯을 배포하겠습니다.
위 소스를 기반으로 확인해보시고 다른곳에 적용해보시고 하세요.
보다 자세한 원리의 강좌는 제 홈페이지에 설명되어있습니다.
http://www.animeclub.net/zbXE
by Anna 안나 2008. 11. 6. 00:08
※제가 한번 아래 소스로 시도해보았는데, 오류가 나더라구요..ㅇ_ㅇ



xe_board_for_extra_vars 확장변수 전용 게시판 스킨[3차수정] 보완용 팁입니다.
1.modules/editor/editor.admin.controller.php line161 부분에 소스를 삽입한다.
$editor_config->enable_autosave = Context::get('enable_autosave');
$editor_config->enable_only_upload_editor = Context::get('enable_only_upload_editor'); if($editor_config->enable_height_resizable != 'Y') $editor_config->enable_height_resizable = 'N';
if($editor_config->enable_comment_height_resizable != 'Y') $editor_config->enable_comment_height_resizable = 'N';
if($editor_config->enable_autosave != 'Y') $editor_config->enable_autosave = 'N';
if($editor_config->enable_only_upload_editor != 'Y') $editor_config->enable_only_upload_editor = 'N'; 2. modules/editor/editor.model.php line45 부분에 소스를 삽입한다.
if(!$editor_config->editor_height) $editor_config->editor_height = 500;
if(!$editor_config->comment_editor_height) $editor_config->comment_editor_height = 120;
if($editor_config->enable_height_resizable!='N') $editor_config->enable_height_resizable= "Y";
if($editor_config->enable_comment_height_resizable!='Y') $editor_config->enable_comment_height_resizable= "N";
if($editor_config->enable_autosave!='N') $editor_config->enable_autosave = "Y";
if($editor_config->enable_only_upload_editor != 'Y') $editor_config->enable_only_upload_editor = 'N'; return $editor_config;
} /**
* @brief 에디터 template을 return
* upload_target_srl은 글의 수정시 호출하면 됨.
* 이 upload_target_srl은 첨부파일의 유무를 체크하기 위한 루틴을 구현하는데 사용됨.
**/
function getEditor($upload_target_srl = 0, $option = null) {
/**
* 기본적인 에디터의 옵션을 정리
**/ // 에디터 업로드만 사용 옵션 설정
if(!$option->enable_only_upload_editor) $enable_only_upload_editor = false;
else $enable_only_upload_editor = true; line 166
/**
* 에디터 컴포넌트 체크
**/
if($enable_component) {
if(!Context::get('component_list')) {
$component_list = $this->getComponentList();
Context::set('component_list', $component_list);
}
}
Context::set('enable_component', $enable_component);
Context::set('enable_default_component', $enable_default_component); /**
* 에디터 업로드 기능만 가능한지 변수 설정
**/
Context::set('enable_only_upload_editor', $enable_only_upload_editor); line 220
function getModuleEditor($type = 'document', $module_srl, $upload_target_srl, $primary_key_name, $content_key_name) {
// 지정된 모듈의 에디터 설정을 구해옴
$editor_config = $this->getEditorConfig($module_srl); // type에 따른 설정 정리
if($type == 'document') {
$config->editor_skin = $editor_config->editor_skin;
$config->upload_file_grant = $editor_config->upload_file_grant;
$config->enable_default_component_grant = $editor_config->enable_default_component_grant;
$config->enable_component_grant = $editor_config->enable_component_grant;
$config->enable_html_grant = $editor_config->enable_html_grant;
$config->editor_height = $editor_config->editor_height;
$config->enable_height_resizable = $editor_config->enable_height_resizable;
$config->enable_autosave = $editor_config->enable_autosave;
$config->enable_only_upload_editor = 'N';
} elseif($type == 'extra_vars'){
$config->enable_only_upload_editor = 'Y';
} elseif($type == 'comment') {
$config->editor_skin = $editor_config->comment_editor_skin;
$config->upload_file_grant = $editor_config->comment_upload_file_grant;
$config->enable_default_component_grant = $editor_config->enable_comment_default_component_grant;
$config->enable_component_grant = $editor_config->enable_comment_component_grant;
$config->enable_html_grant = $editor_config->enable_comment_html_grant;
$config->editor_height = $editor_config->comment_editor_height;
$config->enable_height_resizable = $editor_config->enable_comment_height_resizable;
$config->enable_autosave = 'N';
$config->enable_only_upload_editor = 'N';
} line 293
// HTML 편집 권한
$enable_html = false;
if(count($config->enable_html_grant)) {
foreach($group_list as $group_srl => $group_info) {
if(in_array($group_srl, $config->enable_html_grant)) {
$enable_html = true;
break;
}
}
} else $enable_html = true; if($enable_html) $option->disable_html = false;
else $option->disable_html = true; // 에디터 업로드만 설정
$option->enable_only_upload_editor = $config->enable_only_upload_editor=='Y'?true:false; 3. moudles/editor/tpl/js/uploader.js line 247 부분 소스를 삽입한다.
// 이미지 파일의 경우
} else if(/\.(jpg|jpeg|png|gif)$/i.test(uploaded_filename)) {
html = "<img src=\""+uploaded_filename+"\" border=\"0\" width=\"110\" height=\"110\" onclick=\"copyContent(this.href);return false\" />"; line 끝부분에 아래의 소스를 삽입한다.
function copyContent(trb)
{
var IE=(document.all)?true:false;
if (IE) {
if(confirm("이 글의 주소를 클립보드에 복사하시겠습니까?"))
window.clipboardData.setData("Text", trb);
}
}; <<보충설명>>
1> 이 소스는 글쓰기 폼에서 이미지 파일이 업로드 되면 미리보기가 지원되는데, 미리보기 이미지를 클릭하면 업로드된 파일의 위치를 클립보드에 복사 합니다. 2> 위의 방법으로 복사된 이미지 파일의 주소를 확장변수의 이미지 주소창에 사용자가 붙여넣기하여 사용하기 위함입니다. 4. module/editor/skins/default/editor.html line 9 부분에 소스를 삽입한다.
<!-- 자동저장용 폼 -->
<!--@if($enable_autosave && !$enable_only_upload_editor)-->
<input type="hidden" name="_saved_doc_title" value="{htmlspecialchars($saved_doc->title)}" />
<input type="hidden" name="_saved_doc_content" value="{htmlspecialchars($saved_doc->content)}" />
<input type="hidden" name="_saved_doc_message" value="{$lang->msg_load_saved_doc}" />
<!--@end--> <!-- 에디터 -->
<div class="xeEditor">
<!--@if(!$enable_only_upload_editor)--> line 142 부분에 소스를 삽입한다.
<!-- 에디터 크기 조절 bar -->
<!--@if($enable_resizable)-->
<div class="textAreaDragIndicator"><div class="textAreaDragIndicatorBar" id="editor_drag_bar_{$editor_sequence}"></div></div>
<!--@end-->
<!--@else-->
<!-- 에디터 출력 -->
<div><iframe id="editor_iframe_{$editor_sequence}" frameborder="0" height="0" style="background-color:transparent;" allowTransparency="true"></iframe></div>
<textarea id="editor_textarea_{$editor_sequence}" class="editor_iframe_textarea" style="display:none; height:0" rows="10" cols="10"></textarea>
<!--@end--> line 169 부분에 소스를 삽입한다.
<!-- 파일 업로드 영역 -->
<div class="fileListArea">
<select id="uploaded_file_list_{$editor_sequence}" multiple="multiple" size="5" class="fileList" onclick="editor_preview(this, '{$editor_sequence}');"></select>
</div>
<div class="fileUploadControl">
<a href="#" onclick="editor_upload_file('{$editor_sequence}');return false;" class="button"><span>{$lang->edit->upload_file}</span></a>
<a href="#" onclick="editor_remove_file('{$editor_sequence}');return false;" class="button"><span>{$lang->edit->delete_selected}</span></a>
<!--@if(!$enable_only_upload_editor)-->
<a href="#" onclick="editor_insert_file('{$editor_sequence}');return false;" class="button"><span>{$lang->edit->link_file}</span></a><!--@end-->
</div> 5. modules/document/document.item.php line 589 부분에 소스를 삽입한다.
/**
* @brief 에디터 html을 구해서 return
**/
function getEditor() {
$module_srl = $this->get('module_srl');
if(!$module_srl) $module_srl = Context::get('module_srl'); $oEditorModel = &getModel('editor');
return $oEditorModel->getModuleEditor('document', $module_srl, $this->document_srl, 'document_srl', 'content');
} function getExtra_vars_Editor() {
$module_srl = $this->get('module_srl');
if(!$module_srl) $module_srl = Context::get('module_srl'); $oEditorModel = &getModel('editor');
return $oEditorModel->getModuleEditor('extra_vars', $module_srl, $this->document_srl, 'document_srl', 'content');
} 6. modules/board/skins/xe_board_for_extra_vars/write_form.html line 103 부분에 소스를 삽입한다.
<!--@if($module_info->enable_editor =='N' && $val->type=='image' || $module_info->enable_editor =='N' && $val->type=='media')-->
<div class="editor">{$oDocument->getExtra_vars_Editor()}</div>
<!--@end-->
<!--@if($module_info->enable_editor !='N')-->
<div class="editor">{$oDocument->getEditor()}</div>
<!--@end-->
by Anna 안나 2008. 6. 21. 23:26
에디터에서 선택 영역을 컴포넌트로 불러올 때, 굵은 표시 참고 function getText() {
// 부모 위지윅 에디터에서 선택된 영역이 있으면 처리
var fo_obj = xGetElementById("text_form");
var text = opener.editorGetSelectedHtml(opener.editorPrevSrl);
if(text==undefined) text = "";
text = text.replace(/<([^>]*)>/ig,'').replace(/&lt;/ig,'<').replace(/&gt;/ig,'>').replace(/&amp;/ig,'&');
fo_obj.contents.value = text;
return;
}
xAddEventListener(window, "load", getText);

컴포넌트의 HTML 내용을 에디터에 적용할 때 /* 부모창의 위지윅 에디터의 선택된 영역의 글자색을 변경 */
function completeCreateLink() {

var sHTML = preview.innerHTML;

opener.editorFocus(opener.editorPrevSrl);

var iframe_obj = opener.editorGetIFrame(opener.editorPrevSrl)

opener.editorReplaceHTML(iframe_obj, sHTML);
opener.editorFocus(opener.editorPrevSrl);

self.close();
}
by Anna 안나 2008. 6. 21. 16:20
폴더명 부분은 위젯 폴더 이름입니다.

폴더명.class.php

conf/info.xml 에서 선언한 extra_vars를 args로 받은 후 처리 합니다.
결과는 Context::set 으로 돌려주어 skin/스킨이름/폴더명.html 파일에서 사용됩니다.

예제
위젯 편집 페이지에서 입력받은 제목 값($args->title)을 obj변수($obj->title)로 받은 후,
Context::set에서 obj로 값을 돌려줍니다.
<?php
class 폴더명 extends WidgetHandler {

function proc($args) {

// 템플릿 파일에서 사용할 변수들을 세팅
$obj->title = $args->title;
$obj->list = $args->list;

// 템플릿의 스킨 경로를 지정 (skin, colorset에 따른 값을 설정)
$tpl_path = sprintf('%sskins/%s', $this->widget_path, $args->skin);
Context::set('colorset', $args->colorset);
$tpl_file = '폴더명';

Context::set('obj', $obj);

// 템플릿 컴파일
$oTemplate = &TemplateHandler::getInstance();
return $oTemplate->compile($tpl_path, $tpl_file);
}
}
?>
conf/info.xml
var에서 지정된 변수 값은 폴더명.class.php 파일에서 args 변수로 넘어갑니다.
type이 text이면 INPUT 폼을, select이면 SELECT폼을 출력합니다.
<?xml version="1.0" encoding="utf-8"?>
<widget version="0.1">
<title xml:lang="ko">제목</title>
<author email_address="이메일" link="홈페이지" date="만든 날짜">
<name xml:lang="ko">제작자</name>
<description xml:lang="ko">설명</description>
</author>
<extra_vars>
<var id="title">
<name xml:lang="ko">좌측 설명</name>
<type>text</type>
<description xml:lang="ko">폼 하단 설명</description>
</var>
<var id="list">
<name xml:lang="ko">좌측 설명</name>
<type>select</type>
<description xml:lang="ko">하단 설명</description>
<options>
<name xml:lang="ko">목록</name>
<value>값</value>
</options>
</var>
</extra_vars>
</widget>
skin/스킨이름/폴더명.html
Context::set 로 지정한 변수 값을 받아서 출력합니다.

예제
<div>제목: {$obj->title}</div>
<div>목록: {$obj->list}</div>
by Anna 안나 2008. 6. 21. 16:20
게시판 목록에서 셀렉트 폼이 아닌 텍스트나 대체 이미지로 분류를 표시하고 싶다면

list.html 파일의 적당한 곳에 아래 소스를 알맞게 편집하여 삽입해보세요.

<!--@if($module_info->use_category == "Y")-->
<!-- 카테고리 사용시 카테고리 선택 표시 -->
<a href="{getUrl('','mid',$mid,'page',$page,'category','','document_srl','')}">분류</a>
<!--@foreach($category_list as $val)-->
<a href="{getUrl('','mid',$mid,'page',$page,'category',$val->category_srl,'document_srl','')}"><!--@if($category==$val->category_srl)--><b><!--@end-->{$val->title} <!--@if($val->document_count)-->({$val->document_count})<!--@end--><!--@if($category==$val->category_srl)--></b><!--@end--></a>
<!--@end-->
<!--@end-->


분류명을 이미지로 나열할 때

<!--@if($module_info->use_category == "Y")-->
<!-- 카테고리 사용시 카테고리 선택 표시 -->
<a href="{getUrl('','mid',$mid,'page',$page,'category','','document_srl','')}"><IMG 전체 분류 이미지/></a>
<!--@foreach($category_list as $val)-->
{@$on = ($category==$val->category_srl)?"_on":""}
<a href="{getUrl('','mid',$mid,'page',$page,'category',$val->category_srl,'document_srl','')}"><IMG src="{$val->category_srl}{$on}.jpg">!--@if($val->document_count)-->({$val->document_count})<!--@end--></a>
<!--@end-->
<!--@end-->

이미지 경로는 알맞게 편집하세요.

파일명 예
123 카테고리일 경우
123.jpg 분류 이미지
123_on.jpg 선택된 분류 이미지
by Anna 안나 2008. 6. 21. 15:23
학습 목표
1. 회원 정보에서 글, 댓글 작성 갯수를 보여주기


2. 회원 목록 관리자 페이지에서 글, 댓글 작성 갯수를 보여주기



작동 원리
document, comment 테이블을 user_id로 쿼리를 한다.

이때 쿼리 XML 파일을 만들어 줘야 함



작업준비
※ XML 파일은 어디에 넣어도 상관이 없습니다만 다른 용도로 사용을 하기 위해 각 모듈의 쿼리 폴더에 복사합니다.

아래 파일을 modules\comment\queries 폴더에 복사합니다.
getMemberCommentCount.xml

아래 파일을 modules\document\queries 폴더에 복사합니다.
getMemberDocumentCount.xml
getMemberUploadedCount.xml

1. 회원 정보 페이지 작업하기
modules\member\skins\스킨 폴더의 member_info.html 파일을 편집합니다.
70번대 줄에 아래 소스를 추가합니다.

{@
$obj->member_srl = $member_info->member_srl;
$output_document_count = executeQuery("document.getMemberDocumentCount",$obj);
$output_comment_count = executeQuery("comment.getMemberCommentCount",$obj);
$output_attach_count = executeQuery("document.getMemberUploadedCount",$obj);
}
<tr>
<th scope="row">{$lang->count_document}</th>
<td>{$output_document_count->data->count}</td>
</tr>
<tr>
<th scope="row">{$lang->count_comment}</th>
<td>{$output_comment_count->data->count}</td>
</tr>
<tr>
<th scope="row">{$lang->count_attach}</th>
<td>{$output_attach_count->data->count}</td>
</tr>
변수 대신 직접 한글을 사용해도 되지만 언어별로 나타내려면 lang 파일을 편집합니다.


modules\member\lang 폴더의 ko.lang.php 파일을 편집합니다.
아래 소스를 적당한 곳에 추가합니다.

$lang->count_document = '글 수';
$lang->count_comment = '댓글 수';
$lang->count_attach = '첨부 수';


2. 회원 목록 관리 페이지 작업하기
member 모듈의 member.admin.view.php 파일을 편집합니다.
dispMemberAdminList 함수의 중간에 아래 소스 중 굵은 부분을 삽입합니다.
function dispMemberAdminList() {
// member model 객체 생성후 목록을 구해옴
$oMemberModel = &getAdminModel('member');
$output = $oMemberModel->getMemberList();

foreach($output->data as $key => $value) {
$output_document_count = executeQuery("document.getMemberDocumentCount", $value);
$output_comment_count = executeQuery("comment.getMemberCommentCount", $value);
$output->data[$key]->document_count = $output_document_count->data->count;
$output->data[$key]->comment_count = $output_comment_count->data->count;
}

// 템플릿에 쓰기 위해서 context::set
Context::set('total_count', $output->total_count);
Context::set('total_page', $output->total_page);
Context::set('page', $output->page);
Context::set('member_list', $output->data);
Context::set('page_navigation', $output->page_navigation);

// 템플릿 파일 지정
$this->setTemplateFile('member_list');
}

modules\member\tpl 폴더에서 member_list.html 파일을 편집합니다.

<thead></thead> 사이에 아래 소스를 삽입하고,
<th scope="col">Document</th>
<th scope="col">Comment</th>
<tbody></tbody> 사이에 아래 소스를 삽입합니다.
<td class="tahoma">{$val->document_count}</td>
<td class="tahoma">{$val->comment_count}</td>

※ 소스를 참고하여 포인트 모듈의 회원 목록에서도 적용할 수 있습니다.
by Anna 안나 2008. 6. 21. 15:19
포인트 모듈 관리자에서 회원 목록을 포인트 순으로 정렬

SELECT m.*, p.point FROM xe_member m left outer join xe_point p on m.member_srl = p.member_srl order by point desc
by Anna 안나 2008. 6. 21. 15:18
기본 값으로 회원 서명은 본문 아래에 출력이 됩니다.

학습목표
원하는 곳에 회원 서명을 출력하기



작업 하기

addons\member_extra_info 폴더의 member_extra_info.addon.php 파일을 편집합니다. 36번 줄
// 2. 출력문서~ 아래 줄을 주석 처리합니다.
//$output = ~


아래 소스를 보드모듈 스킨의 header.html 또는 view_document.html 파일 상단에 삽입하고
{@
$oMemberModel = &getModel('member');
$signature = $oMemberModel->getSignature($oDocument->get('member_srl'));
}


아래 소스를 출력하기 원하는 곳에 삽입합니다.
{$signature}

끝;;;

by Anna 안나 2008. 6. 21. 15:17
파일을 새로 첨부하였을 때, 쉽게 구별하여 내려 받을 수 있도록 시간과 아이콘을 표시해 줍니다.

조건문 설명
· 파일 등록 시각은 현재 시각 빼기 설정시간보다 커야 한다.
(설정 시간동안 아이콘 표시)
· 파일 등록 시각은 글 등록 시각보다 커야 한다.
(처음 글 작성시는 아이콘 표시 안함)
· 파일 등록 시각은 글 수정 시각보다 작아야 한다.
(파일만 등록 후 글을 수정 안했을 때 아이콘 표시 안함)


소스
<ul>
{@ $uploaded_list = $oDocument->getUploadedFiles() }
<!--@foreach($uploaded_list as $key => $file)-->
{@ $new_icon = ($file->regdate > date("YmdHis", time() - $module_info->duration_new*3600) && $file->regdate > $oDocument->get('regdate') && $file->regdate < $oDocument->get('last_update')) ? "<img src='".getUrl()."modules/document/tpl/icons/new.gif' alt='new.gif' title='new.gif' align='absmiddle'/>" : "";
}
<li><a href="{getUrl('')}{$file->download_url}">{$file->source_filename} ({FileHandler::filesize($file->file_size)})({number_format($file->download_count)}) [{zdate($file->regdate, "Y-m-d H:i:s")}] {$new_icon}</a></li>
<!--@end-->
</ul>

사용하기

modules/board/skins/스킨/view_document.html 파일에서 120번대 줄을 위 소스로 대체.
by Anna 안나 2008. 6. 21. 15:16
질문 답변 게시판에서 유용한 기능

댓글이 달리지 않은 글을 검색합니다.

modules\document\queries 폴더에 아래 첨부 파일을 복사합니다.
getDocumentListNoComment.xml

document.model.php 파일의 getDocumentList 함수에서 아래 굵은 소스를 추가합니다.
$query_id = 'document.getDocumentList';

if(Context::get('nocomment') == true) {
$args->s_comment_count = "'0'";
$query_id = 'document.getDocumentListNoComment';
}
게시판 스킨의 list.html 파일에서 하단의 검색 소스 아래에 아래 소스를 추가합니다.
<a href="{getUrl('','mid',$mid,'listStyle',$listStyle,'nocomment',true)}" class="button"><span>무플</span></a>
아래는 내 글을 검색하는 소스로 위 소스의 바로 옆에 추가하면 됩니다.
<!--@if($logged_info)--><a href="{getUrl('','mid',$mid,'listStyle',$listStyle,'search_target','user_id','search_keyword',$logged_info->user_id)}" class="button"><span>내글</span></a><!--@end-->
by Anna 안나 2008. 6. 21. 15:15
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=5,0,0,0" width="0" height="0"><param name=menu value=false><param name=wmode value=transparent><param name=movie value="./addons/member_extra_info/swf/memo_on.swf"><param name=quality value=low><param name="LOOP" value="false"><embed src="./addons/member_extra_info/swf/memo_on.swf" quality=low pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" type="application/x-shockwave-flash" width="0" height="0" loop="false" wmode=transparent menu="false"></embed></object>

위 소스를 member_extra_info.addon.php 49번줄에 추가하세요. <script> 앞에^^



첨부 파일은 다음 폴더에 추가하세요. addons/member_extra_info/swf/
by Anna 안나 2008. 6. 21. 15:12
default value 호출하기.. 라고 해야하나요?? 제목이 좀 이상하긴 하지만..

이 팁은 php문서를 수정하는 것이 아니라 /zbxe/modules/board/skins/ 경로안에 있는 모듈보드스킨의 글쓰기 창에서 간단히 수정할 수 있는 방법입니다. 아무래도 다른 문서를 만지는 것은 업데이트도 있고, 실력없는 저로서는 불안하기 때문에..
또, 제 홈페이지에서는 php문서를 수정하면 이상하게 에러가 출몰해서 아예 건들지 않습니다.
아무것도 건드리지 않고 드림위버로 저장만해서 올려도 에러가 뜨더군요.. 참 황당스러운.. -_-ㆀ 쓸데 없는 말은 집어치우고 본론으로 들어가도록 할께요.

write_form.html 문서에서 form 영역을 살펴보면 아래와 같은 부분이 있습니다.
<input type="hidden" name="content" value="{$oDocument->getContentText()}" />
바로 내용을 불러오는 인풋이죠.
type="hidden" 처리를 했기 때문에 글쓰기창에서는 에디터만 보인다는 것은 아실테죠?
이 것을 변경하여 에디터에 원하는 글을 넣는 방법입니다. 3가지 방법이 있으니 원하는 방법으로 테스트해보시면 됩니다.

1. 글쓰기창에 변수를 선언하여 문자호출하기 일단 아래의 코드창에 있는 내용을 살펴보세요. view plaincopy to clipboardprint? {@ $Content = "에디터에 미리 글을 넣어봅시다<br />태그를 이용할 수도 있군요!";} <input type="hidden" name="content" value="<!--@if($document_srl == $oDocument->document_srl)-->{$oDocument->getContentText()}<!--@else-->{$Content}<!--@end-->" /> {@ $Content = "에디터에 미리 글을 넣어봅시다<br />태그를 이용할 수도 있군요!";} <input type="hidden" name="content" value="<!--@if($document_srl == $oDocument->document_srl)-->{$oDocument->getContentText()}<!--@else-->{$Content}<!--@end-->" /> 왜 저렇게 했는지 아시는 분들은 이미 아실테죠?
첫번째 줄에서 $Content라는 변수를 선언하여 두번째줄의 내용에서 제목변수와 함께 호출을 했습니다. 내용이 들아가는 value에 아래와 같은 곳이 있는데요. view plaincopy to clipboardprint? <!--@if($document_srl == $oDocument->document_srl)-->{$oDocument->getContentText()}<!--@else-->{$Content}<!--@end--> <!--@if($document_srl == $oDocument->document_srl)-->{$oDocument->getContentText()}<!--@else-->{$Content}<!--@end--> 위에서도 말씀드렸듯이 {$Content} 이 부분은 선언한 내용을 호출한 부분이구요.
나머지부분또한 필요해서 넣은 것입니다.
새글로 작성할 때에는 상관이 없는데, {$Content}만 호출하여 글수정을 하면 이미 작성된 부분을 반영하지 못하더라구요.
그래서 저렇게 넣은 것입니다. 문서의 번호가 부여된 글.. 그러니까 이미 작성된 글에서는 {$Content}를 호출하지 않게요. 아래는 테스트 결과입니다.
((-------IMAGE-------))
2. 위의 경우로 예를 들면 $Content 변수를 선언하지 않고 value에 직접 내용을 입력하는 방법입니다. view plaincopy to clipboardprint? <input type="hidden" name="content" value="<!--@if($document_srl == $oDocument->document_srl)-->{$oDocument->getContentText()}<!--@else-->에디터에 미리 글을 넣어봅시다<br />태그를 이용할 수도 있군요!<!--@end-->" /> <input type="hidden" name="content" value="<!--@if($document_srl == $oDocument->document_srl)-->{$oDocument->getContentText()}<!--@else-->에디터에 미리 글을 넣어봅시다<br />태그를 이용할 수도 있군요!<!--@end-->" /> 에디터에 미리 글을 넣어봅시다<br />태그를 이용할 수도 있군요! 이 글귀가 있는 곳에 원하는 내용을 넣으시면 됩니다.

3. skin.xml을 이용하여 각 게시판마다 다른내용을 출력할 수 있습니다. skin.xml문서를 열어 변수를 추가합니다.
저는 editor_message로 추가했습니다.

((-------IMAGE-------))

그렇다면 이번에는 skin.xml 에 추가한 변수를 에디터에 불러와야겠죠?
어떻게 호출하는지 아시겠지만 처음사용하는 분들을 위해 설명을 해볼께요. write_form.html 문서를 열고 form영역안에 아래와 같이 추가하시면 됩니다. view plaincopy to clipboardprint? <input type="hidden" name="content" value="<!--@if($document_srl == $oDocument->document_srl)-->{$oDocument->getContentText()}<!--@else-->{$module_info->editor_message}<!--@end-->" /> <input type="hidden" name="content" value="<!--@if($document_srl == $oDocument->document_srl)-->{$oDocument->getContentText()}<!--@else-->{$module_info->editor_message}<!--@end-->" /> 내용을 불러오는 곳에 {$module_info->editor_message} 이 변수를 추가했습니다.
아시겠지만 skin.xml에 추가한 변수이름이 editor_message이고...
skin.xml에서 추가한 변수의 호출시작은 $module_info로 합니다. ... 글을 마치며 ...

확장변수를 이용하여 위와 같이 할 수도 있지만 많이 번거로울 것 같아서 생략합니다.

클릭하면 사라지는 자바가.. 저는 적용이 안되더군요. 음..

여러가지로 응용해보세요.
출석부를 만들다가 해보니 되길래 팁게시판에도 없는 것 같아서 올리는 팁입니다.
by Anna 안나 2008. 6. 1. 20:42
검색해봤지만 없는 것 같아 올립니다. 중복이면 지우겠습니다.
그리고 굉장히 쉬운 팁일 수도 있겠으나 저처럼 초보라서 어딜 건드려야 하는지 몰라 답답하실 분들께 도움이 되면 좋겠네요.


확장변수, 특히 여러줄입력칸(textarea) 사용시 태그가 먹히도록 하고 싶으시면
스킨파일의 extra_var_value.html를 수정합니다.(예를들어 zbxe/modules/board/skins/xe_board/extra_var_value.html)

<!-- textarea -->
<!--@elseif($val->type!--@elseif($val->type == 'textarea')-->
{nl2br(htmlspecialchars($val->value))}
&nbsp;


이 부분을 찾아서
{nl2br(htmlspecialchars($val->value))} 를 {$val->value} 로 바꿔주시면 됩니다.

줄바꿈(br) 태그만은 자동으로 먹히게 하고 싶다면 {nl2br($val->value)} 로 수정하면 되지요.
by Anna 안나 2008. 6. 1. 20:41
이틀째, 제로보드 XE와 씨름을 하고 있습니다.

메뉴 고정 펼침 기능이 체크만으로는 잘 안먹죠?

view plaincopy to clipboardprint? <!-- main_menu 3차 시작 --> <!--@if($val['list'])--> <ul style="display:block;"> <!--@foreach($val['list'] as $k => $v)--><!--@if($v['text'])--> <li <!--@if($v['selected'])-->class="on"<!--@end-->><a href="{$v['href']}" <!--@if($v['open_window']=='Y')-->onclick="window.open(this.href);return false;"<!--@end-->>{$v['text']}</a></li> <!--@end--><!--@end--> <!-- main_menu 3차 시작 --> <!--@if($val['list'])--> <ul style="display:block;"> <!--@foreach($val['list'] as $k => $v)--><!--@if($v['text'])--> <li <!--@if($v['selected'])-->class="on"<!--@end-->><a href="{$v['href']}" <!--@if($v['open_window']=='Y')-->onclick="window.open(this.href);return false;"<!--@end-->>{$v['text']}</a></li> <!--@end--><!--@end-->
3차 메뉴를 모두 펼치고 싶은 분들은, 레이아웃의
<ul style="display:block;"> 태그에 스타일을 추가해서 항상 보이도록 강제 세팅하시면 됩니다.

이 방법이야말로 언발에 오줌누기라서...

tree_menu.js 파일에 관해 빵조각(?)이 떨어져 있는데...

빵조각을 따라가기엔 시간이 촉박하여 저 방법을 썼습니다.

참고만하세요...
by Anna 안나 2008. 6. 1. 20:40
안녕하세요 럭키입니디 ㅏ.. #_#;;

많은분들이 메뉴와 관련된부분을 어려워 하시는거 같습니다.

1차메뉴부터..
<!-- main_menu 1차 시작 -->
<!--@foreach($main_menu->list as $key => $val)-->
<!--@if($val['text'])--> ①
<!--@if($val['selected'])--> ②
{@ $menu_1st = $val }
<!--@end--> ②
// 밑에 li안에있는 IF가 ③ <li <!--@if($val['selected'])-->class="on"<!--@end-->><a href="{$val['href']}" <!--@if($val['open_window']=='Y')-->onclick="window.open(this.href);return false;"<!--@end-->>{$val['text']}</a></li> <!--@end--> ③
<!--@end--> ①
<!-- main_menu 1차 끝 -->
아닐수도있지만 전 제나름대로의 방식대로 이해했습니다. .....

일단 제나름대로 해석해보면..
메뉴정보를 가져와서, $val에 가져오고
①IF 로 $val['text'] 1차메뉴가 하나이상 있을때 밑에부분을 실행하란 말입니다
((-------IMAGE-------))
이안에서 또 ② If로 $val['selected'] 현재 메뉴가 선택되어있을때(만약 공지게시판에 접속했다면 공지게시판이 선택)
$menu_1st 에 $val값을 대입, ② End문으로 ② IF를 닫습니다.
그리고
<li <!--@if($val['selected'])-->class="on"<!--@end-->><a href="{$val['href']}" <!--@if($val['open_window']=='Y')-->onclick="window.open(this.href);return false;"<!--@end-->>{$val['text']}</a></li>

CSS에서 지정해놓았던 <li 에 ③ IF $val['selected'] 메뉴가 선택되어있다면 class="on" 이란 클래스를 지정하고 End
a href .. 링크는 메뉴관리에서 설정한 링크를 지정하고, 그뒷부분은 메뉴관리에서 새창열기가 체크?을경우 새창으로 띄워줍니다
{$val['text']) 는 메뉴이름을 보여줍니다.
그리고 맨밑에 ① IF를 닫습니다.
1차 메뉴 끝
즉 1차메뉴가 한개이상 있을경우, <li><a href="링크">메뉴항목</a></li>
이렇게 반복적으로 출력한단 말이고, 현재 메뉴일경우 class="on"이란 클래스를 지정해줌으로써
현재 위치한 메뉴에 CSS를이용하여 효과를 주는것입니다.

----------------------------
<!-- 왼쪽 2차 메뉴 -->
<!--@if($menu_1st)-->
<ol id="lnb">
{@ $idx = 1 }
<!--@foreach($menu_1st['list'] as $key => $val)--><!--@if($val['text'])-->
<li <!--@if($val['selected'])-->class="on"<!--@end-->><a href="{$val['href']}" <!--@if($val['open_window']=='Y')-->onclick="window.open(this.href);return false;"<!--@end-->>{$val['text']}</a> <!-- main_menu 3차 시작 -->
<!--@if($val['list'])-->
<ul>
<!--@foreach($val['list'] as $k => $v)--><!--@if($v['text'])-->
<li <!--@if($v['selected'])-->class="on"<!--@end-->><a href="{$v['href']}" <!--@if($v['open_window']=='Y')-->onclick="window.open(this.href);return false;"<!--@end-->>{$v['text']}</a></li>
<!--@end--><!--@end-->
</ul>
<!--@end-->
</li>
{@$idx++}
<!--@end--><!--@end-->
</ol>
<!--@end-->
2차메뉴까지만 이해한다면 3차부터는 그대로 응용하시면 가능한 문제입니다.
일단 2차메뉴는 1차메뉴의 하위메뉴입니다.
그러므로 ① IF에서 1차메뉴가 있을? 밑에 문법을 실행합니다.
$idx에 1을 대입하고, $menu_1st , $key 메뉴정보를 $val에 가져옵니다.
여기서 보니 아마 $key는 2차메뉴정보가 있나봅니다.
② If로 val['text'] 2차메뉴가 있을때, 밑에 문법들을 실행하라..이말이죠
아까 1차메뉴와 똑같이, 메뉴가 선택되었을때 class="on" 을 지정하고,
링크나 새창 , 메뉴출력 .. 다 1차와 똑같이 되어있죠~
즉.. 무슨말이냐

저거 진하게 강조한부분만 변경하시면, 4차메뉴나 5차메뉴도 가져오실수있습니다.
음.. 그럼 ZBXE공식사이트에있는걸 기준으로 4차메뉴 추가한 예제를 보여드릴게요

<!-- main_menu 2차 시작 -->
<!--@if($menu_1st)-->
<ol id="lnb">
{@ $idx = 1 }
<!--@foreach($menu_1st['list'] as $key => $val)--><!--@if($val['text'])-->
<li <!--@if($val['selected'])-->class="on"<!--@end-->><a href="{$val['href']}" <!--@if($val['open_window']=='Y')-->onclick="window.open(this.href);return false;"<!--@end-->>{$val['text']}</a> <!-- main_menu 3차 시작 -->
<!--@if($val['list'])-->
<ul>
<!--@foreach($val['list'] as $k => $v)--><!--@if($v['text'])-->
<li <!--@if($v['selected'])-->class="on"<!--@end-->><a href="{$v['href']}" <!--@if($v['open_window']=='Y')-->onclick="window.open(this.href);return false;"<!--@end-->>{$v['text']}</a></li>
<!-- main_menu 4차 시작 -->
<!--@if($v['list'])-->
<ul>
<!--@foreach($v['list'] as $k => $v4)--><!--@if($v4['text'])-->
<li <!--@if($v4['selected'])-->class="laa"<!--@end-->><a href="{$v4['href']}" <!--@if($v4['open_window']=='Y')-->onclick="window.open(this.href);return false;"<!--@end-->>{$v4['text']}</a></li>
<!--@end--> <!--@end--> <!--@end--> <!--@end-->
</ul>
<!--@end--><!--@end-->
</li>
{@$idx++}
<!--@end--><!--@end-->
</ol>
<!--@end-->
보시면 아시겠지만 3차메뉴에서는 2차메뉴인 val['list'] 에서 가져온것을 $v에 담아두고있습니다.
4차에서는 이걸이용해 3차메뉴인 $v['list'] 에서 가져온것을 $v4에 담아두고 이용하면 잘됩니다.
만약 5차메뉴도 추가하고싶다면 4차메뉴인 $v4['list'] 에서 가져와서 이용하시면 되겠죠..??

.......
쓰고보니까 글도 너무 복잡하고 길어서 죄송합니다 .ㅜ __ㅜ
모르거나 이해안가시는것은 댓글이나 쪽지로 주세요 __ ....

★ 제가 위에서 소스해석한게 틀릴수도있습니다. 하지만 무작정 붙여넣어서 쓰는것보단 이렇게라도 이해하고 쓰면 쉽게 할수있습니다.
by Anna 안나 2008. 6. 1. 20:39
((-------IMAGE-------))

이 팁은 메뉴를 플래시로 바꾼다고 해서 플래시를 배경으로 하고 그위에 메뉴가 자동으로 나타나게 하는 것이 아니라 ,
플래시를 만들때 메뉴를 직접 넣어서 만들어야 합니다.
실력이 미천하여 플래시를 배경으로 하고 그위에 메뉴가 구현되게 하기는 역부족입니다.

먼저 플래시파일을 제작해야겠죠(Flash Mx 나 Swish Max 사용)
제작된 플래시파일을 자신이 선택한 폴더에 업로드합니다.(Ex : /img/flash.swf)

자신이 사용중인 레이아웃 (Ex : xe_official)
1. layout.html를 에디터기로 엽니다.
[변경전] - 23줄부터
<div id="bodyWrap">
<div id="header">
<h1><a href="{$layout_info->index_url}"><!--@if(!$layout_info->logo_image)--><img src="./images/{$layout_info->colorset}/zeroBoardXE.png" alt="ZeroBoard™ XE" class="iePngFix" /><!--@else--><img src="{$layout_info->logo_image}" alt="logo" border="0" class="iePngFix" /><!--@end--></a></h1>[변경전] - 36줄부터
<!--GNB-->
<ul id="gnb">
<!-- main_menu 1차 시작 -->
<!--@foreach($main_menu->list as $key => $val)--><!--@if($val['link'])-->
<!--@if($val['selected'])-->
{@ $menu_1st = $val }
<!--@end-->

<li <!--@if($val['selected'])-->class="on"<!--@end-->><a href="{$val['href']}" <!--@if($val['open_window']=='Y')-->onclick="window.open(this.href);return false;"<!--@end-->>{$val['link']}</a></li>

<!--@end--><!--@end-->
<!-- main_menu 1차 끝 -->
</ul>
<!--//GNB-->
[변경후] - 빨간색 부분 추가 (플래시메뉴 추가하는 소스)
<div id="header">
<h1><a href="{$layout_info->index_url}"><!--@if(!$layout_info->logo_image)--><img src="./images/{$layout_info->colorset}/zeroBoardXE.png" alt="ZeroBoard™ XE" class="iePngFix" /><!--@else--><img src="{$layout_info->logo_image}" alt="logo" border="0" class="iePngFix" /><!--@end--></a></h1>

<h2><script type="text/javascript">displayMultimedia("/img/flash.swf", "980","100",false);</script></h2>"980","100", "가로크기", "세로크기", 자신의 스킨에 맞게 변경하세요
[변경후] - 녹색 부분 제거 (기존의 메뉴부분 삭제, 다 지우면 왼쪽 2차메뉴 생성이 안됩니다)
<!--GNB-->
<ul id="gnb">
<!-- main_menu 1차 시작 -->
<!--@foreach($main_menu->list as $key => $val)--><!--@if($val['text'])-->
<!--@if($val['selected'])-->
{@ $menu_1st = $val }
<!--@end-->

<!--@end--><!--@end-->
<!-- main_menu 1차 끝 -->
</ul>
<!--//GNB-->여기까지가 layout.html를 편집하는 부분입니다.

2. 해당 칼라의 css를 엽니다. (Ex : default.css)
15줄
#header h1 { position:absolute; top:32px; left:25px;}
아래에
#header h2 { position:absolute; top:75px; right:0px;}
를 추가해 줍니다.
top:75px; right:0px; 도 자신의 스킨에 맞게 변경하세요.

이상 이렇게 하면 메뉴가 플래시로 바뀝니다.
바꾸기전에 자신의 메뉴가 확립된 상태에서 하는 것이 좋을 것입니다.
아니면 메뉴가 바뀔때마다 플래시메뉴를 편집해야 합니다.
별 것도 아니지만 혹시나 필요한 분이 있을까봐 올려봅니다.
by Anna 안나 2008. 6. 1. 20:37
((-------IMAGE-------))


제로보드4로 운영하던 사이트에서 사용하던 플래시 메뉴를
제로보드XE에 적용시켜 봤습니다.

제로보드XE에서 플래시 파일을 불러들이는 방식이 embed 태그없이 아주 간편하게 되어 있어서
오히려 적용하기기 수월해졌습니다.

제로보드4에서 사용할 때는 한 플래시 파일에 메뉴 버튼을 필요만큼 미리 만들어서 사용했었는데
한 플래시 파일에 한 버튼만 두고, 레이아웃의 메뉴 불러들이는 방식으로 플래시 파일을 삽입하는 방식으로 적용했습니다.

우선 레이아웃에서 플래시 파일을 읽어들이는 방식은
<script type="text/javascript">displayMultimedia("http://주소/submenulist.swf", "150","200",false);</script>
이와 같이 불러 들일 수 있지요

이 플래시 파일에 변수를 전달하려면
url 부분을 아래와 같이 확장하면 되더군요..
http://주소/submenulist.swf?변수1=값1&변수2=값2&변수3=값3.....
메뉴의 갯수가 고정적이라면 첨부한 submentlist.fla를 수정하여 위와 같은 방식으로 사용하면 될것입니다.

이제 submenu1.swf를 이용하여 레이아웃의 sub 메뉴에 적용시키는 방법을 말씀드리겠습니다.

레이아웃의 서브 메뉴 부분을 보면
<!-- 왼쪽 2차 메뉴 -->
<img src="./images/blank.gif" alt="" class="mask" />
<!--@if($menu_1st)-->
<ol id="lnb">
{@ $idx = 1 }
<!--@foreach($menu_1st['list'] as $key => $val)-->
<!--@if($val['text'])-->
<li <!--@if($val['selected'])-->class="on"<!--@end-->>
<a href="{$val['href']}" <!--@if($val['open_window']=='Y')-->onclick="window.open(this.href);return false;"<!--@end-->>
{$val['text']}</a>
<!-- main_menu 3차 시작 -->
<!--@if($val['list'])-->
<ul>
<!--@foreach($val['list'] as $k => $v)-->
<!--@if($v['text'])-->
<li <!--@if($v['selected'])-->class="on"<!--@end-->>
<a href="{$v['href']}" <!--@if($v['open_window']=='Y')-->onclick="window.open(this.href);return false;"<!--@end-->>
{$v['text']}</a>
</li>
<!--@end-->
<!--@end-->
</ul>
<!--@end-->
</li>
{@$idx++}
<!--@end-->
<!--@end-->
</ol>
<!--@end-->

이것을 아래와 같이 수정합니다.
<!-- 왼쪽 2차 플래시 메뉴 -->
<img src="./images/blank.gif" alt="" class="mask" />
<!--@if($menu_1st)-->
<ol id="lnb">
{@ $idx = 1 }
{@ $selbtnno = 0 }
{@ $selbtn3no = 0 }
<!--@foreach($menu_1st['list'] as $key => $val)--><!--@if($val['text'])-->
<!--@if($val['selected'])-->
{@ $selbtnno = 1 }
<!--@else-->
{@ $selbtnno = 0 }
<!--@end-->
<li>
<script type="text/javascript">displayMultimedia("http://주소/submenu1.swf?pselbtn={$selbtnno}&pbtn1menu={$val['text']}&pbtn1url={$val['href']}", "190","21",false);</script>
<!-- main_menu 3차 시작 -->
<!--@if($val['list'])-->
<ul <!--@if($val['selected'])-->style="display:block"<!--@end-->>
<!--@foreach($val['list'] as $k => $v)--><!--@if($v['text'])-->
<!--@if($v['selected'])-->
{@ $selbtn3no = 1 }
<!--@else-->
{@ $selbtn3no = 0 }
<!--@end-->
<li>
<script type="text/javascript">displayMultimedia("http://주소/submenu1.swf?pselbtn={$selbtn3no}&pbtn1menu={$v['text']}&pbtn1url={$v['href']}", "190","21",false);</script>
</li>
<!--@end--><!--@end-->
</ul>
<!--@end-->
</li>
{@$idx++}
<!--@end--><!--@end-->
</ol>
<!--@end-->



변경된 부분을 비교해 보면
2차 메뉴에서
<li <!--@if($val['selected'])-->class="on"<!--@end-->>
<a href="{$val['href']}" <!--@if($val['open_window']=='Y')-->onclick="window.open(this.href);return false;"<!--@end-->>
{$val['text']}</a>
이 부분을
<li>
<script type="text/javascript">displayMultimedia("http://주소/submenu1.swf?pselbtn={$selbtnno}&pbtn1menu={$val['text']}&pbtn1url={$val['href']}", "190","21",false);</script>
이렇게 변경했습니다.
<li>의 selected되었을 때 class를 on으로 변경하는 부분이 지워진 것입니다.
class가 on이어야 3차메뉴가 display되기 때문에 이부분을 생략한 대신 3차메뉴 부분에서
<ul <!--@if($val['selected'])-->style="display:block"!--@end-->
이 부분을 첨가했습니다.
그리고 새창열기 옵션은 사용하지 않는 것으로 전제하고 window.open 부분도 생략했습니다.

다음 변경된 부분에서 플래시 파일을 불러들일 때 url 옵션
http://주소/submenu1.swf?pselbtn={$selbtnno}&pbtn1menu={$val['text']}&pbtn1url={$val['href']}

변수 pselbtn과 값 {$selbtnno}
이 변수와 값은 레이아웃이 로딩될 때 메뉴가 선택되어 있는가의 여부에 따라 플래시 버튼에 다른 액션을 주기 위한 값입니다.
{$selbtnno}을 할당하는 부분은 위에서 찾으실 수 있을 겁니다.
pbtn1menu와 pbtn1url에 각각 메뉴 text와 메뉴 href를 할당합니다.

이제 첨부한 submenu1.swf를 사이트에 적당한 위치에 업로드하고
http://주소/submenu1.swf 주소 부분만 수정해서 쓰시면 됩니다..

더불어서 플래시 소스 파일도 올려 놓겠습니다.
한 층 세련된 디자인의 메뉴용 플래시 파일들이 올라오길 바랍니다.

맨 앞에서 적은 것처럼
한 파일에 여러개의 메뉴 버튼를 적용하려면
submenutest.fla처럼 메뉴 버튼 갯수를 조절해서 쓰셔도 됩니다.
by Anna 안나 2008. 6. 1. 20:36
| 1 2 |