diff --git a/.htaccess b/.htaccess index 17d0d7415..a8a9628cb 100644 --- a/.htaccess +++ b/.htaccess @@ -1,5 +1,8 @@ RewriteEngine On +# reserve XE Layout Template Source File (*.html) +RewriteRule ^layouts/(.+)/(.+).html$ ./index.php [L] + # static files RewriteRule ^(.+)/files/member_extra_info/(.*) ./files/member_extra_info/$2 [L] RewriteRule ^(.+)/files/attach/(.*) ./files/attach/$2 [L] diff --git a/addons/blogapi/blogapi.addon.php b/addons/blogapi/blogapi.addon.php index 09237dd5d..2d77ae1f0 100644 --- a/addons/blogapi/blogapi.addon.php +++ b/addons/blogapi/blogapi.addon.php @@ -243,7 +243,6 @@ } } - debugPrint($obj->content); // 문서 번호 설정 $document_srl = getNextSequence(); @@ -265,7 +264,7 @@ } } - $obj->content = str_replace($uploaded_target_path,sprintf('/files/attach/images/%s/%s%s', $this->module_srl, getNumberingPath($document_srl,3), $filename), $obj->content); + $obj->content = str_replace($uploaded_target_path,sprintf('./files/attach/images/%s/%s%s', $this->module_srl, getNumberingPath($document_srl,3), $filename), $obj->content); $oDocumentController = &getController('document'); $obj->allow_comment = 'Y'; @@ -356,7 +355,7 @@ $obj->uploaded_count += $file_count; } } - $obj->content = str_replace($uploaded_target_path,sprintf('/files/attach/images/%s/%s%s', $this->module_srl, getNumberingPath($document_srl,3), $filename), $obj->content); + $obj->content = str_replace($uploaded_target_path,sprintf('./files/attach/images/%s/%s%s', $this->module_srl, getNumberingPath($document_srl,3), $filename), $obj->content); $oDocumentController = &getController('document'); $output = $oDocumentController->updateDocument($oDocument,$obj); diff --git a/addons/captcha/captcha.addon.php b/addons/captcha/captcha.addon.php index 4fa01548f..f50f6c600 100644 --- a/addons/captcha/captcha.addon.php +++ b/addons/captcha/captcha.addon.php @@ -20,6 +20,7 @@ $target_acts = array('procBoardInsertDocument','procBoardInsertComment','procIssuetrackerInsertIssue','procIssuetrackerInsertHistory'); if($addon_info->apply_find_account=='apply') $target_acts[] = 'procMemberFindAccount'; + if($addon_info->apply_resend_auth_mail=='apply') $target_acts[] = 'procMemberResendAuthMail'; Context::addHtmlHeader(''); diff --git a/addons/captcha/conf/info.xml b/addons/captcha/conf/info.xml index b1c283de1..87ea216ff 100644 --- a/addons/captcha/conf/info.xml +++ b/addons/captcha/conf/info.xml @@ -79,9 +79,9 @@ 비밀번호 찾기 적용 비밀번호 찾기 적용 비밀번호 찾기 적용 - 적용으로 하시면 비밀번호찾기 기능에도 적용되어 악의적인 봇(또는 프로그램)에 의한 메일 발송을 막을 수 있습니다. - 적용으로 하시면 비밀번호찾기 기능에도 적용되어 악의적인 봇(또는 프로그램)에 의한 메일 발송을 막을 수 있습니다. - 적용으로 하시면 비밀번호찾기 기능에도 적용되어 악의적인 봇(또는 프로그램)에 의한 메일 발송을 막을 수 있습니다. + 적용으로 하시면 비밀번호 찾기 기능에도 적용되어 악의적인 봇(또는 프로그램)에 의한 메일 발송을 막을 수 있습니다. + 적용으로 하시면 비밀번호 찾기 기능에도 적용되어 악의적인 봇(또는 프로그램)에 의한 메일 발송을 막을 수 있습니다. + 적용으로 하시면 비밀번호 찾기 기능에도 적용되어 악의적인 봇(또는 프로그램)에 의한 메일 발송을 막을 수 있습니다. 적용으로 하시면 비밀번호찾기 기능에도 적용되어 악의적인 봇(또는 프로그램)에 의한 메일 발송을 막을 수 있습니다. 적용하지 않음 @@ -96,5 +96,27 @@ 적용 + + 인증 메일 재발송 적용 + 인증 메일 재발송 적용 + 인증 메일 재발송 적용 + 인증 메일 재발송 적용 + 적용으로 하시면 인증 메일 재발송 기능에도 적용되어 악의적인 봇(또는 프로그램)에 의한 메일 발송을 막을 수 있습니다. + 적용으로 하시면 인증 메일 재발송 기능에도 적용되어 악의적인 봇(또는 프로그램)에 의한 메일 발송을 막을 수 있습니다. + 적용으로 하시면 인증 메일 재발송 기능에도 적용되어 악의적인 봇(또는 프로그램)에 의한 메일 발송을 막을 수 있습니다. + 적용으로 하시면 인증 메일 재발송 기능에도 적용되어 악의적인 봇(또는 프로그램)에 의한 메일 발송을 막을 수 있습니다. + + 적용하지 않음 + 적용하지 않음 + 적용하지 않음 + 적용하지 않음 + + + 적용 + 적용 + 적용 + 적용 + + diff --git a/addons/captcha/lang/en.lang.php b/addons/captcha/lang/en.lang.php index c46b9ce65..31858ba45 100644 --- a/addons/captcha/lang/en.lang.php +++ b/addons/captcha/lang/en.lang.php @@ -5,7 +5,7 @@ * @brief English Language Pack **/ - $lang->about_captcha = "Choose an image whose name is listed below"; + $lang->about_captcha = "Please choose an image whose name is listed below"; $lang->target_captcha = array( "airplane" => "airplane", "apple" => "apple", diff --git a/addons/mobile/classes/mobile.class.php b/addons/mobile/classes/mobile.class.php index c6fb93172..1e26399b0 100644 --- a/addons/mobile/classes/mobile.class.php +++ b/addons/mobile/classes/mobile.class.php @@ -445,7 +445,7 @@ // 변환 후 출력 if(strtolower($this->charset) == 'utf-8') print $content; - else print iconv('UTF-8',$this->charset."//TRANSLIT", $content); + else print iconv('UTF-8',$this->charset."//TRANSLIT//IGNORE", $content); exit(); } diff --git a/addons/mobile/lang/jp.lang.php b/addons/mobile/lang/jp.lang.php index 697c560e6..3aa8e74e7 100644 --- a/addons/mobile/lang/jp.lang.php +++ b/addons/mobile/lang/jp.lang.php @@ -5,7 +5,13 @@ * @brief 日本語言語パッケージ **/ + // 言語選択部分 by misol + $lang->president_lang = '現在言語'; + $lang->select_lang = '言語選択'; + $lang->lang_return = '戻る'; + $lang->cmd_go_upper = '上位メニュー'; $lang->cmd_go_home = 'トップへ'; $lang->cmd_view_sitemap = 'サイトマップ'; + ?> diff --git a/addons/mobile/lang/zh-TW.lang.php b/addons/mobile/lang/zh-TW.lang.php index fc321705e..13d8df620 100644 --- a/addons/mobile/lang/zh-TW.lang.php +++ b/addons/mobile/lang/zh-TW.lang.php @@ -4,6 +4,10 @@ * @author zero (zero@nzeo.com) 翻譯:royallin * @brief XE行動上網正體中文語言 **/ + // lang select by misol + $lang->president_lang = '已選擇語言'; + $lang->select_lang = '選擇語言'; + $lang->lang_return = '返回'; $lang->cmd_go_upper = '回上頁'; $lang->cmd_go_home = '回首頁'; diff --git a/addons/point_level_icon/conf/info.xml b/addons/point_level_icon/conf/info.xml index 68d8dafe2..c96dc5821 100644 --- a/addons/point_level_icon/conf/info.xml +++ b/addons/point_level_icon/conf/info.xml @@ -22,7 +22,7 @@ This addon displays level icon in front of the user name when you are using the point system. - You can choose the level icon on Module > Point System. + You can choose the level icon in Module > Point System. Dieses Addon zeigt Level Icon vor dem Benutzernamen, wenn Sie die Punkte-System. diff --git a/addons/rainbow_link/conf/info.xml b/addons/rainbow_link/conf/info.xml index 01c984779..334c6ce4e 100644 --- a/addons/rainbow_link/conf/info.xml +++ b/addons/rainbow_link/conf/info.xml @@ -29,7 +29,7 @@ <a href="http://www.dynamicdrive.com" target="_blank">Dynamicdrive.com</a> tiene derecho de autor sobre rainbow.js - 「rainbow.js」をヘッダーに追加し、リンクが張られている文字列の色を虹色で表示します。この機能拡張の「 rainbow.js」は「<a href="http://www.dynamicdrive.com" target="_blank">Dynamicdrive.com</a>」に著作権があります。 + 「rainbow.js」をヘッダーに追加し、リンクが張られている文字列の色を虹色で表示します。この機能拡張の「rainbow.js」は「<a href="http://www.dynamicdrive.com" target="_blank">Dynamicdrive.com</a>」に著作権があります。 Этот аддон добавляет файл с именем "rainbow.js" в заголовки HTML, и тогда связанный текс приобретает эффект смены цвета, подобно радуге или хамелеону. diff --git a/addons/resize_image/js/resize_image.js b/addons/resize_image/js/resize_image.js index 9f8b5982e..b0fe66bc8 100644 --- a/addons/resize_image/js/resize_image.js +++ b/addons/resize_image/js/resize_image.js @@ -2,14 +2,14 @@ * @brief 화면내에서 상위 영역보다 이미지가 크면 리사이즈를 하고 클릭시 원본을 보여줄수 있도록 변경 **/ (function($){ - + var xScreen = null; // 슬라이드를 위한 블랙 스크린을 만들거나 반환하는 함수 function getScreen() { var body = $(document.body); var controls, imgframe, closebtn, prevbtn, nextbtn; - + // 스크린이 없으면 스크린을 만든다. if (!xScreen) { // 검은 스크린 @@ -22,7 +22,7 @@ function getScreen() { zIndex:500, opacity:0.5 }); - + // 이미지를 보여주고 컨트롤 버튼을 다룰 레이어 controls = $("
") .attr("id","xe_gallery_controls") @@ -32,7 +32,7 @@ function getScreen() { overflow:"hidden", zIndex:510 }); - + // 닫기 버튼 closebtn = $("") .attr("id", "xe_gallery_closebtn") @@ -42,7 +42,7 @@ function getScreen() { }) .click(function(){xScreen.xeHide()}) .appendTo(controls); - + // 이전 버튼 prevbtn = $("") .attr("id", "xe_gallery_prevbtn") @@ -50,7 +50,7 @@ function getScreen() { .css("left","10px") .click(function(){xScreen.xePrev()}) .appendTo(controls); - + // 다음 버튼 nextbtn = $("") .attr("id", "xe_gallery_nextbtn") @@ -58,7 +58,7 @@ function getScreen() { .css("right","10px") .click(function(){xScreen.xeNext()}) .appendTo(controls); - + // 버튼 공통 속성 controls.find("img") .attr({ @@ -73,7 +73,7 @@ function getScreen() { zIndex : 530, cursor : "pointer" }); - + // 이미지 홀더 imgframe = $("") .attr("id", "xe_gallery_holder") @@ -82,12 +82,12 @@ function getScreen() { .appendTo(controls).draggable(); body.append(xScreen).append(controls); - + // xScreen 객체를 확장한다. xScreen.xeShow = function() { var clientWidth = $(window).width(); var clientHeight = $(window).height(); - + $("#xe_gallery_controls,#xe_gallery_screen").css({ display:"block", width : clientWidth + "px", @@ -115,19 +115,19 @@ function getScreen() { xScreen.xeMove = function(val) { var clientWidth = $(window).width(); var clientHeight = $(window).height(); - + this.index += val; prevbtn.css("visibility", (this.index>0)?"visible":"hidden"); nextbtn.css("visibility", (this.index
'); - $(".xe_content").each(function() { - $(this).find("img").each(function(){ - var img = $(this); - var width = img.attr("width"); - if(!width) width = img.width(); - img.attr("orig_width",width); - img.attr("width",1); - }); - var offsetWidth = $(this).width(); + /** + * 리사이즈 실행 함수 + **/ + function doResize(contentWidth, count) { + // 재시도 회수 제한 + if(!count) count = 0; + if(count >= 10) return; - $(this).find("img").each(function(){ - var img = $(this); - var src = img.attr("src"); - img.attr("width",img.attr("orig_width")); - img.removeAttr("orig_width",''); - var width = img.attr("width"); - var height = img.attr("height"); - - // XE 내부 프로그램 또는 스킨의 이미지라면 이미지 리사이즈를 하지 않음 - if ( !regx_skip.test(src) ) { - // 커스텀 속성 추가 - img.attr("rel", "xe_gallery"); + var $img = this; + var beforSize = {'width':$img.width(), 'height':$img.height()}; - // 크기를 계산한다 - if(width>offsetWidth) { - img.attr("width",offsetWidth-10); - img.attr("height",parseInt(offsetWidth/width*height,10)); - } + // 이미지 사이즈를 구하지 못했을 때 재시도 + if(!beforSize.width || !beforSize.height) { + setTimeout(function() { + doResize.call($img, contentWidth, ++count) + }, 200); + return; + } - // 링크가 설정되어 있거나 onclick 이벤트가 부여되어 있으면 원본 보기를 하지 않음 - if ( !img.parent("a").size() && !img.attr("onclick") ) { - // 스타일 설정 - img.css("cursor", "pointer"); - - // 클릭하면 슬라이드쇼 시작 - img.click(slideshow); - } - } - }); - }); + // 리사이즈 필요 없으면 리턴 + if(beforSize.width <= contentWidth) return; + + var resize_ratio = contentWidth / beforSize.width; + + $img + .removeAttr('width').removeAttr('height') + .css({ + 'width':contentWidth, + 'height':parseInt(beforSize.height * resize_ratio, 10) + }); + } + + $('div.xe_content').each(function() { + dummy.appendTo(this); + var contentWidth = dummy.width(); + dummy.remove(); + if(!contentWidth) return; + + $('img', this).each(function() { + var $img = $(this); + var imgSrc = $img.attr('src'); + if(regx_skip.test(imgSrc) && !regx_allow_i6pngfix.test(imgSrc)) return; + + $img.attr('rel', 'xe_gallery'); + + doResize.call($img, contentWidth); + }); + + /* live 이벤트로 적용 (image_gallery 컴포넌트와의 호환 위함) */ + $('img[rel=xe_gallery]', this).live('mouseover', function() { + var $img = $(this); + if(!$img.parent('a').length && !$img.attr('onclick')) { + $img.css('cursor', 'pointer').click(slideshow); + } + }); + }); }); })(jQuery); diff --git a/addons/smartphone/conf/info.xml b/addons/smartphone/conf/info.xml index 55552e395..065e59a3b 100644 --- a/addons/smartphone/conf/info.xml +++ b/addons/smartphone/conf/info.xml @@ -1,10 +1,14 @@ - SmartphonePhone XE 애드온 - SmartphonePhone XE - SmartphonePhone XE アドオン + SmartPhone XE 애드온 + SmartPhone XE + SmartPhone XE + SmartPhone XE アドオン IPhone (touch) 등, smartphone 에서 접속시 최적화된 화면을 보여줍니다. + + + This addon displays the best screen for users who use smartphones like IPhone (touch). 以 IPhone (touch) 和 smartphone 瀏覽時會以最適當的畫面顯示。 @@ -16,6 +20,7 @@ 2009-04-20 haneul + haneul haneul haneul diff --git a/addons/wiki_link/conf/info.xml b/addons/wiki_link/conf/info.xml index 2a22f9e3e..296bef0b2 100644 --- a/addons/wiki_link/conf/info.xml +++ b/addons/wiki_link/conf/info.xml @@ -1,11 +1,15 @@ 위키 링크 애드온 + Wiki Linker 维基链接插件 維基百科 wikiリンクアドオン 위키 링크를 추가해주는 애드온. + + + This addon adds wiki link. 给维基模块添加链接的插件。 @@ -21,6 +25,7 @@ haneul + haneul haneul haneul haneul diff --git a/classes/context/Context.class.php b/classes/context/Context.class.php index ba2609b27..c6269a92e 100644 --- a/classes/context/Context.class.php +++ b/classes/context/Context.class.php @@ -338,7 +338,7 @@ **/ function checkSSO() { // GET 접속이 아니거나 설치가 안되어 있으면 패스 - if(Context::getRequestMethod()!='GET' || !Context::isInstalled()) return true; + if(Context::getRequestMethod()!='GET' || !Context::isInstalled() || in_array(Context::get('act'),array('rss','atom'))) return true; // DB info에 설정된 Default URL이 없다면 무조건 무사통과 $default_url = trim($this->db_info->default_url); @@ -359,8 +359,11 @@ } else { // SSO 결과를 받는 경우 session_name() 세팅 if(Context::get('SSOID')) { - setcookie(session_name(), Context::get('SSOID'), 0, '/'); - header("location:".getUrl('SSOID','')); + $session_name = Context::get('SSOID'); + setcookie(session_name(), $session_name); + + $url = preg_replace('/([\?\&])$/','',str_replace('SSOID='.$session_name,'',Context::getRequestUrl())); + header("location:".$url); return false; // SSO 결과를 요청 } else if($_COOKIE['sso']!=md5(Context::getRequestUri()) && !Context::get('SSOID')) { @@ -768,128 +771,139 @@ **/ function _getUrl($num_args=0, $args_list=array(), $domain = null) { static $site_module_info = null; - if($domain) $is_site = true; - else $is_site = false; - if(is_null($site_module_info)) { - $site_module_info = Context::get('site_module_info'); - } + // 가상 사이트 정보를 구함 + if(is_null($site_module_info)) $site_module_info = Context::get('site_module_info'); - // SiteID 요청시 전처리 + // SiteID 요청시 전처리 ($domain이 vid 형식일 경우 $domain값을 없애고 vid로 처리하도록 함) if($domain && isSiteID($domain)) { $vid = $domain; $domain = ''; } - // SiteID가 요청되지 않았다면 현재 site_module_info에서 SiteID 판별 - if(!$vid && $site_module_info->domain && isSiteID($site_module_info->domain)) { - $vid = $site_module_info->domain; + // $domain, $vid값이 없을 경우(= 현재 사이트 정보를 이용함) + if(!$domain && !$vid) { + if($site_module_info->domain && isSiteID($site_module_info->domain)) $vid = $site_module_info->domain; + else $domain = $site_module_info->domain; } - if(!$domain) { - if($site_module_info->domain && !isSiteID($site_module_info->domain)) $domain = $site_module_info->domain; + // $domain값이 있을 경우 현재 요청된 도메인과 비교해서 동일할 경우 제거 그렇지 않으면 http 프로토콜을 제거하고 제일 뒤에 / 를 붙임 + if($domain) { + $domain_info = parse_url($domain); + $current_info = parse_url($_SERVER['HTTP_HOST'].getScriptPath()); + if($domain_info['host'].$domain_info['path']==$current_info['host'].$current_info['path']) unset($domain); else { - if($this->db_info->default_url) $domain = $this->db_info->default_url; - else if(!$domain) $domain = Context::getRequestUri(); + $domain = preg_replace('/^(http|https):\/\//i','', trim($domain)); + if(substr($domain,-1) != '/') $domain .= '/'; } } - $domain = preg_replace('/^(http|https):\/\//i','', trim($domain)); - if(substr($domain,-1) != '/') $domain .= '/'; + // 변수 정리 + $get_vars = null; + + // GET 변수가 없거나 변수 초기화 지정이 되었을 경우 if(!$this->get_vars || $args_list[0]=='') { - $get_vars = null; - if(is_array($args_list) && $args_list[0]=='') { - array_shift($args_list); - $num_args = count($args_list); - } + // 요청받은 변수가 있고 첫번째 인자가 '' 라서 초기화를 해야 할 경우 요청받은 변수를 정리 + if(is_array($args_list) && $args_list[0]=='') array_shift($args_list); + // 초기화를 원하지 않을 경우 GET 변수를 배열로 처리 } else { $get_vars = get_object_vars($this->get_vars); } - for($i=0;$i<$num_args;$i=$i+2) { + // 새로 꾸미기를 원하는 변수를 정리 + for($i=0,$c=count($args_list);$i<$c;$i=$i+2) { $key = $args_list[$i]; $val = trim($args_list[$i+1]); + + // 값이 없으면 GET변수에서 해당 키를 제거 if(!isset($val)) { unset($get_vars[$key]); continue; } + // 새로운 변수를 정리 $get_vars[$key] = $val; } - unset($get_vars['vid']); + + // 변수중 vid, rnd값 제거 unset($get_vars['rnd']); - if(isset($get_vars['page'])&&$get_vars['page']<2) unset($get_vars['page']); + if($vid) $get_vars['vid'] = $vid; + else unset($get_vars['vid']); - /* member module중의 쪽지함/친구 관리 기능이 communication 모듈로 이전하여 하위 호환성을 위한 act값 변경 */ - if($get_vars['act'] == 'dispMemberFriend') $get_vars['act'] = 'dispCommunicationFriend'; - elseif($get_vars['act'] == 'dispMemberMessages') $get_vars['act'] = 'dispCommunicationMessages'; - /* 기존의 action의 값이 바뀌어서 이를 강제 변경 */ - elseif($get_vars['act'] == 'dispDocumentAdminManageDocument') $get_vars['act'] = 'dispDocumentManageDocument'; - elseif($get_vars['act'] == 'dispModuleAdminSelectList') $get_vars['act'] = 'dispModuleSelectList'; - - if($get_vars['act'] && $this->isExistsSSLAction($get_vars['act'])) $path = $this->getRequestUri(ENFORCE_SSL, $domain); - else $path = $this->getRequestUri(RELEASE_SSL, $domain); - - $var_count = count($get_vars); - if(!$var_count) { - if(!$is_site) return $path; - if($vid) { - if($this->allow_rewrite) $path .= $vid; - else $path .= '?vid='.$vid; - } - return $path; - } - - // rewrite모듈을 사용할때 getUrl()을 이용한 url 생성 - // 2009. 4. 8 mid, document_srl, site id, entry 를 제외하고는 rewrite rule 사용하지 않도록 변경 - if($this->allow_rewrite) { - if(count($get_vars)) foreach($get_vars as $key => $value) if(!isset($value) || $value === '') unset($get_vars[$key]); - - $var_keys = array_keys($get_vars); - asort($var_keys); - $target = implode('.',$var_keys); - - if($vid) $rpath = $path.$vid .'/'; - else $rpath = $path; - - switch($target) { - case 'mid' : - return $rpath.$get_vars['mid']; - case 'document_srl' : - return $rpath.$get_vars['document_srl']; - case 'document_srl.mid' : - return sprintf('%s%s/%s',$rpath,$get_vars['mid'],$get_vars['document_srl']); - case 'entry.mid' : - return sprintf('%s%s/entry/%s',$rpath,$get_vars['mid'],$get_vars['entry']); - case 'act.document_srl.key' : - if($get_vars['act']=='trackback') return sprintf('%s%s/%s/%s', $rpath,$get_vars['document_srl'],$get_vars['key'],$get_vars['act']); - break; - + if(count($get_vars)) { + foreach($get_vars as $key => $val) { + if(!trim($val)) unset($get_vars[$key]); } } - // rewrite 모듈을 사용하지 않고 인자의 값이 2개 이상이거나 rewrite모듈을 위한 인자로 적당하지 않을 경우 - if($vid) $url = 'vid='.$vid; - foreach($get_vars as $key => $val) { - if(!isset($val)) continue; - if(is_array($val) && count($val)) { - foreach($val as $k => $v) { - $url .= ($url?'&':'').$key.'['.$k.']='.urlencode($v); + // action명이 변경되었던 것에 대해 호환성을 유지하기 위한 강제 값 변경 + switch($get_vars['act']) { + case 'dispMemberFriend' : $get_vars['act'] = 'dispCommunicationFriend'; break; + case 'dispMemberMessages' : $get_vars['act'] = 'dispCommunicationMessages'; break; + case 'dispDocumentAdminManageDocument' : $get_vars['act'] = 'dispDocumentManageDocument'; break; + case 'dispModuleAdminSelectList' : $get_vars['act'] = 'dispModuleSelectList'; break; + } + + // URL 구성 + $query = null; + if($var_count = count($get_vars)) { + // rewrite mod 사용시 + if($this->allow_rewrite) { + $var_keys = array_keys($get_vars); + asort($var_keys); + $target = implode('.',$var_keys); + switch($target) { + case 'vid' : $query = $get_vars['vid']; break; + case 'mid' : $query = $get_vars['mid']; break; + case 'document_srl' : $query = $get_vars['document_srl']; break; + case 'document_srl.mid' : $query = $get_vars['mid'].'/'.$get_vars['document_srl']; break; + case 'entry.mid' : $query = $get_vars['mid'].'/entry/'.$get_vars['entry']; break; + case 'act.document_srl.key' : $query = $get_vars['act']=='trackback'?$get_vars['document_srl'].'/'.$get_vars['key'].'/'.$get_vars['act']:''; break; + case 'mid.vid' : $query = $get_vars['vid'].'/'.$get_vars['mid']; break; + case 'document_srl.vid' : $query = $get_vars['vid'].'/'.$get_vars['document_srl']; break; + case 'document_srl.mid.vid' : $query = $get_vars['vid'].'/'.$get_vars['mid'].'/'.$get_vars['document_srl']; break; + case 'entry.mid.vid' : $query = $get_vars['vid'].'/'.$get_vars['mid'].'/entry/'.$get_vars['entry']; break; + case 'act.document_srl.key.vid' : $query = $get_vars['act']=='trackback'?$get_vars['vid'].'/'.$get_vars['document_srl'].'/'.$get_vars['key'].'/'.$get_vars['act']:''; break; } - } else { - $url .= ($url?'&':'').$key.'='.urlencode($val); + } + + // rewrite mod 미사용 또는 query값이 생성되지 않았을 경우 get argument로 생성 + if(!$query) { + foreach($get_vars as $key => $val) { + if(is_array($val) && count($val)) { + foreach($val as $k => $v) $query .= ($query?'&':'').$key.'['.$k.']='.urlencode($v); + } else { + $query .= ($query?'&':'').$key.'='.urlencode($val); + } + } + if($query) $query = '?'.$query; } } - return $path.'?'.htmlspecialchars($url); + + // XE가 설치된 절대 경로를 구해서 query를 완성 + + // 항상 SSL을 이용하고 현재 SSL이 아닌 경우 https에 대한 prefix를 붙임 + if(Context::get('_use_ssl')=='always') { + if($_SERVER['HTTPS']!='on') $query = $this->getRequestUri(ENFORCE_SSL, $domain).$query; + // 상황에 따라 혹은 지정된 대상만 SSL 취급될 경우 + } else { + // SSL상태인데 대상이 SSL이 아닌 경우 + if($_SERVER['HTTPS']=='on') $query = $this->getRequestUri(ENFORCE_SSL, $domain).$query; + // SSL 상태가 아니면 domain값에 따라 query 완성 + else if($domain) $query = $this->getRequestUri(FOLLOW_REQUEST_SSL, $domain).$query; + else $query = getScriptPath().$query; + } + return htmlspecialchars($query); } /** * @brief 요청이 들어온 URL에서 argument를 제거하여 return **/ function getRequestUri($ssl_mode = FOLLOW_REQUEST_SSL, $domain = null) { + static $url = array(); + // HTTP Request가 아니면 패스 if(!isset($_SERVER['SERVER_PROTOCOL'])) return ; - static $url = array(); if(Context::get('_use_ssl') == "always") $ssl_mode = ENFORCE_SSL; if($domain) $domain_key = md5($domain); @@ -930,7 +944,7 @@ if(Context::get("_http_port") && Context::get("_http_port") != 80) { $url_info['port'] = Context::get("_http_port"); } - else + elseif($url_info['port']==80) { unset($url_info['port']); } diff --git a/classes/db/DBFirebird.class.php b/classes/db/DBFirebird.class.php index b9de8d553..460795057 100644 --- a/classes/db/DBFirebird.class.php +++ b/classes/db/DBFirebird.class.php @@ -18,6 +18,7 @@ var $password = NULL; ///< password var $database = NULL; ///< database var $prefix = 'xe'; ///< XE에서 사용할 테이블들의 prefix (한 DB에서 여러개의 XE 설치 가능) + var $idx_no = 0; // 인덱스 생성시 사용할 카운터 /** * @brief firebird에서 사용될 column type @@ -30,8 +31,8 @@ 'number' => 'INTEGER', 'varchar' => 'VARCHAR', 'char' => 'CHAR', - 'text' => 'BLOB SUB_TYPE TEXT SEGMENT SIZE 20', - 'bigtext' => 'BLOB SUB_TYPE TEXT SEGMENT SIZE 20', + 'text' => 'BLOB SUB_TYPE TEXT SEGMENT SIZE 32', + 'bigtext' => 'BLOB SUB_TYPE TEXT SEGMENT SIZE 32', 'date' => 'VARCHAR(14)', 'float' => 'FLOAT', ); @@ -176,16 +177,16 @@ $as = $this->addDoubleQuotes($as); } - // 함수 사용시 - $tmpFunc1 = null; - $tmpFunc2 = null; + // 함수 사용시 + $tmpFunc1 = null; + $tmpFunc2 = null; if(($no1 = strpos($string,'('))!==false && ($no2 = strpos($string, ')'))!==false) { $tmpFunc1 = substr($string, 0, $no1+1); - $tmpFunc2 = substr($string, $no2, strlen($string)-$no2+1); + $tmpFunc2 = substr($string, $no2, strlen($string)-$no2+1); $string = trim(substr($string, $no1+1, $no2-$no1-1)); } - // 테이블.필드 + // 테이블.필드 if(($no1 = strpos($string,'.'))!==false) { $tmpString1 = substr($string, 0, $no1); // table $tmpString2 = substr($string, $no1+1, strlen($string)-$no1+1); // field @@ -202,8 +203,8 @@ $string = $this->addDoubleQuotes($string); } - if($tmpFunc1 != null) $string = $tmpFunc1.$string; - if($tmpFunc2 != null) $string = $string.$tmpFunc2; + if($tmpFunc1 != null) $string = $tmpFunc1.$string; + if($tmpFunc2 != null) $string = $string.$tmpFunc2; if($as !== false) $string = $string." as ".$as; return $string; @@ -227,7 +228,7 @@ $isTable = false; foreach($tables as $key => $val) { if($key == $tmpString1) $isTable = true; - if($val == $tmpString1) $isTable = true; + if($val == $tmpString1) $isTable = true; } if($isTable) { @@ -322,25 +323,25 @@ while($tmp = ibase_fetch_object($result)) { foreach($tmp as $key => $val) { - $type = $output->column_type[$key]; + $type = $output->column_type[$key]; - if($type == null) { - foreach($output->columns as $cols) { - if($cols['alias'] == $key) { - $type = $output->column_type[$cols['name']]; - } - } - } + if($type == null) { + foreach($output->columns as $cols) { + if($cols['alias'] == $key) { + $type = $output->column_type[$cols['name']]; + } + } + } if($type == "text" || $type == "bigtext") { - $blob_data = ibase_blob_info($tmp->{$key}); + $blob_data = ibase_blob_info($tmp->{$key}); $blob_hndl = ibase_blob_open($tmp->{$key}); $tmp->{$key} = ibase_blob_get($blob_hndl, $blob_data[0]); ibase_blob_close($blob_hndl); } - else if($type == "char") { - $tmp->{$key} = trim($tmp->{$key}); // DB의 character set이 UTF8일때 생기는 빈칸을 제거 - } + else if($type == "char") { + $tmp->{$key} = trim($tmp->{$key}); // DB의 character set이 UTF8일때 생기는 빈칸을 제거 + } } $return[] = $tmp; @@ -563,24 +564,15 @@ if(count($index_list)) { foreach($index_list as $key => $val) { - // index name = prefix + table name + index_list - // index name 크기가 31byte로 제한되어 있어 중복되지 않을만큼 테이블명을 줄임 - // prefix name을 2byte 보다 크게 할 경우 31byte를 넘는 index name이 생김 - // 더 좋은 방법을 찾아봐야겠음. - $tok = strtok($table_name, "_"); + // index_name = prefix + 'idx_' + no + // index name 크기가 31byte로 제한되어 있어 일련번호로 대체 + $this->idx_no++; $index_name = $this->prefix; - $tok = strtok("_"); - $index_name .= substr($tok, 0, 2); - $index_name .= substr($tok, -1, 1); - $tok = strtok("_"); - while($tok !== false) { - $index_name .= substr($tok, 0, 1); - $tok = strtok("_"); - } + $index_name .= "idx_"; + $index_name .= sprintf("%04d", $this->idx_no); - - $schema = sprintf("CREATE INDEX \"%s_%s\" ON \"%s\" (\"%s\");", - $index_name, $key, $table_name, implode($val, "\",\"")); + $schema = sprintf("CREATE INDEX \"%s\" ON \"%s\" (\"%s\");", + $index_name, $table_name, implode($val, "\",\"")); $output = $this->_query($schema); //commit(); @ibase_commit($this->fd); @@ -723,28 +715,18 @@ ibase_blob_add($blh, $value); $value = ibase_blob_close($blh); } - else if($output->column_type[$name]!='number') { - //$value = "'".$value."'"; - } - elseif(!$value || is_numeric($value)) { - $value = (int)$value; - } + else if($output->column_type[$name]=='number') { + // 연산식이 들어갔을 경우 컬럼명이 있는 지 체크해 더블쿼터를 넣어줌 + preg_match("/(?i)[a-z][a-z0-9_-]+/", $value, $matches); - if(strlen($value) != 0) { - $pos = strpos($value, '+'); - if($pos == 0) $pos = strpos($value, '-'); - if($pos == 0) $pos = strpos($value, '*'); - if($pos == 0) { - $pos = strpos($value, '/'); - if(substr_count($value, ".") > 1) $pos = 0; // value에 url주소가 들어가는경우 - } + foreach($matches as $key => $val) { + $value = str_replace($val, "\"".$val."\"", $value); + } - if($pos != 0) { - $substr = substr($value, 0, $pos); - $value = '"'.$substr.'"'.substr($value, $pos, strlen($value)); - $column_list[] = sprintf("\"%s\" = %s", $name, $value); - continue; - } + if($matches != null) { + $column_list[] = sprintf("\"%s\" = %s", $name, $value); + continue; + } } $values[] = $value; @@ -973,13 +955,13 @@ foreach($tmp as $key => $val){ $type = $output->column_type[$key]; - if($type == null) { - foreach($output->columns as $cols) { - if($cols['alias'] == $key) { - $type = $output->column_type[$cols['name']]; - } - } - } + if($type == null) { + foreach($output->columns as $cols) { + if($cols['alias'] == $key) { + $type = $output->column_type[$cols['name']]; + } + } + } if($type == "text" || $type == "bigtext") { $blob_data = ibase_blob_info($tmp->{$key}); diff --git a/classes/display/DisplayHandler.class.php b/classes/display/DisplayHandler.class.php index 8b386f4eb..cda47c579 100644 --- a/classes/display/DisplayHandler.class.php +++ b/classes/display/DisplayHandler.class.php @@ -110,6 +110,11 @@ $pattern = '/src=("|\'){1}(\.\/)?(files\/attach|files\/cache|files\/faceOff|files\/member_extra_info|modules|common|widgets|widgetstyle|layouts|addons)\/([^"\']+)\.(jpg|jpeg|png|gif)("|\'){1}/s'; $output = preg_replace($pattern, 'src=$1'.$real_path.'$3/$4.$5$6', $output); + + if(Context::get('vid')) { + $pattern = '/\/'.Context::get('vid').'\?([^=]+)=/is'; + $output = preg_replace($pattern, '/?$1=', $output); + } } // 간혹 background-image에 url(none) 때문에 request가 한번 더 일어나는 경우가 생기는 것을 방지 diff --git a/classes/module/ModuleHandler.class.php b/classes/module/ModuleHandler.class.php index 1c96a7952..575d8ca39 100644 --- a/classes/module/ModuleHandler.class.php +++ b/classes/module/ModuleHandler.class.php @@ -110,13 +110,6 @@ //if($this->module && $module_info->module != $this->module) unset($module_info); } - // 모듈을 여전히(;;) 못 찾고 모듈번호(module_srl)가 있으면 해당 모듈을 구함 - // module_srl로 대상 모듈을 찾는 것을 주석 처리함. - if((!$this->module || $this->module != 'admin') && !$module_info && $this->module_srl) { - $module_info = $oModuleModel->getModuleInfoByModuleSrl($this->module_srl); - //if($this->module && $module_info->module != $this->module) unset($module_info); - } - // 역시 모듈을 못 찾았고 $module이 없다면 기본 모듈을 찾아봄 if(!$module_info && !$this->module) $module_info = $site_module_info; diff --git a/classes/module/ModuleObject.class.php b/classes/module/ModuleObject.class.php index f0014af7d..aa5e15e87 100644 --- a/classes/module/ModuleObject.class.php +++ b/classes/module/ModuleObject.class.php @@ -86,11 +86,16 @@ // module model 객체 생성 $oModuleModel = &getModel('module'); - // 사이트 관리자이면 로그인 정보의 is_admin 에 'Y'로 세팅 - //if($oModuleModel->isSiteAdmin($logged_info)) $logged_info->is_admin = 'Y'; - // XE에서 access, manager (== is_admin) 는 고정된 권한명이며 이와 관련된 권한 설정 - $grant = $oModuleModel->getGrant($module_info, $logged_info, $xml_info); + $module_srl = Context::get('module_srl'); + if(!$module_info->mid && preg_match('/^([0-9]+)$/',$module_srl)) { + $request_module = $oModuleModel->getModuleInfoByModuleSrl($module_srl); + if($request_module->module_srl == $module_srl) { + $grant = $oModuleModel->getGrant($request_module, $logged_info); + } + } else { + $grant = $oModuleModel->getGrant($module_info, $logged_info, $xml_info); + } // 현재 모듈의 access 권한이 없으면 권한 없음 표시 //if(!$grant->access) return $this->stop("msg_not_permitted"); diff --git a/common/js/plugins/ui.calendar/ui.calendar.css b/common/js/plugins/ui.calendar/ui.calendar.css index ff3205e47..d810562aa 100644 --- a/common/js/plugins/ui.calendar/ui.calendar.css +++ b/common/js/plugins/ui.calendar/ui.calendar.css @@ -1,30 +1,31 @@ -/* Calendar */ -.ui-calendar {display:none; padding:25px 15px 15px 15px; position:absolute; border:2px solid #737373; background:#fff; color:#333;} -.ui-calendar .close{ position:absolute; top:10px; right:15px; width:17px; height:17px; border:0; padding:0; background:url(./img/buttonCloseLayerX.gif) no-repeat center center; cursor:pointer;} -.ui-calendar .close span{ position:absolute; width:0; height:0; font-size:0; line-height:0; overflow:hidden; z-index:-1; visibility:hidden;} -.ui-calendar table{ border:0; border-spacing:0; _width:200px;} -.ui-calendar caption{ font-weight:bold; text-align:center; position:relative;} -.ui-calendar caption span{ display:block; position:relative; padding:10px 0 15px 0; *zoom:1;} -.ui-calendar caption .today{ font-size:11px; border:0; padding:0; border-bottom:1px solid; background:none; cursor:pointer;} -.ui-calendar caption .today span{text-decoration:underline;} -.ui-calendar caption .navi{ position:absolute; top:10px; border:0; padding:0; width:17px; height:18px; background-color:transparent; background-image:url(./img/buttonPaginate.gif); background-repeat:no-repeat; cursor:pointer;} -.ui-calendar caption .navi span{ position:absolute; width:0; height:0; overflow:hidden; font-size:0; line-height:0; z-index:-1; visibility:hidden;} -.ui-calendar caption .navi.prev{ left:0; background-position:left top;} -.ui-calendar caption .navi.next{ right:0; background-position:right top;} -.ui-calendar th, -.ui-calendar td{ border:0; text-align:center;} -.ui-calendar th{ color:#666; background:#f2f2f2; padding:3px 8px;} -.ui-calendar td{ font-size:11px; padding:3px 8px;} -.ui-calendar td button{ padding:0; border:0; background:none; cursor:pointer; width:20px; font-size:11px; font-family:Tahoma, Sans-serif;} -.ui-calendar td button.today{ font-weight:bold;} -.ui-calendar td button.book, -.ui-calendar td button.active, -.ui-calendar tr.active button{ background:#ff4747; color:#fff;} -.ui-calendar .sun, -.ui-calendar .sun button{ color:#ff1a1a;} - -.ui-calendar table.month{ border-top:1px solid #f2f2f2; border-left:1px solid #f2f2f2;} -.ui-calendar table.month td{ border-right:1px solid #f2f2f2; border-bottom:1px solid #f2f2f2;} -.ui-calendar table.month td button{ width:50px; color:#bababa;} -.ui-calendar table.month td button.past{ color:#333;} -.ui-calendar table.month td button.active{ color:#fff;} +@charset "utf-8"; +/* Calendar */ +.ui-calendar {display:none; padding:25px 15px 15px 15px; position:absolute; border:2px solid #737373; background:#fff; color:#333; *zoom:1;} +.ui-calendar .close{ position:absolute; _display:block !important; top:10px; right:15px; width:17px; height:17px; border:0; padding:0; background:url(./img/buttonCloseLayerX.gif) no-repeat center center; cursor:pointer; *zoom:1;} +.ui-calendar .close span{ position:absolute; width:0; height:0; font-size:0; line-height:0; overflow:hidden; z-index:-1; visibility:hidden;} +.ui-calendar table{ border:0; border-spacing:0; _width:200px;} +.ui-calendar caption{ font-weight:bold; text-align:center; position:relative;} +.ui-calendar caption span{ display:block; position:relative; padding:10px 0 15px 0; *zoom:1;} +.ui-calendar caption .today{ font-size:11px; border:0; padding:0; border-bottom:1px solid; background:none; cursor:pointer;} +.ui-calendar caption .today span{text-decoration:underline;} +.ui-calendar caption .navi{ position:absolute; top:10px; border:0; padding:0; width:17px; height:18px; background-color:transparent; background-image:url(./img/buttonPaginate.gif); background-repeat:no-repeat; cursor:pointer;} +.ui-calendar caption .navi span{ position:absolute; width:0; height:0; overflow:hidden; font-size:0; line-height:0; z-index:-1; visibility:hidden;} +.ui-calendar caption .navi.prev{ left:0; background-position:left top;} +.ui-calendar caption .navi.next{ right:0; background-position:right top;} +.ui-calendar th, +.ui-calendar td{ border:0; text-align:center;} +.ui-calendar th{ color:#666; background:#f2f2f2; padding:3px 8px;} +.ui-calendar td{ font-size:11px; padding:3px 8px;} +.ui-calendar td button{ padding:0; border:0; background:none; cursor:pointer; width:20px; font-size:11px; font-family:Tahoma, Sans-serif;} +.ui-calendar td button.today{ font-weight:bold;} +.ui-calendar td button.book, +.ui-calendar td button.active, +.ui-calendar tr.active button{ background:#ff4747; color:#fff;} +.ui-calendar .sun, +.ui-calendar .sun button{ color:#ff1a1a;} + +.ui-calendar table.month{ border-top:1px solid #f2f2f2; border-left:1px solid #f2f2f2;} +.ui-calendar table.month td{ border-right:1px solid #f2f2f2; border-bottom:1px solid #f2f2f2;} +.ui-calendar table.month td button{ width:50px; color:#bababa;} +.ui-calendar table.month td button.past{ color:#333;} +.ui-calendar table.month td button.active{ color:#fff;} diff --git a/common/js/xml_handler.js b/common/js/xml_handler.js index e2a36288b..2c6685a3a 100644 --- a/common/js/xml_handler.js +++ b/common/js/xml_handler.js @@ -49,7 +49,7 @@ function xml_response_filter(oXml, callback_func, response_tags, callback_func_a } if(ret_obj["redirect_url"]) { - location.href=ret_obj["redirect_url"]; + location.href=ret_obj["redirect_url"].replace(/&/g,'&'); return null; } diff --git a/common/lang/jp.lang.php b/common/lang/jp.lang.php index d8de2c85f..02a2a8a5b 100644 --- a/common/lang/jp.lang.php +++ b/common/lang/jp.lang.php @@ -45,7 +45,7 @@ $lang->cmd_select = '選択'; $lang->cmd_select_all = 'すべて選択'; $lang->cmd_unselect_all = 'すべて解除'; - $lang->cmd_reverse_all = "選択の反転"; + $lang->cmd_reverse_all = '選択の反転'; $lang->cmd_close_all = 'すべて閉じる'; $lang->cmd_open_all = 'すべて開く'; $lang->cmd_reload = 'リロード'; @@ -53,16 +53,16 @@ $lang->cmd_open = '開く'; $lang->cmd_setup = '設定'; $lang->cmd_addition_setup = '追加設定'; - $lang->cmd_option = 'オプション'; + $lang->cmd_option = 'オプション'; $lang->cmd_apply = '適用'; - $lang->cmd_open_calendar = 'カレンダーを開く'; + $lang->cmd_open_calendar = 'カレンダーを開く'; $lang->cmd_send = '送信'; $lang->cmd_print = '印刷'; $lang->cmd_scrap = 'スクラップ'; $lang->cmd_preview = 'プレビュー'; $lang->cmd_reset = '初期化'; - $lang->cmd_remake_cache = "キャッシュファイル再生成"; - $lang->cmd_publish = "発行"; + $lang->cmd_remake_cache = 'キャッシュファイル再生成'; + $lang->cmd_publish = '発行'; $lang->cmd_layout_setup = 'レイアウト設定'; $lang->cmd_layout_edit = 'レイアウト編集'; $lang->cmd_search_by_ipaddress = 'IPアドレスで検索'; @@ -124,7 +124,7 @@ $lang->file = 'ファイル'; $lang->mid = 'モジュール名'; - $lang->sid = 'Site Name'; + $lang->sid = 'バーチャル(Virtual)サイト名'; $lang->layout = 'レイアウト'; $lang->widget = 'ウィジェット'; $lang->module = 'モジュール'; @@ -132,8 +132,8 @@ $lang->colorset = 'カラーセット'; $lang->extra_vars = '拡張変数'; - $lang->domain = "ドメイン"; - $lang->url = "URL"; + $lang->domain = 'ドメイン'; + $lang->url = 'URL'; $lang->document_url = '書き込みURL'; $lang->trackback_url = 'トラックバックURL'; $lang->blog_name = 'ブログ名'; @@ -284,19 +284,18 @@ $lang->cmd_check_ftp_connect = 'FTP接続をテストする'; $lang->about_ftp_info = " FTP情報は次の場合、利用されます。
- 1. サーバー側のPHPの設定中、「safe_mode=On」になった際、FTP情報を用いてXEが正常に働くようにします。 -
+ 1. サーバー側のPHPの設定中、「safe_mode=On」になった際、FTP情報を用いてXEが正常に働くようにします。
2. FTP経由でXEの自動アップデート等に使われます。
- FTP情報は「files/config/ftp.config.php」の中に保存されます。
+ FTP情報は「files/config/ftp.config.php」の中に保存されます。
また、XEのインストールの後、管理者画面からFTP情報の変更・削除が可能です。(省略可能)
"; - $lang->msg_safe_mode_ftp_needed = "PHPのsafe_modeがOnの場合、FTP情報を登録することで、XEのインストール及び利用が可能になります。"; - $lang->msg_ftp_not_connected = "localhostへのFTP接続エラーが発生しました。FTPポート(port)番号をはじめ、FTPサービスが可能であるかをご確認下さい。"; - $lang->msg_ftp_invalid_auth_info = "ログインが失敗しました。 FTPアクセス情報を再度ご確認下さい。"; - $lang->msg_ftp_mkdir_fail = "FTPを用いたディレクトリ生成に失敗しました。FTPサーバーの設定を再度ご確認下さい。"; - $lang->msg_ftp_chmod_fail = "FTPを用いたディレクトリパーミッション(permission)変更に失敗しました。FTPサーバーの設定を再度ご確認下さい。"; - $lang->msg_ftp_connect_success = "FTP接続に成功しました。"; + $lang->msg_safe_mode_ftp_needed = 'PHPのsafe_modeがOnの場合、FTP情報を登録することで、XEのインストール及び利用が可能になります。'; + $lang->msg_ftp_not_connected = 'localhostへのFTP接続エラーが発生しました。FTPポート(port)番号をはじめ、FTPサービスが可能であるかをご確認下さい。'; + $lang->msg_ftp_invalid_auth_info = 'ログインが失敗しました。 FTPアクセス情報を再度ご確認下さい。'; + $lang->msg_ftp_mkdir_fail = 'FTPを用いたディレクトリ生成に失敗しました。FTPサーバーの設定を再度ご確認下さい。'; + $lang->msg_ftp_chmod_fail = 'FTPを用いたディレクトリパーミッション(permission)変更に失敗しました。FTPサーバーの設定を再度ご確認下さい。'; + $lang->msg_ftp_connect_success = 'FTP接続に成功しました。'; // xml filterで用いられているjavascript用のアラートメッセージ $lang->filter->isnull = '%sを入力して下さい。'; diff --git a/common/lang/ko.lang.php b/common/lang/ko.lang.php index 47b53482a..270927b02 100644 --- a/common/lang/ko.lang.php +++ b/common/lang/ko.lang.php @@ -7,7 +7,7 @@ // 기본적으로 사용되는 action 언어 $lang->cmd_write = '쓰기'; - $lang->cmd_reply = '답글'; + $lang->cmd_reply = '댓글'; $lang->cmd_delete = '삭제'; $lang->cmd_modify = '수정'; $lang->cmd_edit = '편집'; @@ -247,7 +247,7 @@ $lang->failed_voted = '추천하실 수 없습니다'; $lang->failed_blamed = '비추천하실 수 없습니다'; $lang->failed_declared = '신고를 하실 수 없습니다'; - $lang->fail_to_delete_have_children = '답글이 있어서 삭제할 수 없습니다'; + $lang->fail_to_delete_have_children = '댓글이 있어서 삭제할 수 없습니다'; $lang->confirm_submit = '등록하시겠습니까?'; $lang->confirm_logout = '로그아웃하시겠습니까?'; diff --git a/common/tpl/common_layout.html b/common/tpl/common_layout.html index 5174c9bd1..924f4ec23 100644 --- a/common/tpl/common_layout.html +++ b/common/tpl/common_layout.html @@ -41,11 +41,12 @@ - - - - - + + + + + + {@ $ssl_actions = Context::getSSLActions() } diff --git a/config/config.inc.php b/config/config.inc.php index 172d6f65e..4d995e225 100644 --- a/config/config.inc.php +++ b/config/config.inc.php @@ -13,7 +13,7 @@ * @brief XE의 전체 버전 표기 * 이 파일의 수정이 없더라도 공식 릴리즈시에 수정되어 함께 배포되어야 함 **/ - define('__ZBXE_VERSION__', '1.2.3'); + define('__ZBXE_VERSION__', '1.2.4'); /** * @brief zbXE가 설치된 장소의 base path를 구함 diff --git a/index.php b/index.php index d665ba38f..9542647c6 100644 --- a/index.php +++ b/index.php @@ -7,7 +7,7 @@ * Request Argument에서 mid, act로 module 객체를 찾아서 생성하고 \n * 모듈 정보를 세팅함 * - * @mainpage 첫페이지 + * @mainpage XpressEngine * @section intro 소개 * XE 는 오픈 프로젝트로 개발되는 오픈 소스입니다.\n * 자세한 내용은 아래 링크를 참조하세요. @@ -25,6 +25,7 @@ * GNU 일반 공중 사용 허가서는 이 프로그램과 함께 제공됩니다. 만약, 이 문서가 누락되어 있다면 자유 소프트웨어\n * 재단으로 문의하시기 바랍니다. \n * (자유 소프트웨어 재단: Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA) + * **/ /** @@ -45,18 +46,9 @@ $oContext->init(); /** - * @brief SSO 인증 확인이 불필요할때 모듈 동작 + * @brief default_url 이 설정되어 있고 현재 url이 default_url과 다르면 SSO인증을 위한 rediret 시도 후 모듈 동작 **/ if($oContext->checkSSO()) { - /** - * @brief ModuleHandler 객체를 생성/ 실행 - * - * 모듈 핸들러는 Request Argument를 바탕으로 모듈을 찾아서\n - * 객체를 생성하고 기본 정보를 setting 해준다.\n - * ModuleHandler는 이 외에도 설치가 되어 있는지에 대한 체크를\n - * 하여 미설치시 Install 모듈을 실행하도록 한다\n - * 그리고 해당 모듈을 실행후 컨텐츠를 출력한다\n - **/ $oModuleHandler = new ModuleHandler(); if($oModuleHandler->init()) { $oModule = &$oModuleHandler->procModule(); diff --git a/layouts/cafeXE/css/widget.css b/layouts/cafeXE/css/widget.css index a31eac229..f955bc098 100755 --- a/layouts/cafeXE/css/widget.css +++ b/layouts/cafeXE/css/widget.css @@ -174,8 +174,8 @@ dl.widgetDivider dd{ display:none; margin:0;} .widgetTree a strong{ letter-spacing:-1px; cursor:pointer; _cursor /**/:hand;} .widgetTree ul{ position:relative; display:block; padding:3px 0 0 0 !important; zoom:1;} .widgetTree ul li{ list-style:none; position:relative; padding:3px 0 2px 8px; white-space:nowrap;} -.widgetTree ul li a, -.widgetTree ul li span.nav_tree_label{ position:relative; left:16px; _left /**/:0; top:0;} +.widgetTree ul li .nav_tree_label, +.widgetTree ul li .sum{ position:relative; left:16px; _left /**/:0; top:0; font-style:normal;} .widgetTree ul li a.selected {font-weight:bold;} .widgetTree ul li button{ display:inline-block; position:relative; _left /**/:-16px; *top:-2px; width:13px; height:13px; *width:17px; *height:17px; margin:0 -13px 0 0; *margin:0 -17px -1px -2px; text-indent:-10000px; *text-indent:0; *font:0/0 Sans-serif; border:none; cursor:pointer; _cursor /**/:hand;} .widgetTree ul li ul{ display:none; padding:2px 0 0 0 !important; margin:0 0 -2px 6px; background-position:left top;} diff --git a/layouts/cafeXE/layout.html b/layouts/cafeXE/layout.html index 428fa2d2a..4604ea319 100644 --- a/layouts/cafeXE/layout.html +++ b/layouts/cafeXE/layout.html @@ -43,7 +43,9 @@
+ + diff --git a/layouts/xe_blog/layout.html b/layouts/xe_blog/layout.html index 8baadabcb..e2a5fba8f 100644 --- a/layouts/xe_blog/layout.html +++ b/layouts/xe_blog/layout.html @@ -93,7 +93,9 @@
{$lang->cmd_search} + + diff --git a/layouts/xe_official/layout.html b/layouts/xe_official/layout.html index 265f3602a..4b76b6789 100644 --- a/layouts/xe_official/layout.html +++ b/layouts/xe_official/layout.html @@ -46,7 +46,9 @@ + + diff --git a/modules/addon/lang/jp.lang.php b/modules/addon/lang/jp.lang.php index 74e1fbfed..217ce6f27 100644 --- a/modules/addon/lang/jp.lang.php +++ b/modules/addon/lang/jp.lang.php @@ -12,6 +12,6 @@ $lang->addon_license = 'ライセンス'; $lang->addon_history = '変更履歴'; - $lang->about_addon_mid = "アドオンが使われる対象を指定します。
(選択なしの場合、全てのモジュールが利用可能対象)"; - $lang->about_addon = 'アドオンは、HTMLの出力をコントロールするというより、動作を制御する役割をします。お好みのアドオンを「使用/未使用」に設定するだけで、サイトの運営に有用な機能が利用出来ます。'; + $lang->about_addon_mid = 'アドオンが使われる対象を指定します。
(選択なしの場合、全てのモジュールが利用可能対象)'; + $lang->about_addon = 'アドオンは、HTMLの出力をコントロールすると言うより、動作を制御する役割をします。お好みのアドオンを「使用/未使用」に設定するだけで、サイトの運営に有用な機能が利用出来ます。'; ?> diff --git a/modules/admin/admin.admin.view.php b/modules/admin/admin.admin.view.php index 4b48efdfb..501851b9e 100644 --- a/modules/admin/admin.admin.view.php +++ b/modules/admin/admin.admin.view.php @@ -92,6 +92,9 @@ $newest_news_url = sprintf("http://news.xpressengine.com/%s/news.php", Context::getLangType()); $cache_file = sprintf("%sfiles/cache/newest_news.%s.cache.php", _XE_PATH_,Context::getLangType()); if(!file_exists($cache_file) || filemtime($cache_file)+ 60*60 < time()) { + // 네트웍 상태로 데이터를 가져오지 못할 상황을 고려해 일단 filemtime을 변경하여 관리자 페이지 refresh시에 다시 읽ㅇ 오지 않도록 함 + // 뉴스를 보지는 못하지만 관리자 페이지 접속은 이상없도록 함 + FileHandler::writeFile($cache_file,''); FileHandler::getRemoteFile($newest_news_url, $cache_file); } diff --git a/modules/admin/lang/jp.lang.php b/modules/admin/lang/jp.lang.php index 50fe3e8da..387e1ca58 100644 --- a/modules/admin/lang/jp.lang.php +++ b/modules/admin/lang/jp.lang.php @@ -24,59 +24,59 @@ 'system' => 'システム管理', ); - $lang->newest_news = "最新ニュース"; + $lang->newest_news = '最新ニュース'; - $lang->env_setup = "環境設定"; + $lang->env_setup = '環境設定'; $lang->default_url = '基本URL'; - $lang->about_sso_url = "複数のバーチャル(Virtual)サイトを運営する場合、どちらからログインしてもバーチャル(Virtual)サイトの間でログイン情報を維持出来るようにするためには、基本になるサイトでのXEをインストールしたurlを登録して下さい。 (例: http://ドメイン/インストールパス)"; - + $lang->about_default_url = '複数のバーチャル(Virtual)サイトを運営する場合、どちらからログインしてもバーチャル(Virtual)サイトの間でログイン情報を維持出来るようにするためには、基本になるサイトでのXEをインストールしたurlを登録して下さい。 (例: http://ドメイン/インストールパス)'; - $lang->env_information = "環境情報"; - $lang->current_version = "インストールバージョン"; - $lang->current_path = "インストールパス"; - $lang->released_version = "最新バージョン"; + + $lang->env_information = '環境情報'; + $lang->current_version = 'インストールバージョン'; + $lang->current_path = 'インストールパス'; + $lang->released_version = '最新バージョン'; $lang->about_download_link = "インストールされたバージョンより新しいバージョンが配布されています。\n「ダウンロード」リンクをクリックするとダウンロード出来ます。"; - $lang->item_module = "モジュールリスト"; - $lang->item_addon = "アドオンリスト"; - $lang->item_widget = "ウィジェットリスト"; - $lang->item_layout = "レイアウトリスト"; + $lang->item_module = 'モジュールリスト'; + $lang->item_addon = 'アドオンリスト'; + $lang->item_widget = 'ウィジェットリスト'; + $lang->item_layout = 'レイアウトリスト'; - $lang->module_name = "モジュール名"; - $lang->addon_name = "アドオン名"; - $lang->version = "バージョン"; - $lang->author = "制作者"; - $lang->table_count = "テーブル数"; - $lang->installed_path = "インストールパス"; + $lang->module_name = 'モジュール名'; + $lang->addon_name = 'アドオン名'; + $lang->version = 'バージョン'; + $lang->author = '制作者'; + $lang->table_count = 'テーブル数'; + $lang->installed_path = 'インストールパス'; - $lang->cmd_shortcut_management = "メニューの編集"; + $lang->cmd_shortcut_management = 'メニューの編集'; $lang->msg_is_not_administrator = '管理者だけアクセス出来ます'; $lang->msg_manage_module_cannot_delete = 'モジュール、アドオン、ウィジェットのショットカットは削除出来ません。'; $lang->msg_default_act_is_null = 'デフォルトの管理者のアクションが指定されていないため、ショットカットを登録することが出来ません。'; $lang->welcome_to_xe = 'XEの管理者ページです。'; - $lang->about_admin_page = "管理者ページはまだ未完成です。\nクローズベータバージョンの期間に、多くの方々からご意見をいただきながら、必ず必要なコンテンツを埋めていきたいと思います。"; - $lang->about_lang_env = "初めてサイトに訪問したユーザーに対し、上記の選択した言語でサイトを表示させるためには、必ず下記の「保存」ボタンをクリックして適用して下さい。"; + $lang->about_admin_page = "管理者ページはまだ未完成です。\nクローズベータバージョンの期間に、多くの方々からご意見をいただきながら、必ず完成したいと思います。"; + $lang->about_lang_env = '初めてサイトに訪問したユーザーに対し、上記の選択した言語でサイトを表示させるためには、必ず下記の「保存」ボタンをクリックして適用して下さい。'; $lang->xe_license = 'XEのライセンスはGPLです。'; $lang->about_shortcut = 'よく使用するモジュールに登録されたショートカットは削除出来ます。'; - $lang->yesterday = "昨日"; - $lang->today = "今日"; + $lang->yesterday = '昨日'; + $lang->today = '今日'; - $lang->cmd_lang_select = "言語選択"; - $lang->about_cmd_lang_select = "選択された言語だけでサービスを行います。"; - $lang->about_recompile_cache = "要らないかごみのキャッシューファイルを整理します。"; - $lang->use_ssl = "SSL環境設定"; + $lang->cmd_lang_select = '言語選択'; + $lang->about_cmd_lang_select = '選択された言語だけでサービスを行います。'; + $lang->about_recompile_cache = '要らないかごみのキャッシューファイルを整理します。'; + $lang->use_ssl = 'SSL環境設定'; $lang->ssl_options = array( - 'none' => "使わない", - 'optional' => "部分的に使う", - 'always' => "常に使う" + 'none' => '使わない', + 'optional' => '部分的に使う', + 'always' => '常に使う' ); - $lang->about_use_ssl = "「部分的に使う場合」は「会員登録/会員情報変更」など特定のactionでSSLを利用する場合、「常に使う」は全てのサービスがSSLを使う場合に選択します。"; - $lang->server_ports = "サーバーポート指定"; - $lang->about_server_ports = "一般的に使われているHTTPの80、HTTPSの443以外の他のポートを使うために、ポートを指定して下さい。"; + $lang->about_use_ssl = '「部分的に使う場合」は「会員登録/会員情報変更」など特定のactionでSSLを利用する場合、「常に使う」は全てのサービスがSSLを使う場合に選択します。'; + $lang->server_ports = 'サーバーポート指定'; + $lang->about_server_ports = '一般的に使われているHTTPの80、HTTPSの443以外の他のポートを使うために、ポートを指定して下さい。'; $lang->use_db_session = 'DBで認証セッション管理'; $lang->about_db_session = '認証の時に使われるPHPセッションをDBで使う機能です。
ウェブサーバーの負荷が低いサイトではこの機能をオフにすることでむしろサイトのレスポンスが向上されることもあります。
また、この機能をオンにすると、「現在ログイン中の会員」の機能が不可になります。'; ?> diff --git a/modules/admin/tpl/css/admin.css b/modules/admin/tpl/css/admin.css index 7f6dec799..1c3673e02 100644 --- a/modules/admin/tpl/css/admin.css +++ b/modules/admin/tpl/css/admin.css @@ -130,7 +130,7 @@ .boxModelControler .buttonArea{ padding:15px 0 0 0; text-align:center;} #popup_content { border:2px solid #777; margin:0; font-size:12px; background:#fff; position:relative;} -#popup_content .xButton { position:absolute; top:9px; right:18px; width:15px; height:14px; background-color:transparent; background:url(../img/buttonClose.gif) no-repeat; border:0; cursor:pointer; overflow:hidden; } +#popup_content .xButton { position:absolute; top:9px; right:18px; width:15px; height:14px; padding:0; background-color:transparent; background:url(../img/buttonClose.gif) no-repeat; border:0; cursor:pointer; overflow:hidden; } #popup_content .xButton span { position:relative; z-index:-1; visibility:hidden; } #popup_content * { font-size:12px; } #popHeadder h4.xeAdmin, #popHeadder h1.xeAdmin, #popHeadder h3.xeAdmin { font-size:14px !important; font-family:Dotum !important; background:#f4f4f4 !important; padding:8px 30px 8px 15px !important; letter-spacing:-1px !important; border:none !important; margin:0 !important;} diff --git a/modules/admin/tpl/index.html b/modules/admin/tpl/index.html index 847666f3d..23739e662 100644 --- a/modules/admin/tpl/index.html +++ b/modules/admin/tpl/index.html @@ -2,6 +2,7 @@ + @@ -201,6 +202,19 @@ +

{$lang->cmd_remake_cache}

+ + + + + + + +
+ + + +

{$lang->newest_news}

diff --git a/modules/board/board.class.php b/modules/board/board.class.php index d58d83cb1..b6d953350 100644 --- a/modules/board/board.class.php +++ b/modules/board/board.class.php @@ -23,27 +23,22 @@ function moduleInstall() { // action forward에 등록 (관리자 모드에서 사용하기 위함) $oModuleController = &getController('module'); + $oModuleModel = &getModel('module'); // 2007. 10. 17 아이디 클릭시 나타나는 팝업메뉴에 작성글 보기 기능 추가 $oModuleController->insertTrigger('member.getMemberMenu', 'board', 'controller', 'triggerMemberMenu', 'after'); // 기본 게시판 생성 - $output = executeQuery('module.getDefaultMidInfo'); - if($output->data) return new Object(); - - // 기본 모듈을 찾음 - $oModuleModel = &getModel('module'); - $site_args->site_srl = 0; - $mid_list = $oModuleModel->getMidList($site_args); - if(!count($mid_list)) { + $args->site_srl = 0; + $output = executeQuery('module.getSite', $args); + if(!$output->data->index_module_srl) { $args->mid = 'board'; $args->module = 'board'; - $args->browser_title = 'test module'; + $args->browser_title = 'XpressEngine'; $args->skin = 'xe_default'; $args->site_srl = 0; $output = $oModuleController->insertModule($args); $module_srl = $output->get('module_srl'); - $site_args->site_srl = 0; $site_args->index_module_srl = $module_srl; $oModuleController = &getController('module'); diff --git a/modules/board/board.model.php b/modules/board/board.model.php index 70cfd2981..9e465fb9c 100644 --- a/modules/board/board.model.php +++ b/modules/board/board.model.php @@ -38,7 +38,7 @@ **/ function getDefaultListConfig($module_srl) { // 가상번호, 제목, 등록일, 수정일, 닉네임, 아이디, 이름, 조회수, 추천수 추가 - $virtual_vars = array( 'no', 'title', 'regdate', 'last_update', 'nick_name', 'user_id', 'user_name', 'readed_count', 'voted_count' ); + $virtual_vars = array( 'no', 'title', 'regdate', 'last_update', 'last_post', 'nick_name', 'user_id', 'user_name', 'readed_count', 'voted_count','thumbnail','summary'); foreach($virtual_vars as $key) { $extra_vars[$key] = new ExtraItem($module_srl, -1, Context::getLang($key), $key, 'N', 'N', 'N', null); } diff --git a/modules/board/lang/en.lang.php b/modules/board/lang/en.lang.php index 753b9c7c0..43ea3aa64 100644 --- a/modules/board/lang/en.lang.php +++ b/modules/board/lang/en.lang.php @@ -13,6 +13,9 @@ $lang->cmd_manage_menu = 'Manage Menus'; $lang->list_target_item = 'Target Item'; $lang->list_display_item = 'Display Item'; + $lang->summary = 'Summary'; + $lang->thumbnail = 'Thumbnail'; + $lang->last_post = 'Last post'; // Item $lang->search_result = 'Search Result'; diff --git a/modules/board/lang/es.lang.php b/modules/board/lang/es.lang.php index 14d25db1b..372d2d336 100644 --- a/modules/board/lang/es.lang.php +++ b/modules/board/lang/es.lang.php @@ -12,6 +12,9 @@ $lang->cmd_manage_menu = 'Manejo del menú'; $lang->list_target_item = 'Target Item'; $lang->list_display_item = 'Display Item'; + $lang->summary = '요약'; + $lang->thumbnail = '썸네일'; + $lang->last_post = '최종 글'; $lang->cmd_remake_cache = 'Rehacer archivo caché'; $lang->cmd_layout_setup = 'Configuración del diseño'; $lang->cmd_layout_edit = 'Editar el diseño'; diff --git a/modules/board/lang/fr.lang.php b/modules/board/lang/fr.lang.php index 2546ed983..23269ceb1 100644 --- a/modules/board/lang/fr.lang.php +++ b/modules/board/lang/fr.lang.php @@ -13,6 +13,9 @@ $lang->cmd_manage_menu = 'Administration de Menu'; $lang->list_target_item = 'Target Item'; $lang->list_display_item = 'Display Item'; + $lang->summary = '요약'; + $lang->thumbnail = '썸네일'; + $lang->last_post = '최종 글'; // Item $lang->search_result = 'Résultat de la Recherche'; $lang->consultation = 'Consultation'; diff --git a/modules/board/lang/jp.lang.php b/modules/board/lang/jp.lang.php index 30878581f..aeca8dbe5 100644 --- a/modules/board/lang/jp.lang.php +++ b/modules/board/lang/jp.lang.php @@ -11,6 +11,9 @@ $lang->cmd_manage_menu = 'メニュー管理'; $lang->list_target_item = 'ターゲットアイテム'; $lang->list_display_item = '表示アイテム'; + $lang->summary = '요약'; + $lang->thumbnail = '썸네일'; + $lang->last_post = '최종 글'; // 項目 @@ -29,7 +32,7 @@ // その他 $lang->about_layout_setup = 'ブログのレイアウトのコードを直接修正します。ウィジェットコードを好きなところに入力、又は管理して下さい。'; $lang->about_board_category = 'ブログのカテゴリを作成します。
ブログのカテゴリが誤作動する場合、「キャッシュファイルの再生性」を手動で行うことで解決出来ます。'; - $lang->about_except_notice = "リストの上段に常に表示されるお知らせの書き込みを一般リストからお知らせの書き込みが表示されないようにします。"; + $lang->about_except_notice = 'リストの上段に常に表示されるお知らせの書き込みを一般リストからお知らせの書き込みが表示されないようにします。'; $lang->about_use_anonymous = '匿名掲示板として活用出来ます。スキン設定で登録者の情報を表示しないに設定をお勧めします。'; $lang->about_board = '掲示板の生成、および管理するモジュールです。'; $lang->about_consultation = "相談機能とは、管理権限のない会員に本人の書き込みだけを表示する機能です。\n但し、相談機能を使用する際は、非会員の書き込みは自動的に禁止されます。"; diff --git a/modules/board/lang/ko.lang.php b/modules/board/lang/ko.lang.php index 0a507dfbd..c5dfaee60 100644 --- a/modules/board/lang/ko.lang.php +++ b/modules/board/lang/ko.lang.php @@ -11,7 +11,9 @@ $lang->cmd_manage_menu = '메뉴관리'; $lang->list_target_item = '대상 항목'; $lang->list_display_item = '표시 항목'; - + $lang->summary = '요약'; + $lang->thumbnail = '썸네일'; + $lang->last_post = '최종 글'; // 항목 $lang->search_result = '검색결과'; diff --git a/modules/board/lang/ru.lang.php b/modules/board/lang/ru.lang.php index 1e4f0a18b..dbf38066c 100644 --- a/modules/board/lang/ru.lang.php +++ b/modules/board/lang/ru.lang.php @@ -13,6 +13,9 @@ $lang->cmd_manage_menu = 'Управление меню'; $lang->list_target_item = 'Target Item'; $lang->list_display_item = 'Display Item'; + $lang->summary = '요약'; + $lang->thumbnail = '썸네일'; + $lang->last_post = '최종 글'; $lang->cmd_make_child = 'Добавить дочернюю категорию'; $lang->cmd_enable_move_category = "Изменить позицию категории (Перетащите верхнее меню после выделения)"; $lang->cmd_remake_cache = 'Перепостроить файл кеша'; diff --git a/modules/board/lang/zh-CN.lang.php b/modules/board/lang/zh-CN.lang.php index 3b0ad8f5d..6302c87cd 100644 --- a/modules/board/lang/zh-CN.lang.php +++ b/modules/board/lang/zh-CN.lang.php @@ -11,6 +11,9 @@ $lang->cmd_manage_menu = '菜单管理'; $lang->list_target_item = '备选项'; $lang->list_display_item = '显示项'; + $lang->summary = '요약'; + $lang->thumbnail = '썸네일'; + $lang->last_post = '최종 글'; // 项目 diff --git a/modules/board/lang/zh-TW.lang.php b/modules/board/lang/zh-TW.lang.php index 0aba9c623..cc65478d8 100644 --- a/modules/board/lang/zh-TW.lang.php +++ b/modules/board/lang/zh-TW.lang.php @@ -11,6 +11,9 @@ $lang->cmd_manage_menu = '選單管理'; $lang->list_target_item = '目標項目'; $lang->list_display_item = '顯示項目'; + $lang->summary = '요약'; + $lang->thumbnail = '썸네일'; + $lang->last_post = '최종 글'; // 項目 diff --git a/modules/board/skins/xe_board/css/common.css b/modules/board/skins/xe_board/css/common.css index fd55a49b7..20c2e974b 100644 --- a/modules/board/skins/xe_board/css/common.css +++ b/modules/board/skins/xe_board/css/common.css @@ -123,7 +123,7 @@ Jeong, Chan Myeong 070601~070630 .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 p { display:inline; } .replyBox .author { float:left; padding:0 .3em 0 0; 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;} diff --git a/modules/board/skins/xe_board/list.html b/modules/board/skins/xe_board/list.html index f27fac0d5..4a763accf 100644 --- a/modules/board/skins/xe_board/list.html +++ b/modules/board/skins/xe_board/list.html @@ -56,6 +56,9 @@
+ + + diff --git a/modules/board/skins/xe_board/view_document.html b/modules/board/skins/xe_board/view_document.html index 5168f829f..a716dd7de 100644 --- a/modules/board/skins/xe_board/view_document.html +++ b/modules/board/skins/xe_board/view_document.html @@ -142,8 +142,8 @@
- - {$lang->cmd_list} + + {$lang->cmd_list}{$lang->cmd_view_all} {$lang->cmd_modify} diff --git a/modules/board/skins/xe_default/list.html b/modules/board/skins/xe_default/list.html index dcc974a5f..4d9afd3aa 100644 --- a/modules/board/skins/xe_default/list.html +++ b/modules/board/skins/xe_default/list.html @@ -51,6 +51,9 @@
Board Search + + + diff --git a/modules/board/skins/xe_default/view_document.html b/modules/board/skins/xe_default/view_document.html index 72222695b..8d9a0c504 100644 --- a/modules/board/skins/xe_default/view_document.html +++ b/modules/board/skins/xe_default/view_document.html @@ -40,7 +40,7 @@

"{$lang->msg_is_secret}"

-
:
+
:
@@ -124,9 +124,9 @@
- + diff --git a/modules/board/skins/xe_guestbook/input_password_form.html b/modules/board/skins/xe_guestbook/input_password_form.html index 9b661831c..3277509d3 100644 --- a/modules/board/skins/xe_guestbook/input_password_form.html +++ b/modules/board/skins/xe_guestbook/input_password_form.html @@ -1,6 +1,5 @@ -sadf
diff --git a/modules/board/tpl/board_insert.html b/modules/board/tpl/board_insert.html index 5acb5f0e6..d68d3a431 100644 --- a/modules/board/tpl/board_insert.html +++ b/modules/board/tpl/board_insert.html @@ -175,6 +175,7 @@ + diff --git a/modules/board/tpl/index.html b/modules/board/tpl/index.html index cf0feb5df..977417d5d 100644 --- a/modules/board/tpl/index.html +++ b/modules/board/tpl/index.html @@ -18,6 +18,7 @@ - diff --git a/modules/counter/lang/jp.lang.php b/modules/counter/lang/jp.lang.php index 7ab28400c..d722aff6d 100644 --- a/modules/counter/lang/jp.lang.php +++ b/modules/counter/lang/jp.lang.php @@ -5,7 +5,7 @@ * @brief 日本語言語パッケージ(基本的な内容のみ) **/ - $lang->counter = "カウンター"; + $lang->counter = 'カウンター'; $lang->cmd_select_date = '日付選択'; $lang->cmd_select_counter_type = array( 'hour' => '時間帯別', diff --git a/modules/document/document.controller.php b/modules/document/document.controller.php index b84bbf438..eb503a0b5 100644 --- a/modules/document/document.controller.php +++ b/modules/document/document.controller.php @@ -30,7 +30,7 @@ $args->alias_srl = getNextSequence(); $args->module_srl = $module_srl; $args->document_srl = $document_srl; - $args->alias_title = $alias_title; + $args->alias_title = urldecode($alias_title); $query = "document.insertAlias"; $output = executeQuery($query, $args); return $output; @@ -218,7 +218,7 @@ // trigger 호출 (after) if($output->toBool()) { - $trigger_output = ModuleHandler::triggerCall('document.insertDocument', 'after', $obj); + $trigger_output = ModuleHandler::triggerCall('document.insertDocument', 'after', $obj); if(!$trigger_output->toBool()) { $oDB->rollback(); return $trigger_output; @@ -501,6 +501,9 @@ return $output; } + // update category + if($oDocument->get('category_srl')) $this->updateCategoryCount($oDocument->get('module_srl'),$oDocument->get('category_srl')); + // commit $oDB->commit(); @@ -546,7 +549,7 @@ **/ function insertDocumentExtraKey($module_srl, $var_idx, $var_name, $var_type, $var_is_required = 'N', $var_search = 'N', $var_default = '', $var_desc = '', $eid) { if(!$module_srl || !$var_idx || !$var_name || !$var_type || !$eid) return new Object(-1,'msg_invalid_request'); - + $obj->module_srl = $module_srl; $obj->var_idx = $var_idx; $obj->var_name = $var_name; @@ -555,14 +558,14 @@ $obj->var_search = $var_search=='Y'?'Y':'N'; $obj->var_default = $var_default; $obj->var_desc = $var_desc; - $obj->eid = $eid; + $obj->eid = $eid; $output = executeQuery('document.getDocumentExtraKeys', $obj); if(!$output->data) return executeQuery('document.insertDocumentExtraKey', $obj); $output = executeQuery('document.updateDocumentExtraKey', $obj); - - // extra_vars에서 확장 변수 eid를 일괄 업데이트 - $output = executeQuery('document.updateDocumentExtraVar', $obj); + + // extra_vars에서 확장 변수 eid를 일괄 업데이트 + $output = executeQuery('document.updateDocumentExtraVar', $obj); return $output; } @@ -586,13 +589,13 @@ function insertDocumentExtraVar($module_srl, $document_srl, $var_idx, $value, $eid = null, $lang_code = '') { if(!$module_srl || !$document_srl || !$var_idx || !isset($value)) return new Object(-1,'msg_invalid_request'); if(!$lang_code) $lang_code = Context::getLangType(); - + $obj->module_srl = $module_srl; $obj->document_srl = $document_srl; $obj->var_idx = $var_idx; $obj->value = $value; $obj->lang_code = $lang_code; - $obj->eid = $eid; + $obj->eid = $eid; executeQuery('document.insertDocumentExtraVar', $obj); } @@ -609,7 +612,7 @@ $output = executeQuery('document.deleteDocumentExtraVars', $obj); return $output; } - + /** * @brief 해당 document의 추천수 증가 @@ -824,7 +827,7 @@ function updateCategoryCount($module_srl, $category_srl, $document_count = 0) { // document model 객체 생성 $oDocumentModel = &getModel('document'); - if(!$document_count) $document_count = $oDocumentModel->getCategoryDocumentCount($category_srl); + if(!$document_count) $document_count = $oDocumentModel->getCategoryDocumentCount($module_srl,$category_srl); $args->category_srl = $category_srl; $args->document_count = $document_count; @@ -998,7 +1001,13 @@ **/ function procDocumentInsertCategory($args = null) { // 입력할 변수 정리 - if(!$args) $args = Context::gets('module_srl','category_srl','parent_srl','title','expand','group_srls','color'); + if(!$args) $args = Context::gets('module_srl','category_srl','parent_srl','title','expand','group_srls','color','mid'); + + if(!$args->module_srl && $args->mid){ + $mid = $args->mid; + unset($args->mid); + $args->module_srl = $this->module_srl; + } // 권한 체크 $oModuleModel = &getModel('module'); @@ -1587,6 +1596,5 @@ $this->setError(-1); $this->setMessage('success_updated'); } - } ?> diff --git a/modules/document/document.item.php b/modules/document/document.item.php index d0aa3c783..b2ba0076c 100644 --- a/modules/document/document.item.php +++ b/modules/document/document.item.php @@ -301,9 +301,10 @@ * 에디터 코드가 변환된 내용 반환 **/ function getTransContent($add_popup_menu = true, $add_content_info = true, $resource_realpath = false, $add_xe_content_class = true) { - $oContext = &Context::getInstance(); + $oEditorController = &getController('editor'); $content = $this->getContent($add_popup_menu, $add_content_info, $resource_realpath, $add_xe_content_class); + $content = $oEditorController->transComponent($content); return $content; } @@ -311,8 +312,8 @@ function getSummary($str_size = 50, $tail = '...') { $content = $this->getContent(false,false); - // 줄바꿈이 있을 때, 공백문자 삽입 - $content = preg_replace('!([\s]*)+!is', ' ', $content); + // 줄바꿈이 있을 때, 공백문자 삽입 + $content = preg_replace('!([\s]*)+!is', ' ', $content); //

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

', '
', ''), ' ', $content); @@ -323,8 +324,8 @@ // < , > , " 를 치환 $content = str_replace(array('<','>','"',' '), array('<','>','"',' '), $content); - // 연속된 공백문자 삭제 - $content = preg_replace('/ ( +)/is', ' ', $content); + // 연속된 공백문자 삭제 + $content = preg_replace('/ ( +)/is', ' ', $content); // 문자열을 자름 $content = trim(cut_str($content, $str_size, $tail)); @@ -376,7 +377,13 @@ } function getPermanentUrl() { - return getUrl('','document_srl',$this->document_srl); + $url = getUrl('','document_srl',$this->get('document_srl')); + if(substr($url,0,1)=='/') { + if($_SERVER['HTTPS']=='on') $http_url = 'https://'; + else $http_url = 'http://'; + $url = $http_url.$_SERVER['HTTP_HOST'].$url; + } + return $url; } function getTrackbackUrl() { @@ -465,9 +472,19 @@ if(!$output->toBool() || !count($output->data)) return; // 구해온 목록을 commentItem 객체로 만듬 + // 계층구조에 따라 부모글에 관리권한이 있으면 자식글에는 보기 권한을 줌 + $accessible = array(); foreach($output->data as $key => $val) { $oCommentItem = new commentItem(); $oCommentItem->setAttribute($val); + + // 권한이 있는 글에 대해 임시로 권한이 있음을 설정 + if($oCommentItem->isGranted()) $accessible[$val->comment_srl] = true; + + // 현재 댓글이 비밀글이고 부모글이 있는 답글이고 부모글에 대해 관리 권한이 있으면 보기 가능하도록 수정 + if($val->parent_srl>0 && $val->is_secret == 'Y' && !$oCommentItem->isAccessible() && $accessible[$val->parent_srl]===true) { + $oCommentItem->setAccessible(); + } $comment_list[$val->comment_srl] = $oCommentItem; } @@ -557,7 +574,7 @@ $cnt = count($matches); for($i=0;$i<$cnt;$i++) { $target_src = trim($matches[$i][2]); - if(!preg_match("/\.(jpg|png|jpeg|gif|bmp)$/i",$target_src)) continue; + if(!preg_match("/\.(jpg|png|jpeg|gif|bmp)$/i",$target_src)) continue; if(preg_match('/\/(common|modules|widgets|addons|layouts)\//i', $target_src)) continue; else { if(!preg_match('/^(http|https):\/\//i',$target_src)) $target_src = Context::getRequestUri().$target_src; diff --git a/modules/document/document.model.php b/modules/document/document.model.php index 124cb7564..45d489ea6 100644 --- a/modules/document/document.model.php +++ b/modules/document/document.model.php @@ -703,7 +703,8 @@ /** * @brief 카테고리에 속한 문서의 갯수를 구함 **/ - function getCategoryDocumentCount($category_srl) { + function getCategoryDocumentCount($module_srl, $category_srl) { + $args->module_srl = $module_srl; $args->category_srl = $category_srl; $output = executeQuery('document.getCategoryDocumentCount', $args); return (int)$output->data->count; @@ -903,8 +904,10 @@ function getDocumentSrlByAlias($mid, $alias) { if(!$mid || !$alias) return null; + $site_module_info = Context::get('site_module_info'); $args->mid = $mid; $args->alias_title = $alias; + $args->site_srl = $site_module_info->site_srl; $output = executeQuery('document.getDocumentSrlByAlias', $args); if(!$output->data) return null; else return $output->data->document_srl; diff --git a/modules/document/document.view.php b/modules/document/document.view.php index 3ed31e505..49a25caac 100644 --- a/modules/document/document.view.php +++ b/modules/document/document.view.php @@ -97,7 +97,10 @@ } $oModuleModel = &getModel('module'); - $document_config = $oModuleModel->getModulePartConfig('document', $module_srl); + if($current_module_srl) + { + $document_config = $oModuleModel->getModulePartConfig('document', $current_module_srl); + } if(!isset($document_config->use_history)) $document_config->use_history = 'N'; Context::set('document_config', $document_config); diff --git a/modules/document/lang/jp.lang.php b/modules/document/lang/jp.lang.php index 2b1292ef1..2f82f60bf 100644 --- a/modules/document/lang/jp.lang.php +++ b/modules/document/lang/jp.lang.php @@ -21,7 +21,7 @@ $lang->category_group_srls = 'グループ制限'; $lang->cmd_make_child = '下位カテゴリ追加'; - $lang->cmd_enable_move_category = "カテゴリ位置変更(選択後上のメニューをドラッグして下さい)"; + $lang->cmd_enable_move_category = 'カテゴリ位置変更(選択後上のメニューをドラッグして下さい)'; $lang->about_category_title = 'カテゴリ名を入力して下さい。'; $lang->about_expand = 'チェックすると常に展開された状態になります。'; @@ -41,7 +41,7 @@ $lang->msg_is_secret = '非公開設定の書き込みです。'; $lang->msg_checked_document_is_deleted = '%d個の書き込みが削除されました。'; - $lang->move_target_module = "移動対象モジュール"; + $lang->move_target_module = '移動対象モジュール'; // 管理者ページで検索する内容 $lang->search_target_list = array( @@ -66,14 +66,14 @@ 'ipaddress' => 'IPアドレス', ); - $lang->alias = "アリアス(Alias)"; - $lang->history = "履歴"; - $lang->about_use_history = "履歴機能を使用するかを設定します。履歴機能を使用すると文書修正のバージョンを管理し、過去のバージョンから復元することも可能です。"; - $lang->trace_only = "記録だけ残す"; + $lang->alias = 'アリアス(Alias)'; + $lang->history = '履歴'; + $lang->about_use_history = '履歴機能を使用するかを設定します。履歴機能を使用すると文書修正のバージョンを管理し、過去のバージョンから復元することも可能です。'; + $lang->trace_only = '記録だけ残す'; $lang->cmd_trash = "ごみ箱"; - $lang->cmd_restore = "復元"; - $lang->cmd_restore_all = "すべて復元"; + $lang->cmd_restore = "差し戻し"; + $lang->cmd_restore_all = "すべて差し戻し"; $lang->in_trash = "ごみ箱"; $lang->trash_nick_name = "削除者のニックネーム"; diff --git a/modules/document/queries/getCategoryDocumentCount.xml b/modules/document/queries/getCategoryDocumentCount.xml index 877a2d809..7c7a8e921 100644 --- a/modules/document/queries/getCategoryDocumentCount.xml +++ b/modules/document/queries/getCategoryDocumentCount.xml @@ -7,5 +7,6 @@ + diff --git a/modules/document/queries/getDocumentSrlByAlias.xml b/modules/document/queries/getDocumentSrlByAlias.xml index baac51464..17eadc534 100644 --- a/modules/document/queries/getDocumentSrlByAlias.xml +++ b/modules/document/queries/getDocumentSrlByAlias.xml @@ -7,7 +7,8 @@ - + + diff --git a/modules/document/queries/getDocumentsExtraVars.xml b/modules/document/queries/getDocumentsExtraVars.xml index 48e3fc1ce..f50fc7c12 100644 --- a/modules/document/queries/getDocumentsExtraVars.xml +++ b/modules/document/queries/getDocumentsExtraVars.xml @@ -26,4 +26,4 @@ - \ No newline at end of file + diff --git a/modules/document/queries/updateDocumentOrder.xml b/modules/document/queries/updateDocumentOrder.xml new file mode 100644 index 000000000..0dd50b2df --- /dev/null +++ b/modules/document/queries/updateDocumentOrder.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/modules/editor/components/code_highlighter/lang/jp.lang.php b/modules/editor/components/code_highlighter/lang/jp.lang.php index 324694df5..bc3cff24d 100644 --- a/modules/editor/components/code_highlighter/lang/jp.lang.php +++ b/modules/editor/components/code_highlighter/lang/jp.lang.php @@ -9,6 +9,6 @@ $lang->used_collapse = '折りたたみ機能を使う'; $lang->hidden_linenumber = '行番号を隠す'; $lang->hidden_controls = 'ツールバーを隠す'; -$lang->file_path = 'ファイルパス'; +$lang->file_path = 'ファイルのパス'; $lang->description = '説明'; $lang->first_line = '開始する行番号'; diff --git a/modules/editor/components/emoticon/emoticon.class.php b/modules/editor/components/emoticon/emoticon.class.php index 6e6daf99c..b0f252dd8 100644 --- a/modules/editor/components/emoticon/emoticon.class.php +++ b/modules/editor/components/emoticon/emoticon.class.php @@ -2,10 +2,10 @@ /** * @class emoticon * @author zero (zero@nzeo.com) - * @brief 이모티콘 이미지 연결 컴포넌트 + * @brief 이모티콘 이미지 연결 컴포넌트 **/ - class emoticon extends EditorHandler { + class emoticon extends EditorHandler { // editor_sequence 는 에디터에서 필수로 달고 다녀야 함.... var $editor_sequence = 0; @@ -33,10 +33,10 @@ $this->add('emoticons', implode("\n",$list)); } - /** - * @brief 재귀적으로 이모티콘이 될 법한 파일들을 하위 디렉토리까지 전부 검색한다. 8,000개까지는 테스트 해봤는데 스택오버프로우를 일으킬지 어떨지는 잘 모르겠음.(2007.9.6, 베니) - **/ - function getEmoticons($path) { + /** + * @brief 재귀적으로 이모티콘이 될 법한 파일들을 하위 디렉토리까지 전부 검색한다. 8,000개까지는 테스트 해봤는데 스택오버프로우를 일으킬지 어떨지는 잘 모르겠음.(2007.9.6, 베니) + **/ + function getEmoticons($path) { $emoticon_path = sprintf("%s/%s", $this->emoticon_path, $path); $output = array(); @@ -48,14 +48,20 @@ $oDir->close(); if(count($output)) asort($output); return $output; - } - + } + /** * @brief popup window요청시 popup window에 출력할 내용을 추가하면 된다 **/ function getPopupContent() { // 이모티콘 디렉토리 목록을 가져옴 - $emoticon_list = FileHandler::readDir($this->emoticon_path); + $emoticon_dirs = FileHandler::readDir($this->emoticon_path); + $emoticon_list = array(); + if($emoticon_dirs) { + foreach($emoticon_dirs as $emoticon) { + if(preg_match("/^([a-z0-9\_]+)$/i", $emoticon)) $emoticon_list[] = $emoticon; + } + } Context::set('emoticon_list', $emoticon_list); // 첫번째 이모티콘 디렉토리의 이미지 파일을 구함 @@ -70,10 +76,10 @@ return $oTemplate->compile($tpl_path, $tpl_file); } - /** - * @brief 이모티콘의 경로 문제 해결을 하기 위해 추가하였다. (2007.9.6 베니) - **/ - function transHTML($xml_obj) { + /** + * @brief 이모티콘의 경로 문제 해결을 하기 위해 추가하였다. (2007.9.6 베니) + **/ + function transHTML($xml_obj) { $src = $xml_obj->attrs->src; $alt = $xml_obj->attrs->alt; diff --git a/modules/editor/components/image_gallery/lang/jp.lang.php b/modules/editor/components/image_gallery/lang/jp.lang.php index d07ae739c..1405c6c9e 100644 --- a/modules/editor/components/image_gallery/lang/jp.lang.php +++ b/modules/editor/components/image_gallery/lang/jp.lang.php @@ -21,7 +21,7 @@ $lang->gallery_bg_color = "背景色"; $lang->about_image_list = "イメージギャラリーに追加するファイルを選択して下さい。選択した後、ドラッグまたは「Shift+クリック(範囲選択)、Ctrl+クリック(個別選択)」が出来ます。"; - $lang->cmd_gallery_prev = "前のイメージ表示"; + $lang->cmd_gallery_prev = "前のイメージ表示"; $lang->cmd_gallery_next = "次のイメージ表示"; $lang->cmd_gallery_thumbnail = "サムネール表示"; ?> diff --git a/modules/editor/components/image_gallery/tpl/list_gallery.js b/modules/editor/components/image_gallery/tpl/list_gallery.js index b2ca84b53..5b369d75d 100644 --- a/modules/editor/components/image_gallery/tpl/list_gallery.js +++ b/modules/editor/components/image_gallery/tpl/list_gallery.js @@ -72,11 +72,8 @@ function start_list_gallery() { obj.image.style.marginBottom = "10px"; obj.image.style.display = "block"; - // resize_scale이 1이 아니면, 즉 리사이즈 되었다면 해당 이미지 클릭시 원본을 새창으로 띄워줌 - if(resize_scale!=1 && typeof(showOriginalImage)=='function') { - obj.image.style.cursor = 'pointer'; - xAddEventListener(obj.image, 'click', showOriginalImage); - } + // 리사이즈 되었다면 resize_image 애드온의 slideshow() 기능 사용 + if(resize_scale != 1) obj.image.rel = 'xe_gallery'; zone.appendChild(obj.image); } diff --git a/modules/editor/components/image_link/image_link.class.php b/modules/editor/components/image_link/image_link.class.php index 55286a5c2..6ab1a578b 100644 --- a/modules/editor/components/image_link/image_link.class.php +++ b/modules/editor/components/image_link/image_link.class.php @@ -58,6 +58,14 @@ $src = str_replace(array('&','"'), array('&','&qout;'), $src); $src = str_replace('&amp;', '&', $src); + // 이미지 주소를 request uri가 포함된 주소로 변환 (rss출력, 등등을 위함) + $temp_src = explode('/', $src); + if($temp_src[0]=='.') $src = Context::getRequestUri().substr($src, 2); + elseif($temp_src[0]=='' && $src) { + if($_SERVER['HTTPS']=='on') $http_src = 'https://'; + else $http_src = 'http://'; + $src = $http_src.$_SERVER['HTTP_HOST'].$src; + } if(!$alt) $alt = $src; $attr_output = array(); diff --git a/modules/editor/components/image_link/lang/jp.lang.php b/modules/editor/components/image_link/lang/jp.lang.php index 8fb6f5739..5cba9384a 100644 --- a/modules/editor/components/image_link/lang/jp.lang.php +++ b/modules/editor/components/image_link/lang/jp.lang.php @@ -5,19 +5,19 @@ * @brief ウィジウィグエディター(editor)モジュール > イメージリンク(image_link)コンポネント言語パッケージ **/ - $lang->image_url = "イメージパス"; - $lang->image_alt = "説明(Alt)入力"; - $lang->image_scale = "イメージサイズ"; - $lang->image_align = "アライン位置"; - $lang->image_align_normal = "一段落"; - $lang->image_align_left = "左揃え"; - $lang->image_align_middle = "中央揃え"; - $lang->image_align_right = "右揃え"; - $lang->image_border = "ボーダー"; + $lang->image_url = 'イメージパス'; + $lang->image_alt = '説明(Alt)入力'; + $lang->image_scale = 'イメージサイズ'; + $lang->image_align = 'アライン位置'; + $lang->image_align_normal = '一段落'; + $lang->image_align_left = '左揃え'; + $lang->image_align_middle = '中央揃え'; + $lang->image_align_right = '右揃え'; + $lang->image_border = 'ボーダー'; $lang->image_margin = '外側の空白(Margin)'; - $lang->urllink_open_window = "新しいウィンドウで開く"; - $lang->about_url_link_open_window = "チェックすると、リンクをクリックする際、新しいウィンドウで開きます。"; + $lang->urllink_open_window = '新しいウィンドウで開く'; + $lang->about_url_link_open_window = 'チェックすると、リンクをクリックする際、新しいウィンドウで開きます。'; - $lang->cmd_get_scale = "イメージサイズを計算"; + $lang->cmd_get_scale = 'イメージサイズを計算'; ?> diff --git a/modules/editor/components/multimedia_link/lang/ko.lang.php b/modules/editor/components/multimedia_link/lang/ko.lang.php index 2bf1c4399..c260527c6 100644 --- a/modules/editor/components/multimedia_link/lang/ko.lang.php +++ b/modules/editor/components/multimedia_link/lang/ko.lang.php @@ -10,4 +10,9 @@ $lang->multimedia_width = "가로크기"; $lang->multimedia_height = "세로크기"; $lang->multimedia_auto_start = "자동시작"; + $lang->multimedia_wmode = '위치'; + + $lang->multimedia_wmode_window = '항상 위'; + $lang->multimedia_wmode_opaque = '배경 불투명'; + $lang->multimedia_wmode_transparent = '배경 투명'; ?> diff --git a/modules/editor/components/multimedia_link/multimedia_link.class.php b/modules/editor/components/multimedia_link/multimedia_link.class.php index 4b6ef0b25..841cc7509 100644 --- a/modules/editor/components/multimedia_link/multimedia_link.class.php +++ b/modules/editor/components/multimedia_link/multimedia_link.class.php @@ -53,12 +53,19 @@ if($auto_start!="true") $auto_start = "false"; else $auto_start = "true"; + $wmode = $xml_obj->attrs->wmode; + if($wmode == 'window') $wmode = 'window'; + elseif($wmode == 'opaque') $wmode = 'opaque'; + else $wmode = 'transparent'; + + $caption = $xml_obj->body; $src = str_replace(array('&','"'), array('&','&qout;'), $src); $src = str_replace('&amp;', '&', $src); - return sprintf("
", $src, $width, $height, $auto_start); + if(Context::getResponseMethod() != "XMLRPC") return sprintf("", $src, $width, $height, $auto_start, $wmode); + else return sprintf("

Attached Multimedia
", $width, $height, ($height/2-16), ($width/2-31), Context::getRequestUri().'./modules/editor/components/multimedia_link/tpl/multimedia_link_component.gif'); } } ?> diff --git a/modules/editor/components/multimedia_link/tpl/popup.html b/modules/editor/components/multimedia_link/tpl/popup.html index 269435a03..88241b5d2 100644 --- a/modules/editor/components/multimedia_link/tpl/popup.html +++ b/modules/editor/components/multimedia_link/tpl/popup.html @@ -31,6 +31,16 @@ + + +
{$lang->multimedia_auto_start}
{$lang->multimedia_wmode}
+ +

{$lang->about_ccl_allow_modification}

+
diff --git a/modules/editor/components/multimedia_link/tpl/popup.js b/modules/editor/components/multimedia_link/tpl/popup.js index 9184b3a8c..f1802e7d7 100644 --- a/modules/editor/components/multimedia_link/tpl/popup.js +++ b/modules/editor/components/multimedia_link/tpl/popup.js @@ -14,6 +14,9 @@ function getMultimedia() { var width = xWidth(node); var height = xHeight(node); var auto_start = node.getAttribute("auto_start"); + var wmode = node.getAttribute("wmode"); + + var fo_obj = xGetElementById('fo'); xGetElementById("multimedia_url").value = url; xGetElementById("multimedia_caption").value = caption; @@ -21,6 +24,9 @@ function getMultimedia() { xGetElementById("multimedia_height").value = height-4; if(auto_start=="true") xGetElementById("multimedia_auto_start").checked = true; + if(wmode == 'window') fo_obj.multimedia_wmode.selectedIndex = 0; + else if(wmode == 'opaque') fo_obj.multimedia_wmode.selectedIndex = 1; + else fo_obj.multimedia_wmode.selectedIndex = 2; } function insertMultimedia(obj) { @@ -29,6 +35,9 @@ function insertMultimedia(obj) { var url = xGetElementById("multimedia_url").value; url = url.replace(request_uri,''); // url = encodeURI(url); + var fo_obj = xGetElementById('fo'); + + var wmode = fo_obj.multimedia_wmode.options[fo_obj.multimedia_wmode.selectedIndex].value; var caption = xGetElementById("multimedia_caption").value; @@ -46,7 +55,7 @@ function insertMultimedia(obj) { return; } - var text = "\""+caption+"\""; + var text = "\""+caption+"\""; opener.editorFocus(opener.editorPrevSrl); diff --git a/modules/editor/conf/module.xml b/modules/editor/conf/module.xml index 66ee7d9f2..b2522a8d6 100644 --- a/modules/editor/conf/module.xml +++ b/modules/editor/conf/module.xml @@ -1,26 +1,28 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/editor/editor.class.php b/modules/editor/editor.class.php index e262f4894..f92fd2281 100644 --- a/modules/editor/editor.class.php +++ b/modules/editor/editor.class.php @@ -49,6 +49,15 @@ function checkUpdate() { $oModuleModel = &getModel('module'); + $oDB = &DB::getInstance(); + + // 2009. 06. 15 자동저장시 module_srl 을 저장 + if(!$oDB->isColumnExists("editor_autosave","module_srl")) return true; + + // 2009. 06. 15 module_srl을 인덱스로 + if(!$oDB->isIndexExists("editor_autosave","idx_module_srl")) return true; + + // 2007. 10. 17 글의 입력(신규 or 수정)이 일어날때마다 자동 저장된 문서를 삭제하는 trigger 추가 if(!$oModuleModel->getTrigger('document.insertDocument', 'editor', 'controller', 'triggerDeleteSavedDoc', 'after')) return true; if(!$oModuleModel->getTrigger('document.updateDocument', 'editor', 'controller', 'triggerDeleteSavedDoc', 'after')) return true; @@ -59,6 +68,9 @@ // 2009. 04. 14 editor component 변환 코드를 trigger로 독립 if(!$oModuleModel->getTrigger('display', 'editor', 'controller', 'triggerEditorComponentCompile', 'before')) return true; + // 2009. 06. 19 사용하지 않는 트리거 제거 + if($oModuleModel->getTrigger('file.getIsPermitted', 'editor', 'controller', 'triggerSrlSetting', 'before')) return true; + return false; } @@ -69,6 +81,17 @@ $oModuleModel = &getModel('module'); $oModuleController = &getController('module'); + $oDB = &DB::getInstance(); + + // 자동저장시 module_srl 을 저장 2009.6.15 + if(!$oDB->isColumnExists("editor_autosave","module_srl")) + $oDB->addColumn("editor_autosave","module_srl","number",11); + + // module_srl을 인덱스로 + if(!$oDB->isIndexExists("editor_autosave","idx_module_srl")) + $oDB->addIndex("editor_autosave","idx_module_srl", "module_srl"); + + // 2007. 10. 17 글의 입력(신규 or 수정)이 일어날때마다 자동 저장된 문서를 삭제하는 trigger 추가 if(!$oModuleModel->getTrigger('document.insertDocument', 'editor', 'controller', 'triggerDeleteSavedDoc', 'after')) $oModuleController->insertTrigger('document.insertDocument', 'editor', 'controller', 'triggerDeleteSavedDoc', 'after'); @@ -83,6 +106,10 @@ if(!$oModuleModel->getTrigger('display', 'editor', 'controller', 'triggerEditorComponentCompile', 'before')) $oModuleController->insertTrigger('display', 'editor', 'controller', 'triggerEditorComponentCompile', 'before'); + // 2009. 06. 19 사용하지 않는 트리거 제거 + if($oModuleModel->getTrigger('file.getIsPermitted', 'editor', 'controller', 'triggerSrlSetting', 'before')) + $oModuleController->deleteTrigger('file.getIsPermitted', 'editor', 'controller', 'triggerSrlSetting', 'before'); + return new Object(0, 'success_updated'); } diff --git a/modules/editor/editor.controller.php b/modules/editor/editor.controller.php index ea45e5f2a..32976befe 100644 --- a/modules/editor/editor.controller.php +++ b/modules/editor/editor.controller.php @@ -1,389 +1,446 @@ -deleteSavedDoc(); - - $args->document_srl = Context::get('document_srl'); - $args->content = Context::get('content'); - $args->title = Context::get('title'); - $output = $this->doSaveDoc($args); - - $this->setMessage('msg_auto_saved'); - } - - /** - * @brief 자동저장된 문서 삭제 - **/ - function procEditorRemoveSavedDoc() { - $oEditorController = &getController('editor'); - $oEditorController->deleteSavedDoc(); - } - - /** - * @brief 컴포넌트에서 ajax요청시 해당 컴포넌트의 method를 실행 - **/ - function procEditorCall() { - $component = Context::get('component'); - $method = Context::get('method'); - if(!$component) return new Object(-1, sprintf(Context::getLang('msg_component_is_not_founded'), $component)); - - $oEditorModel = &getModel('editor'); - $oComponent = &$oEditorModel->getComponentObject($component); - if(!$oComponent->toBool()) return $oComponent; - - if(!method_exists($oComponent, $method)) return new Object(-1, sprintf(Context::getLang('msg_component_is_not_founded'), $component)); - - //$output = call_user_method($method, $oComponent); - //$output = call_user_func(array($oComponent, $method)); - if(method_exists($oComponent, $method)) $output = $oComponent->{$method}(); - else return new Object(-1,sprintf('%s method is not exists', $method)); - - if((is_a($output, 'Object') || is_subclass_of($output, 'Object')) && !$output->toBool()) return $output; - - $this->setError($oComponent->getError()); - $this->setMessage($oComponent->getMessage()); - - $vars = $oComponent->getVariables(); - if(count($vars)) { - foreach($vars as $key=>$val) $this->add($key, $val); - } - } - - /** - * @brief 에디터의 모듈별 추가 확장 폼을 저장 - **/ - function procEditorInsertModuleConfig() { - $module_srl = Context::get('target_module_srl'); - - // 여러개의 모듈 일괄 설정일 경우 - if(preg_match('/^([0-9,]+)$/',$module_srl)) $module_srl = explode(',',$module_srl); - else $module_srl = array($module_srl); - - $editor_config = null; - - $editor_config->editor_skin = Context::get('editor_skin'); - $editor_config->comment_editor_skin = Context::get('comment_editor_skin'); - $editor_config->content_style = Context::get('content_style'); - $editor_config->content_font = Context::get('content_font'); - if($editor_config->content_font) { - $font_list = array(); - $fonts = explode(',',$editor_config->content_font); - for($i=0,$c=count($fonts);$i<$c;$i++) { - $font = trim(str_replace(array('"','\''),'',$fonts[$i])); - if(!$font) continue; - $font_list[] = $font; - } - if(count($font_list)) $editor_config->content_font = '"'.implode('","',$font_list).'"'; - } - $editor_config->sel_editor_colorset = Context::get('sel_editor_colorset'); - $editor_config->sel_comment_editor_colorset = Context::get('sel_comment_editor_colorset'); - - $enable_html_grant = trim(Context::get('enable_html_grant')); - if($enable_html_grant) $editor_config->enable_html_grant = explode('|@|', $enable_html_grant); - else $editor_config->enable_html_grant = array(); - - $enable_comment_html_grant = trim(Context::get('enable_comment_html_grant')); - if($enable_comment_html_grant) $editor_config->enable_comment_html_grant = explode('|@|', $enable_comment_html_grant); - else $editor_config->enable_comment_html_grant = array(); - - $upload_file_grant = trim(Context::get('upload_file_grant')); - if($upload_file_grant) $editor_config->upload_file_grant = explode('|@|', $upload_file_grant); - else $editor_config->upload_file_grant = array(); - - $comment_upload_file_grant = trim(Context::get('comment_upload_file_grant')); - if($comment_upload_file_grant) $editor_config->comment_upload_file_grant = explode('|@|', $comment_upload_file_grant); - else $editor_config->comment_upload_file_grant = array(); - - $enable_default_component_grant = trim(Context::get('enable_default_component_grant')); - if($enable_default_component_grant) $editor_config->enable_default_component_grant = explode('|@|', $enable_default_component_grant); - else $editor_config->enable_default_component_grant = array(); - - $enable_comment_default_component_grant = trim(Context::get('enable_comment_default_component_grant')); - if($enable_comment_default_component_grant) $editor_config->enable_comment_default_component_grant = explode('|@|', $enable_comment_default_component_grant); - else $editor_config->enable_comment_default_component_grant = array(); - - $enable_component_grant = trim(Context::get('enable_component_grant')); - if($enable_component_grant) $editor_config->enable_component_grant = explode('|@|', $enable_component_grant); - else $editor_config->enable_component_grant = array(); - - $enable_comment_component_grant = trim(Context::get('enable_comment_component_grant')); - if($enable_comment_component_grant) $editor_config->enable_comment_component_grant = explode('|@|', $enable_comment_component_grant); - else $editor_config->enable_comment_component_grant = array(); - - $editor_config->editor_height = (int)Context::get('editor_height'); - - $editor_config->comment_editor_height = (int)Context::get('comment_editor_height'); - - $editor_config->enable_autosave = Context::get('enable_autosave'); - - if($editor_config->enable_autosave != 'Y') $editor_config->enable_autosave = 'N'; - - $oModuleController = &getController('module'); - for($i=0;$iinsertModulePartConfig('editor',$srl,$editor_config); - } - - $this->setError(-1); - $this->setMessage('success_updated'); - } - - /** - * @brief 에디터컴포넌트의 코드를 결과물로 변환 + 문서서식 style 지정 - **/ - function triggerEditorComponentCompile(&$content) { - if(Context::getResponseMethod()!='HTML') return new Object(); - - $module_info = Context::get('module_info'); - $module_srl = $module_info->module_srl; - if($module_srl) { - $oEditorModel = &getModel('editor'); - $editor_config = $oEditorModel->getEditorConfig($module_srl); - $content_style = $editor_config->content_style; - if($content_style) { - $path = _XE_PATH_.'modules/editor/styles/'.$content_style.'/'; - if(is_dir($path) && file_exists($path.'style.ini')) { - $ini = file($path.'style.ini'); - for($i=0,$c=count($ini);$i<$c;$i++) { - $file = trim($ini[$i]); - if(!$file) continue; - if(preg_match('/\.css$/i',$file)) Context::addCSSFile('./modules/editor/styles/'.$content_style.'/'.$file, false); - elseif(preg_match('/\.js/i',$file)) Context::addJsFile('./modules/editor/styles/'.$content_style.'/'.$file, false); - } - } - } - $content_font = $editor_config->content_font; - if($content_font) Context::addHtmlHeader(''); - } - - $content = $this->transComponent($content); - } - - /** - * @brief 에디터 컴포넌트코드를 결과물로 변환 - **/ - function transComponent($content) { - $content = preg_replace_callback('!]*)editor_component=([^\>]*)>(.*?)\<\/div\>!is', array($this,'transEditorComponent'), $content); - $content = preg_replace_callback('!]*)editor_component=([^\>]*?)\>!is', array($this,'transEditorComponent'), $content); - return $content; - } - - /** - * @brief 내용의 에디터 컴포넌트 코드를 변환 - **/ - function transEditorComponent($matches) { - $script = sprintf(' %s editor_component=%s', $matches[1], $matches[2]); - $script = preg_replace_callback('/([^=^"^ ]*)=([^ ^>]*)/i', fixQuotation, $script); - preg_match_all('/([a-z0-9\-\_]+)\=\"([^\"]+)\"/is', $script, $m); - for($i=0,$c=count($m[0]);$i<$c;$i++) { - $xml_obj->attrs->{$m[1][$i]} = $m[2][$i]; - } - $xml_obj->body = $matches[3]; - - if(!$xml_obj->attrs->editor_component) return $matches[0]; - - // component::transHTML() 을 이용하여 변환된 코드를 받음 - $oEditorModel = &getModel('editor'); - $oComponent = &$oEditorModel->getComponentObject($xml_obj->attrs->editor_component, 0); - if(!is_object($oComponent)||!method_exists($oComponent, 'transHTML')) return $matches[0]; - - return $oComponent->transHTML($xml_obj); - } - - - /** - * @brief 자동 저장 - **/ - function doSaveDoc($args) { - - if(Context::get('is_logged')) { - $logged_info = Context::get('logged_info'); - $args->member_srl = $logged_info->member_srl; - } else { - $args->ipaddress = $_SERVER['REMOTE_ADDR']; - } - - // 저장 - return executeQuery('editor.insertSavedDoc', $args); - } - - - /** - * @brief 게시글의 입력/수정이 일어났을 경우 자동 저장문서를 제거하는 trigger - **/ - function triggerDeleteSavedDoc(&$obj) { - $this->deleteSavedDoc(); - return new Object(); - } - - /** - * @brief 자동 저장된 글을 삭제 - * 현재 접속한 사용자를 기준 - **/ - function deleteSavedDoc() { - if(Context::get('is_logged')) { - $logged_info = Context::get('logged_info'); - $args->member_srl = $logged_info->member_srl; - } else { - $args->ipaddress = $_SERVER['REMOTE_ADDR']; - } - - // 일단 이전 저장본 삭제 - return executeQuery('editor.deleteSavedDoc', $args); - } - - /** - * @brief 가상 사이트에서 사용된 에디터 컴포넌트 정보를 제거 - **/ - function removeEditorConfig($site_srl) { - $args->site_srl = $site_srl; - executeQuery('editor.deleteSiteComponent', $args); - } - - /** - * @brief 에디터 컴포넌트 목록 캐싱 (editorModel::getComponentList) - * 에디터 컴포넌트 목록의 경우 DB query + Xml Parsing 때문에 캐싱 파일을 이용하도록 함 - **/ - function makeCache($filter_enabled = true, $site_srl) { - $oEditorModel = &getModel('editor'); - - if($filter_enabled) $args->enabled = "Y"; - - if($site_srl) { - $args->site_srl = $site_srl; - $output = executeQuery('editor.getSiteComponentList', $args); - } else $output = executeQuery('editor.getComponentList', $args); - $db_list = $output->data; - - // 파일목록을 구함 - $downloaded_list = FileHandler::readDir(_XE_PATH_.'modules/editor/components'); - - // 로그인 여부 및 소속 그룹 구함 - $is_logged = Context::get('is_logged'); - if($is_logged) { - $logged_info = Context::get('logged_info'); - if($logged_info->group_list && is_array($logged_info->group_list)) { - $group_list = array_keys($logged_info->group_list); - } else $group_list = array(); - } - - // DB 목록을 loop돌면서 xml정보까지 구함 - if(!is_array($db_list)) $db_list = array($db_list); - foreach($db_list as $component) { - if(in_array($component->component_name, array('colorpicker_text','colorpicker_bg'))) continue; - - $component_name = $component->component_name; - if(!$component_name) continue; - - if(!in_array($component_name, $downloaded_list)) continue; - - unset($xml_info); - $xml_info = $oEditorModel->getComponentXmlInfo($component_name); - $xml_info->enabled = $component->enabled; - - if($component->extra_vars) { - $extra_vars = unserialize($component->extra_vars); - - // 사용권한이 있으면 권한 체크 - if($extra_vars->target_group) { - // 사용권한이 체크되어 있는데 로그인이 되어 있지 않으면 무조건 사용 중지 - if(!$is_logged) continue; - - // 대상 그룹을 구해서 현재 로그인 사용자의 그룹과 비교 - $target_group = $extra_vars->target_group; - unset($extra_vars->target_group); - - $is_granted = false; - foreach($group_list as $group_srl) { - if(in_array($group_srl, $target_group)) { - $is_granted = true; - break; - } - } - if(!$is_granted) continue; - } - - // 대상 모듈이 있으면 체크 - if($extra_vars->mid_list && count($extra_vars->mid_list) && Context::get('mid')) { - if(!in_array(Context::get('mid'), $extra_vars->mid_list)) continue; - } - - // 에디터 컴포넌트의 설정 정보를 체크 - if($xml_info->extra_vars) { - foreach($xml_info->extra_vars as $key => $val) { - $xml_info->extra_vars->{$key}->value = $extra_vars->{$key}; - } - } - } - - $component_list->{$component_name} = $xml_info; - - // 버튼, 아이콘 이미지 구함 - $icon_file = _XE_PATH_.'modules/editor/components/'.$component_name.'/icon.gif'; - $component_icon_file = _XE_PATH_.'modules/editor/components/'.$component_name.'/component_icon.gif'; - if(file_exists($icon_file)) $component_list->{$component_name}->icon = true; - if(file_exists($component_icon_file)) $component_list->{$component_name}->component_icon = true; - } - - // enabled만 체크하도록 하였으면 그냥 return - if($filter_enabled) { - $cache_file = $oEditorModel->getCacheFile($filter_enabled, $site_srl); - $buff = sprintf('', str_replace('"','\\"',serialize($component_list))); - FileHandler::writeFile($cache_file, $buff); - return $component_list; - } - - // 다운로드된 목록의 xml_info를 마저 구함 - foreach($downloaded_list as $component_name) { - if(in_array($component_name, array('colorpicker_text','colorpicker_bg'))) continue; - - // 설정된 것이라면 패스 - if($component_list->{$component_name}) continue; - - // DB에 입력 - $oEditorController = &getAdminController('editor'); - $oEditorController->insertComponent($component_name, false, $site_srl); - - // component_list에 추가 - unset($xml_info); - $xml_info = $oEditorModel->getComponentXmlInfo($component_name); - $xml_info->enabled = 'N'; - - $component_list->{$component_name} = $xml_info; - } - - $cache_file = $oEditorModel->getCacheFile($filter_enabled, $site_srl); - $buff = sprintf('', str_replace('"','\\"',serialize($component_list))); - FileHandler::writeFile($cache_file, $buff); - - return $component_list; - } - - /** - * @brief 캐시 파일 삭제 - **/ - function removeCache($site_srl = 0) { - $oEditorModel = &getModel('editor'); - FileHandler::removeFile($oEditorModel->getCacheFile(true, $site_srl)); - FileHandler::removeFile($oEditorModel->getCacheFile(false, $site_srl)); - } - } -?> +deleteSavedDoc(false); + + $args->document_srl = Context::get('document_srl'); + $args->content = Context::get('content'); + $args->title = Context::get('title'); + $output = $this->doSaveDoc($args); + + $this->setMessage('msg_auto_saved'); + } + + /** + * @brief 자동저장된 문서 삭제 + **/ + function procEditorRemoveSavedDoc() { + $oEditorController = &getController('editor'); + $oEditorController->deleteSavedDoc(true); + } + + /** + * @brief 컴포넌트에서 ajax요청시 해당 컴포넌트의 method를 실행 + **/ + function procEditorCall() { + $component = Context::get('component'); + $method = Context::get('method'); + if(!$component) return new Object(-1, sprintf(Context::getLang('msg_component_is_not_founded'), $component)); + + $oEditorModel = &getModel('editor'); + $oComponent = &$oEditorModel->getComponentObject($component); + if(!$oComponent->toBool()) return $oComponent; + + if(!method_exists($oComponent, $method)) return new Object(-1, sprintf(Context::getLang('msg_component_is_not_founded'), $component)); + + //$output = call_user_method($method, $oComponent); + //$output = call_user_func(array($oComponent, $method)); + if(method_exists($oComponent, $method)) $output = $oComponent->{$method}(); + else return new Object(-1,sprintf('%s method is not exists', $method)); + + if((is_a($output, 'Object') || is_subclass_of($output, 'Object')) && !$output->toBool()) return $output; + + $this->setError($oComponent->getError()); + $this->setMessage($oComponent->getMessage()); + + $vars = $oComponent->getVariables(); + if(count($vars)) { + foreach($vars as $key=>$val) $this->add($key, $val); + } + } + + /** + * @brief 에디터의 모듈별 추가 확장 폼을 저장 + **/ + function procEditorInsertModuleConfig() { + $module_srl = Context::get('target_module_srl'); + + // 여러개의 모듈 일괄 설정일 경우 + if(preg_match('/^([0-9,]+)$/',$module_srl)) $module_srl = explode(',',$module_srl); + else $module_srl = array($module_srl); + + $editor_config = null; + + $editor_config->editor_skin = Context::get('editor_skin'); + $editor_config->comment_editor_skin = Context::get('comment_editor_skin'); + $editor_config->content_style = Context::get('content_style'); + $editor_config->content_font = Context::get('content_font'); + if($editor_config->content_font) { + $font_list = array(); + $fonts = explode(',',$editor_config->content_font); + for($i=0,$c=count($fonts);$i<$c;$i++) { + $font = trim(str_replace(array('"','\''),'',$fonts[$i])); + if(!$font) continue; + $font_list[] = $font; + } + if(count($font_list)) $editor_config->content_font = '"'.implode('","',$font_list).'"'; + } + $editor_config->content_font_size = Context::get('content_font_size'); + $editor_config->sel_editor_colorset = Context::get('sel_editor_colorset'); + $editor_config->sel_comment_editor_colorset = Context::get('sel_comment_editor_colorset'); + + $enable_html_grant = trim(Context::get('enable_html_grant')); + if($enable_html_grant) $editor_config->enable_html_grant = explode('|@|', $enable_html_grant); + else $editor_config->enable_html_grant = array(); + + $enable_comment_html_grant = trim(Context::get('enable_comment_html_grant')); + if($enable_comment_html_grant) $editor_config->enable_comment_html_grant = explode('|@|', $enable_comment_html_grant); + else $editor_config->enable_comment_html_grant = array(); + + $upload_file_grant = trim(Context::get('upload_file_grant')); + if($upload_file_grant) $editor_config->upload_file_grant = explode('|@|', $upload_file_grant); + else $editor_config->upload_file_grant = array(); + + $comment_upload_file_grant = trim(Context::get('comment_upload_file_grant')); + if($comment_upload_file_grant) $editor_config->comment_upload_file_grant = explode('|@|', $comment_upload_file_grant); + else $editor_config->comment_upload_file_grant = array(); + + $enable_default_component_grant = trim(Context::get('enable_default_component_grant')); + if($enable_default_component_grant) $editor_config->enable_default_component_grant = explode('|@|', $enable_default_component_grant); + else $editor_config->enable_default_component_grant = array(); + + $enable_comment_default_component_grant = trim(Context::get('enable_comment_default_component_grant')); + if($enable_comment_default_component_grant) $editor_config->enable_comment_default_component_grant = explode('|@|', $enable_comment_default_component_grant); + else $editor_config->enable_comment_default_component_grant = array(); + + $enable_component_grant = trim(Context::get('enable_component_grant')); + if($enable_component_grant) $editor_config->enable_component_grant = explode('|@|', $enable_component_grant); + else $editor_config->enable_component_grant = array(); + + $enable_comment_component_grant = trim(Context::get('enable_comment_component_grant')); + if($enable_comment_component_grant) $editor_config->enable_comment_component_grant = explode('|@|', $enable_comment_component_grant); + else $editor_config->enable_comment_component_grant = array(); + + $editor_config->editor_height = (int)Context::get('editor_height'); + + $editor_config->comment_editor_height = (int)Context::get('comment_editor_height'); + + $editor_config->enable_autosave = Context::get('enable_autosave'); + + if($editor_config->enable_autosave != 'Y') $editor_config->enable_autosave = 'N'; + + $oModuleController = &getController('module'); + for($i=0;$iinsertModulePartConfig('editor',$srl,$editor_config); + } + + $this->setError(-1); + $this->setMessage('success_updated'); + } + + /** + * @brief 에디터컴포넌트의 코드를 결과물로 변환 + 문서서식 style 지정 + **/ + function triggerEditorComponentCompile(&$content) { + if(Context::getResponseMethod()!='HTML') return new Object(); + + $module_info = Context::get('module_info'); + $module_srl = $module_info->module_srl; + if($module_srl) { + $oEditorModel = &getModel('editor'); + $editor_config = $oEditorModel->getEditorConfig($module_srl); + $content_style = $editor_config->content_style; + if($content_style) { + $path = _XE_PATH_.'modules/editor/styles/'.$content_style.'/'; + if(is_dir($path) && file_exists($path.'style.ini')) { + $ini = file($path.'style.ini'); + for($i=0,$c=count($ini);$i<$c;$i++) { + $file = trim($ini[$i]); + if(!$file) continue; + if(preg_match('/\.css$/i',$file)) Context::addCSSFile('./modules/editor/styles/'.$content_style.'/'.$file, false); + elseif(preg_match('/\.js/i',$file)) Context::addJsFile('./modules/editor/styles/'.$content_style.'/'.$file, false); + } + } + } + $content_font = $editor_config->content_font; + $content_font_size = $editor_config->content_font_size; + if($content_font || $content_font_size) { + $buff = ''; + Context::addHtmlHeader($buff); + } + } + + $content = $this->transComponent($content); + } + + /** + * @brief 에디터 컴포넌트코드를 결과물로 변환 + **/ + function transComponent($content) { + $content = preg_replace_callback('!]*)editor_component=([^\>]*)>(.*?)\<\/div\>!is', array($this,'transEditorComponent'), $content); + $content = preg_replace_callback('!]*)editor_component=([^\>]*?)\>!is', array($this,'transEditorComponent'), $content); + return $content; + } + + /** + * @brief 내용의 에디터 컴포넌트 코드를 변환 + **/ + function transEditorComponent($matches) { + $script = sprintf(' %s editor_component=%s', $matches[1], $matches[2]); + $script = preg_replace_callback('/([^=^"^ ]*)=([^ ^>]*)/i', fixQuotation, $script); + preg_match_all('/([a-z0-9\-\_]+)\=\"([^\"]+)\"/is', $script, $m); + for($i=0,$c=count($m[0]);$i<$c;$i++) { + $xml_obj->attrs->{$m[1][$i]} = $m[2][$i]; + } + $xml_obj->body = $matches[3]; + + if(!$xml_obj->attrs->editor_component) return $matches[0]; + + // component::transHTML() 을 이용하여 변환된 코드를 받음 + $oEditorModel = &getModel('editor'); + $oComponent = &$oEditorModel->getComponentObject($xml_obj->attrs->editor_component, 0); + if(!is_object($oComponent)||!method_exists($oComponent, 'transHTML')) return $matches[0]; + + return $oComponent->transHTML($xml_obj); + } + + + /** + * @brief 자동 저장 + **/ + function doSaveDoc($args) { + + if(!$args->document_srl) $args->document_srl = $_SESSION['upload_info'][$editor_sequence]->upload_target_srl; + if(Context::get('is_logged')) { + $logged_info = Context::get('logged_info'); + $args->member_srl = $logged_info->member_srl; + } else { + $args->ipaddress = $_SERVER['REMOTE_ADDR']; + } + // module_srl이 없으면 현재 모듈 + if(!$args->module_srl) { + $args->module_srl = Context::get('module_srl'); + } + if(!$args->module_srl) { + $current_module_info = Context::get('current_module_info'); + $args->module_srl = $current_module_info->module_srl; + } + + // 저장 + return executeQuery('editor.insertSavedDoc', $args); + } + + /** + * @brief 자동 저장글 Srl 로드 - XE 이전 버전 사용자를 위함. + **/ + function procEditorLoadSavedDocument() { + $editor_sequence = Context::get('editor_sequence'); + $primary_key = Context::get('primary_key'); + $oEditorModel = &getModel('editor'); + $oFileController = &getController('file'); + + $saved_doc = $oEditorModel->getSavedDoc(null); + + $oFileController->setUploadInfo($editor_sequence, $saved_doc->document_srl); + $vars = $this->getVariables(); + $this->add("editor_sequence", $editor_sequence); + $this->add("key", $primary_key); + $this->add("title", $saved_doc->title); + $this->add("content", $saved_doc->content); + $this->add("document_srl", $saved_doc->document_srl); + } + + + /** + * @brief 게시글의 입력/수정이 일어났을 경우 자동 저장문서를 제거하는 trigger + **/ + function triggerDeleteSavedDoc(&$obj) { + $this->deleteSavedDoc(false); + return new Object(); + } + + /** + * @brief 자동 저장된 글을 삭제 + * 현재 접속한 사용자를 기준 + **/ + function deleteSavedDoc($mode = false) { + if(Context::get('is_logged')) { + $logged_info = Context::get('logged_info'); + $args->member_srl = $logged_info->member_srl; + } else { + $args->ipaddress = $_SERVER['REMOTE_ADDR']; + } + $args->module_srl = Context::get('module_srl'); + // module_srl이 없으면 현재 모듈 + if(!$args->module_srl) { + $current_module_info = Context::get('current_module_info'); + $args->module_srl = $current_module_info->module_srl; + } + + // 자동저장된 값이 혹시 이미 등록된 글인지 확인 + $output = executeQuery('editor.getSavedDocument', $args); + $saved_doc = $output->data; + if(!$saved_doc) return; + + $oDocumentModel = &getModel('document'); + $oSaved = $oDocumentModel->getDocument($saved_doc->document_srl); + if(!$oSaved->isExists()) { + if($mode) { + $output = executeQuery('editor.getSavedDocument', $args); + $output = ModuleHandler::triggerCall('editor.deleteSavedDoc', 'after', $saved_doc); + } + } + + // 일단 이전 저장본 삭제 + return executeQuery('editor.deleteSavedDoc', $args); + } + + /** + * @brief 가상 사이트에서 사용된 에디터 컴포넌트 정보를 제거 + **/ + function removeEditorConfig($site_srl) { + $args->site_srl = $site_srl; + executeQuery('editor.deleteSiteComponent', $args); + } + + /** + * @brief 에디터 컴포넌트 목록 캐싱 (editorModel::getComponentList) + * 에디터 컴포넌트 목록의 경우 DB query + Xml Parsing 때문에 캐싱 파일을 이용하도록 함 + **/ + function makeCache($filter_enabled = true, $site_srl) { + $oEditorModel = &getModel('editor'); + + if($filter_enabled) $args->enabled = "Y"; + + if($site_srl) { + $args->site_srl = $site_srl; + $output = executeQuery('editor.getSiteComponentList', $args); + } else $output = executeQuery('editor.getComponentList', $args); + $db_list = $output->data; + + // 파일목록을 구함 + $downloaded_list = FileHandler::readDir(_XE_PATH_.'modules/editor/components'); + + // 로그인 여부 및 소속 그룹 구함 + $is_logged = Context::get('is_logged'); + if($is_logged) { + $logged_info = Context::get('logged_info'); + if($logged_info->group_list && is_array($logged_info->group_list)) { + $group_list = array_keys($logged_info->group_list); + } else $group_list = array(); + } + + // DB 목록을 loop돌면서 xml정보까지 구함 + if(!is_array($db_list)) $db_list = array($db_list); + foreach($db_list as $component) { + if(in_array($component->component_name, array('colorpicker_text','colorpicker_bg'))) continue; + + $component_name = $component->component_name; + if(!$component_name) continue; + + if(!in_array($component_name, $downloaded_list)) continue; + + unset($xml_info); + $xml_info = $oEditorModel->getComponentXmlInfo($component_name); + $xml_info->enabled = $component->enabled; + + if($component->extra_vars) { + $extra_vars = unserialize($component->extra_vars); + + // 사용권한이 있으면 권한 체크 + if($extra_vars->target_group) { + // 사용권한이 체크되어 있는데 로그인이 되어 있지 않으면 무조건 사용 중지 + if(!$is_logged) continue; + + // 대상 그룹을 구해서 현재 로그인 사용자의 그룹과 비교 + $target_group = $extra_vars->target_group; + unset($extra_vars->target_group); + + $is_granted = false; + foreach($group_list as $group_srl) { + if(in_array($group_srl, $target_group)) { + $is_granted = true; + break; + } + } + if(!$is_granted) continue; + } + + // 대상 모듈이 있으면 체크 + if($extra_vars->mid_list && count($extra_vars->mid_list) && Context::get('mid')) { + if(!in_array(Context::get('mid'), $extra_vars->mid_list)) continue; + } + + // 에디터 컴포넌트의 설정 정보를 체크 + if($xml_info->extra_vars) { + foreach($xml_info->extra_vars as $key => $val) { + $xml_info->extra_vars->{$key}->value = $extra_vars->{$key}; + } + } + } + + $component_list->{$component_name} = $xml_info; + + // 버튼, 아이콘 이미지 구함 + $icon_file = _XE_PATH_.'modules/editor/components/'.$component_name.'/icon.gif'; + $component_icon_file = _XE_PATH_.'modules/editor/components/'.$component_name.'/component_icon.gif'; + if(file_exists($icon_file)) $component_list->{$component_name}->icon = true; + if(file_exists($component_icon_file)) $component_list->{$component_name}->component_icon = true; + } + + // enabled만 체크하도록 하였으면 그냥 return + if($filter_enabled) { + $cache_file = $oEditorModel->getCacheFile($filter_enabled, $site_srl); + $buff = sprintf('', str_replace('"','\\"',serialize($component_list))); + FileHandler::writeFile($cache_file, $buff); + return $component_list; + } + + // 다운로드된 목록의 xml_info를 마저 구함 + foreach($downloaded_list as $component_name) { + if(in_array($component_name, array('colorpicker_text','colorpicker_bg'))) continue; + + // 설정된 것이라면 패스 + if($component_list->{$component_name}) continue; + + // DB에 입력 + $oEditorController = &getAdminController('editor'); + $oEditorController->insertComponent($component_name, false, $site_srl); + + // component_list에 추가 + unset($xml_info); + $xml_info = $oEditorModel->getComponentXmlInfo($component_name); + $xml_info->enabled = 'N'; + + $component_list->{$component_name} = $xml_info; + } + + $cache_file = $oEditorModel->getCacheFile($filter_enabled, $site_srl); + $buff = sprintf('', str_replace('"','\\"',serialize($component_list))); + FileHandler::writeFile($cache_file, $buff); + + return $component_list; + } + + /** + * @brief 캐시 파일 삭제 + **/ + function removeCache($site_srl = 0) { + $oEditorModel = &getModel('editor'); + FileHandler::removeFile($oEditorModel->getCacheFile(true, $site_srl)); + FileHandler::removeFile($oEditorModel->getCacheFile(false, $site_srl)); + } + } +?> diff --git a/modules/editor/editor.model.php b/modules/editor/editor.model.php index 9b9da8e8f..cd542fd1f 100644 --- a/modules/editor/editor.model.php +++ b/modules/editor/editor.model.php @@ -1,619 +1,633 @@ -getModulePartConfig('editor', $module_srl); - } - - $editor_config = $GLOBALS['__editor_module_config__'][$module_srl]; - - if(!is_object($editor_config)) $editor_config = null; - - if(!is_array($editor_config->enable_html_grant)) $editor_config->enable_html_grant = array(); - if(!is_array($editor_config->enable_comment_html_grant)) $editor_config->enable_comment_html_grant = array(); - if(!is_array($editor_config->upload_file_grant)) $editor_config->upload_file_grant = array(); - if(!is_array($editor_config->comment_upload_file_grant)) $editor_config->comment_upload_file_grant = array(); - if(!is_array($editor_config->enable_default_component_grant)) $editor_config->enable_default_component_grant = array(); - if(!is_array($editor_config->enable_comment_default_component_grant)) $editor_config->enable_comment_default_component_grant = array(); - if(!is_array($editor_config->enable_component_grant)) $editor_config->enable_component_grant = array(); - if(!is_array($editor_config->enable_comment_component_grant)) $editor_config->enable_comment_component_grant= array(); - - 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_autosave!='N') $editor_config->enable_autosave = "Y"; - - if(!$editor_config->editor_skin) $editor_config->editor_skin = 'xpresseditor'; - if(!$editor_config->comment_editor_skin) $editor_config->comment_editor_skin = 'xpresseditor'; - //if(!$editor_config->content_style) $editor_config->content_style = 'xeStyle'; - - return $editor_config; - } - - /** - * @brief 에디터 template을 return - * upload_target_srl은 글의 수정시 호출하면 됨. - * 이 upload_target_srl은 첨부파일의 유무를 체크하기 위한 루틴을 구현하는데 사용됨. - **/ - function getEditor($upload_target_srl = 0, $option = null) { - /** - * 기본적인 에디터의 옵션을 정리 - **/ - // 파일 업로드 유무 옵션 설정 - if(!$option->allow_fileupload) $allow_fileupload = false; - else $allow_fileupload = true; - - // content_style 세팅 - if(!$option->content_style) $option->content_style = 'xeStyle'; - Context::set('content_style', $option->content_style); - - // 기본 글꼴 지정 - Context::set('content_font', $option->content_font); - - // 자동 저장 유무 옵션 설정 - if(!$option->enable_autosave) $enable_autosave = false; - else $enable_autosave = true; - - // 기본 에디터 컴포넌트 사용 설정 - if(!$option->enable_default_component) $enable_default_component = false; - else $enable_default_component = true; - - // 확장 컴포넌트 사용 설정 - if(!$option->enable_component) $enable_component = false; - else $enable_component = true; - - // html 모드 조절 - if($option->disable_html) $html_mode = false; - else $html_mode = true; - - // 높이 설정 - if(!$option->height) $editor_height = 400; - else $editor_height = $option->height; - - // 스킨 설정 - $skin = $option->skin; - if(!$skin) $skin = 'xpresseditor'; - - $colorset = $option->colorset; - Context::set('colorset', $colorset); - Context::set('skin', $skin); - /** - * 자동백업 기능 체크 (글 수정일 경우는 사용하지 않음) - **/ - if($enable_autosave) { - // 자동 저장된 데이터를 추출 - $saved_doc = $this->getSavedDoc($upload_target_srl); - - // 자동 저장 데이터를 context setting - Context::set('saved_doc', $saved_doc); - } - Context::set('enable_autosave', $enable_autosave); - - /** - * 에디터의 고유 번호 추출 (한 페이지에 여러개의 에디터를 출력하는 경우를 대비) - **/ - if($option->editor_sequence) $editor_sequence = $option->editor_sequence; - else { - if(!$GLOBALS['_editor_sequence_']) $GLOBALS['_editor_sequence_'] = 1; - $editor_sequence = $GLOBALS['_editor_sequence_'] ++; - } - - /** - * 업로드 활성화시 내부적으로 file 모듈의 환경설정을 이용하여 설정 - **/ - $files_count = 0; - if($allow_fileupload) { - $oFileModel = &getModel('file'); - - // SWFUploader에 세팅할 업로드 설정 구함 - $file_config = $oFileModel->getUploadConfig(); - $file_config->allowed_attach_size = $file_config->allowed_attach_size*1024*1024; - $file_config->allowed_filesize = $file_config->allowed_filesize*1024*1024; - - Context::set('file_config',$file_config); - - // 업로드 가능 용량등에 대한 정보를 세팅 - $upload_status = $oFileModel->getUploadStatus(); - Context::set('upload_status', $upload_status); - - // upload가능하다고 설정 (내부적으로 캐싱하여 처리) - $oFileController = &getController('file'); - $oFileController->setUploadInfo($editor_sequence, $upload_target_srl); - - // 이미 등록된 파일이 있는지 검사 - if($upload_target_srl) $files_count = $oFileModel->getFilesCount($upload_target_srl); - } - Context::set('files_count', (int)$files_count); - - Context::set('allow_fileupload', $allow_fileupload); - - // 에디터 동작을 위한 editor_sequence값 설정 - Context::set('editor_sequence', $editor_sequence); - - // 파일 첨부 관련 행동을 하기 위해 문서 번호를 upload_target_srl로 설정 - // 신규문서일 경우 upload_target_srl=0 이고 첨부파일 관련 동작이 요청될때 이 값이 변경됨 - Context::set('upload_target_srl', $upload_target_srl); - - // 문서 혹은 댓글의 primary key값을 세팅한다. - Context::set('editor_primary_key_name', $option->primary_key_name); - - // 내용을 sync 맞추기 위한 content column name을 세팅한다 - Context::set('editor_content_key_name', $option->content_key_name); - - - /** - * 에디터 컴포넌트 체크 - **/ - $site_module_info = Context::get('site_module_info'); - $site_srl = (int)$site_module_info->site_srl; - if($enable_component) { - if(!Context::get('component_list')) { - $component_list = $this->getComponentList(true, $site_srl); - Context::set('component_list', $component_list); - } - } - Context::set('enable_component', $enable_component); - Context::set('enable_default_component', $enable_default_component); - - /** - * html_mode 가능한지 변수 설정 - **/ - Context::set('html_mode', $html_mode); - - /** - * 에디터 세로 크기 설정 - **/ - Context::set('editor_height', $editor_height); - - // 에디터의 초기화를 수동으로하는 것에 대한 값 체크 - Context::set('editor_manual_start', $option->manual_start); - - /** - * 템플릿을 미리 컴파일해서 컴파일된 소스를 하기 위해 스킨의 경로를 설정 - **/ - $tpl_path = sprintf('%sskins/%s/', $this->module_path, $skin); - $tpl_file = 'editor.html'; - - if(!file_exists($tpl_path.$tpl_file)) { - $skin = 'xpresseditor'; - $tpl_path = sprintf('%sskins/%s/', $this->module_path, $skin); - } - Context::set('editor_path', $tpl_path); - - // tpl 파일을 compile한 결과를 return - $oTemplate = new TemplateHandler(); - return $oTemplate->compile($tpl_path, $tpl_file); - } - - /** - * @brief 모듈별 설정이 반영된 에디터 template을 return - * getEditor() 와 동일한 결과물을 return하지만 getModuleEditor()는 각 모듈별 추가 설정을 통해 직접 제어되는 설정을 이용하여 에디터를 생성함 - * - * document/ comment 2가지 종류를 이용함. - * 굳이 나눈 이유는 하나의 모듈에서 2개 종류의 에디터 사용을 위해서인데 게시판이나 블로그등 원글과 그에 연관된 글(댓글)을 위한 용도임. - **/ - 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->content_style = $editor_config->content_style; - $config->content_font = $editor_config->content_font; - $config->sel_editor_colorset = $editor_config->sel_editor_colorset; - $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_autosave = $editor_config->enable_autosave; - } else { - $config->editor_skin = $editor_config->comment_editor_skin; - $config->content_style = $editor_config->content_style; - $config->content_font = $editor_config->content_font; - $config->sel_editor_colorset = $editor_config->sel_comment_editor_colorset; - $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_autosave = 'N'; - } - - // 권한 체크를 위한 현재 로그인 사용자의 그룹 설정 체크 - if(Context::get('is_logged')) { - $logged_info = Context::get('logged_info'); - $group_list = $logged_info->group_list; - } else { - $group_list = array(); - } - - // 에디터 옵션 변수를 미리 설정 - $option->skin = $config->editor_skin; - $option->content_style = $config->content_style; - $option->content_font = $config->content_font; - $option->colorset = $config->sel_editor_colorset; - - // 파일 업로드 권한 체크 - $option->allow_fileupload = false; - if(count($config->upload_file_grant)) { - foreach($group_list as $group_srl => $group_info) { - if(in_array($group_srl, $config->upload_file_grant)) { - $option->allow_fileupload = true; - break; - } - } - } else $option->allow_fileupload = true; - - // 기본 컴포넌트 사용 권한 - $option->enable_default_component = false; - if(count($config->enable_default_component_grant)) { - foreach($group_list as $group_srl => $group_info) { - if(in_array($group_srl, $config->enable_default_component_grant)) { - $option->enable_default_component = true; - break; - } - } - } else $option->enable_default_component = true; - - // 확장 컴포넌트 사용 권한 - $option->enable_component = false; - if(count($config->enable_component_grant)) { - foreach($group_list as $group_srl => $group_info) { - if(in_array($group_srl, $config->enable_component_grant)) { - $option->enable_component = true; - break; - } - } - } else $option->enable_component = true; - - // 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->height = $config->editor_height; - - // 자동 저장 유무 옵션 설정 - $option->enable_autosave = $config->enable_autosave=='Y'?true:false; - - // 기타 설정 - $option->primary_key_name = $primary_key_name; - $option->content_key_name = $content_key_name; - - return $this->getEditor($upload_target_srl, $option); - } - - /** - * @brief 자동저장되어 있는 정보를 가져옴 - **/ - function getSavedDoc($upload_target_srl) { - // 로그인 회원이면 member_srl, 아니면 ipaddress로 저장되어 있는 문서를 찾음 - if(Context::get('is_logged')) { - $logged_info = Context::get('logged_info'); - $auto_save_args->member_srl = $logged_info->member_srl; - } else { - $auto_save_args->ipaddress = $_SERVER['REMOTE_ADDR']; - } - - // DB에서 자동저장 데이터 추출 - $output = executeQuery('editor.getSavedDocument', $auto_save_args); - $saved_doc = $output->data; - - // 자동저장한 결과가 없으면 null값 return - if(!$saved_doc) return; - - // 자동저장된 값이 혹시 이미 등록된 글인지 확인 - $oDocumentModel = &getModel('document'); - $oSaved = $oDocumentModel->getDocument($saved_doc->document_srl); - if($oSaved->isExists()) return; - - // 자동저장 데이터에 문서번호가 있고 이 번호에 파일이 있다면 파일을 모두 이동하고 - // 해당 문서 번호를 editor_sequence로 세팅함 - if($saved_doc->document_srl) { - $module_srl = Context::get('module_srl'); - $oFileController = &getController('file'); - $oFileController->moveFile($saved_doc->document_srl, $module_srl, $upload_target_srl); - } - $saved_doc->document_srl = $upload_target_srl; - - // 자동 저장 데이터 변경 - $oEditorController = &getController('editor'); - $oEditorController->deleteSavedDoc(); - $oEditorController->doSaveDoc($saved_doc); - - return $saved_doc; - } - - /** - * @brief component의 객체 생성 - **/ - function getComponentObject($component, $editor_sequence = 0, $site_srl = 0) { - if(!$this->loaded_component_list[$component][$editor_sequence]) { - // 해당 컴포넌트의 객체를 생성해서 실행 - $class_path = sprintf('%scomponents/%s/', $this->module_path, $component); - $class_file = sprintf('%s%s.class.php', $class_path, $component); - if(!file_exists($class_file)) return new Object(-1, sprintf(Context::getLang('msg_component_is_not_founded'), $component)); - - // 클래스 파일을 읽은 후 객체 생성 - require_once($class_file); - $eval_str = sprintf('$oComponent = new %s("%s","%s");', $component, $editor_sequence, $class_path); - @eval($eval_str); - if(!$oComponent) return new Object(-1, sprintf(Context::getLang('msg_component_is_not_founded'), $component)); - - // 설정 정보를 추가 - $component_info = $this->getComponent($component, $site_srl); - $oComponent->setInfo($component_info); - $this->loaded_component_list[$component][$editor_sequence] = $oComponent; - } - - return $this->loaded_component_list[$component][$editor_sequence]; - } - - /** - * @brief editor skin 목록을 return - **/ - function getEditorSkinList() { - return FileHandler::readDir('./modules/editor/skins'); - } - - /** - * @brief 에디터 컴포넌트 목록 캐시 파일 이름 return - **/ - function getCacheFile($filter_enabled= true, $site_srl = 0) { - $lang = Context::getLangType(); - $cache_path = _XE_PATH_.'files/cache/editor/cache/'; - if(!is_dir($cache_path)) FileHandler::makeDir($cache_path); - $cache_file = $cache_path.'component_list.' . $lang .'.'; - if($filter_enabled) $cache_file .= 'filter.'; - if($site_srl) $cache_file .= $site_srl.'.'; - $cache_file .= 'php'; - return $cache_file; - } - - /** - * @brief component 목록을 return (DB정보 보함) - **/ - function getComponentList($filter_enabled = true, $site_srl=0) { - $cache_file = $this->getCacheFile($filter_enabled, $site_srl); - if(!file_exists($cache_file)) { - $oEditorController = &getController('editor'); - $oEditorController->makeCache($filter_enabled, $site_srl); - } - - if(!file_exists($cache_file)) return; - @include($cache_file); - - if(count($component_list)) { - foreach($component_list as $key => $val) { - if(!trim($key)) continue; - if(!is_dir(_XE_PATH_.'modules/editor/components/'.$key)) { - FileHandler::removeFile($cache_file); - return $this->getComponentList($filter_enabled, $site_srl); - } - } - - } - return $component_list; - } - - /** - * @brief compnent의 xml+db정보를 구함 - **/ - function getComponent($component_name, $site_srl = 0) { - $args->component_name = $component_name; - - if($site_srl) { - $args->site_srl = $site_srl; - $output = executeQuery('editor.getSiteComponent', $args); - } else { - $output = executeQuery('editor.getComponent', $args); - } - $component = $output->data; - - $component_name = $component->component_name; - - unset($xml_info); - $xml_info = $this->getComponentXmlInfo($component_name); - $xml_info->enabled = $component->enabled; - - $xml_info->target_group = array(); - - $xml_info->mid_list = array(); - - if($component->extra_vars) { - $extra_vars = unserialize($component->extra_vars); - - if($extra_vars->target_group) { - $xml_info->target_group = $extra_vars->target_group; - unset($extra_vars->target_group); - } - - if($extra_vars->mid_list) { - $xml_info->mid_list = $extra_vars->mid_list; - unset($extra_vars->mid_list); - } - - - if($xml_info->extra_vars) { - foreach($xml_info->extra_vars as $key => $val) { - $xml_info->extra_vars->{$key}->value = $extra_vars->{$key}; - } - } - } - - return $xml_info; - } - - /** - * @brief component의 xml정보를 읽음 - **/ - function getComponentXmlInfo($component) { - $lang_type = Context::getLangType(); - - // 요청된 컴포넌트의 xml파일 위치를 구함 - $component_path = sprintf('%s/components/%s/', $this->module_path, $component); - - $xml_file = sprintf('%sinfo.xml', $component_path); - $cache_file = sprintf('./files/cache/editor/%s.%s.php', $component, $lang_type); - - // 캐시된 xml파일이 있으면 include 후 정보 return - if(file_exists($cache_file) && file_exists($xml_file) && filemtime($cache_file) > filemtime($xml_file)) { - include($cache_file); - return $xml_info; - } - - // 캐시된 파일이 없으면 파싱후 캐싱 후 return - $oParser = new XmlParser(); - $xml_doc = $oParser->loadXmlFile($xml_file); - - // 정보 정리 - if($xml_doc->component->version && $xml_doc->component->attrs->version == '0.2') { - $component_info->component_name = $component; - $component_info->title = $xml_doc->component->title->body; - $component_info->description = str_replace('\n', "\n", $xml_doc->component->description->body); - $component_info->version = $xml_doc->component->version->body; - $component_info->date = $xml_doc->component->date->body; - $component_info->homepage = $xml_doc->component->link->body; - $component_info->license = $xml_doc->component->license->body; - $component_info->license_link = $xml_doc->component->license->attrs->link; - - $buff = 'component_name = "%s";', $component_info->component_name); - $buff .= sprintf('$xml_info->title = "%s";', $component_info->title); - $buff .= sprintf('$xml_info->description = "%s";', $component_info->description); - $buff .= sprintf('$xml_info->version = "%s";', $component_info->version); - $buff .= sprintf('$xml_info->date = "%s";', $component_info->date); - $buff .= sprintf('$xml_info->homepage = "%s";', $component_info->homepage); - $buff .= sprintf('$xml_info->license = "%s";', $component_info->license); - $buff .= sprintf('$xml_info->license_link = "%s";', $component_info->license_link); - - // 작성자 정보 - if(!is_array($xml_doc->component->author)) $author_list[] = $xml_doc->component->author; - else $author_list = $xml_doc->component->author; - - for($i=0; $i < count($author_list); $i++) { - $buff .= sprintf('$xml_info->author['.$i.']->name = "%s";', $author_list[$i]->name->body); - $buff .= sprintf('$xml_info->author['.$i.']->email_address = "%s";', $author_list[$i]->attrs->email_address); - $buff .= sprintf('$xml_info->author['.$i.']->homepage = "%s";', $author_list[$i]->attrs->link); - } - - // history - if($xml_doc->component->history) { - if(!is_array($xml_doc->component->history)) $history_list[] = $xml_doc->component->history; - else $history_list = $xml_doc->component->history; - - for($i=0; $i < count($history_list); $i++) { - unset($obj); - sscanf($history_list[$i]->attrs->date, '%d-%d-%d', $date_obj->y, $date_obj->m, $date_obj->d); - $date = sprintf('%04d%02d%02d', $date_obj->y, $date_obj->m, $date_obj->d); - $buff .= sprintf('$xml_info->history['.$i.']->description = "%s";', $history_list[$i]->description->body); - $buff .= sprintf('$xml_info->history['.$i.']->version = "%s";', $history_list[$i]->attrs->version); - $buff .= sprintf('$xml_info->history['.$i.']->date = "%s";', $date); - - if($history_list[$i]->author) { - (!is_array($history_list[$i]->author)) ? $obj->author_list[] = $history_list[$i]->author : $obj->author_list = $history_list[$i]->author; - - for($j=0; $j < count($obj->author_list); $j++) { - $buff .= sprintf('$xml_info->history['.$i.']->author['.$j.']->name = "%s";', $obj->author_list[$j]->name->body); - $buff .= sprintf('$xml_info->history['.$i.']->author['.$j.']->email_address = "%s";', $obj->author_list[$j]->attrs->email_address); - $buff .= sprintf('$xml_info->history['.$i.']->author['.$j.']->homepage = "%s";', $obj->author_list[$j]->attrs->link); - } - } - - if($history_list[$i]->log) { - (!is_array($history_list[$i]->log)) ? $obj->log_list[] = $history_list[$i]->log : $obj->log_list = $history_list[$i]->log; - - for($j=0; $j < count($obj->log_list); $j++) { - $buff .= sprintf('$xml_info->history['.$i.']->logs['.$j.']->text = "%s";', $obj->log_list[$j]->body); - $buff .= sprintf('$xml_info->history['.$i.']->logs['.$j.']->link = "%s";', $obj->log_list[$j]->attrs->link); - } - } - } - } - - - } else { - sscanf($xml_doc->component->author->attrs->date, '%d. %d. %d', $date_obj->y, $date_obj->m, $date_obj->d); - $date = sprintf('%04d%02d%02d', $date_obj->y, $date_obj->m, $date_obj->d); - $xml_info->component_name = $component; - $xml_info->title = $xml_doc->component->title->body; - $xml_info->description = str_replace('\n', "\n", $xml_doc->component->author->description->body); - $xml_info->version = $xml_doc->component->attrs->version; - $xml_info->date = $date; - $xml_info->author->name = $xml_doc->component->author->name->body; - $xml_info->author->email_address = $xml_doc->component->author->attrs->email_address; - $xml_info->author->homepage = $xml_doc->component->author->attrs->link; - - $buff = 'component_name = "%s";', $xml_info->component_name); - $buff .= sprintf('$xml_info->title = "%s";', $xml_info->title); - $buff .= sprintf('$xml_info->description = "%s";', $xml_info->description); - $buff .= sprintf('$xml_info->version = "%s";', $xml_info->version); - $buff .= sprintf('$xml_info->date = "%s";', $xml_info->date); - $buff .= sprintf('$xml_info->author[0]->name = "%s";', $xml_info->author->name); - $buff .= sprintf('$xml_info->author[0]->email_address = "%s";', $xml_info->author->email_address); - $buff .= sprintf('$xml_info->author[0]->homepage = "%s";', $xml_info->author->homepage); - } - - // 추가 변수 정리 (에디터 컴포넌트에서는 text형만 가능) - $extra_vars = $xml_doc->component->extra_vars->var; - if($extra_vars) { - if(!is_array($extra_vars)) $extra_vars = array($extra_vars); - foreach($extra_vars as $key => $val) { - unset($obj); - $key = $val->attrs->name; - $title = $val->title->body; - $description = $val->description->body; - $xml_info->extra_vars->{$key}->title = $title; - $xml_info->extra_vars->{$key}->description = $description; - - $buff .= sprintf('$xml_info->extra_vars->%s->%s = "%s";', $key, 'title', $title); - $buff .= sprintf('$xml_info->extra_vars->%s->%s = "%s";', $key, 'description', $description); - } - } - - $buff .= ' ?>'; - - FileHandler::writeFile($cache_file, $buff, "w"); - - unset($xml_info); - include($cache_file); - return $xml_info; - } - } -?> +getModulePartConfig('editor', $module_srl); + } + + $editor_config = $GLOBALS['__editor_module_config__'][$module_srl]; + + if(!is_object($editor_config)) $editor_config = null; + + if(!is_array($editor_config->enable_html_grant)) $editor_config->enable_html_grant = array(); + if(!is_array($editor_config->enable_comment_html_grant)) $editor_config->enable_comment_html_grant = array(); + if(!is_array($editor_config->upload_file_grant)) $editor_config->upload_file_grant = array(); + if(!is_array($editor_config->comment_upload_file_grant)) $editor_config->comment_upload_file_grant = array(); + if(!is_array($editor_config->enable_default_component_grant)) $editor_config->enable_default_component_grant = array(); + if(!is_array($editor_config->enable_comment_default_component_grant)) $editor_config->enable_comment_default_component_grant = array(); + if(!is_array($editor_config->enable_component_grant)) $editor_config->enable_component_grant = array(); + if(!is_array($editor_config->enable_comment_component_grant)) $editor_config->enable_comment_component_grant= array(); + + 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_autosave!='N') $editor_config->enable_autosave = "Y"; + + if(!$editor_config->editor_skin) $editor_config->editor_skin = 'xpresseditor'; + if(!$editor_config->comment_editor_skin) $editor_config->comment_editor_skin = 'xpresseditor'; + if(!$editor_config->content_style) $editor_config->content_style = 'default'; + + return $editor_config; + } + + /** + * @brief 에디터 template을 return + * upload_target_srl은 글의 수정시 호출하면 됨. + * 이 upload_target_srl은 첨부파일의 유무를 체크하기 위한 루틴을 구현하는데 사용됨. + **/ + function getEditor($upload_target_srl = 0, $option = null) { + /** + * 기본적인 에디터의 옵션을 정리 + **/ + // 파일 업로드 유무 옵션 설정 + if(!$option->allow_fileupload) $allow_fileupload = false; + else $allow_fileupload = true; + + // content_style 세팅 + if(!$option->content_style) $option->content_style = 'default'; + Context::set('content_style', $option->content_style); + + // 기본 글꼴 지정 + Context::set('content_font', $option->content_font); + Context::set('content_font_size', $option->content_font_size); + + // 자동 저장 유무 옵션 설정 글 수정시는 사용 안함 + if(!$option->enable_autosave) $enable_autosave = false; + elseif(Context::get($option->primary_key_name)) $enable_autosave = false; + else $enable_autosave = true; + + // 기본 에디터 컴포넌트 사용 설정 + if(!$option->enable_default_component) $enable_default_component = false; + else $enable_default_component = true; + + // 확장 컴포넌트 사용 설정 + if(!$option->enable_component) $enable_component = false; + else $enable_component = true; + + // html 모드 조절 + if($option->disable_html) $html_mode = false; + else $html_mode = true; + + // 높이 설정 + if(!$option->height) $editor_height = 400; + else $editor_height = $option->height; + + // 스킨 설정 + $skin = $option->skin; + if(!$skin) $skin = 'xpresseditor'; + + $colorset = $option->colorset; + Context::set('colorset', $colorset); + Context::set('skin', $skin); + /** + * 자동백업 기능 체크 (글 수정일 경우는 사용하지 않음) + **/ + if($enable_autosave) { + // 자동 저장된 데이터를 추출 + $saved_doc = $this->getSavedDoc($upload_target_srl); + + // 자동 저장 데이터를 context setting + Context::set('saved_doc', $saved_doc); + } + Context::set('enable_autosave', $enable_autosave); + + /** + * 에디터의 고유 번호 추출 (한 페이지에 여러개의 에디터를 출력하는 경우를 대비) + **/ + if($option->editor_sequence) $editor_sequence = $option->editor_sequence; + else { + if(!$GLOBALS['_editor_sequence_']) $GLOBALS['_editor_sequence_'] = 1; + $editor_sequence = $GLOBALS['_editor_sequence_'] ++; + } + + /** + * 업로드 활성화시 내부적으로 file 모듈의 환경설정을 이용하여 설정 + **/ + $files_count = 0; + if($allow_fileupload) { + $oFileModel = &getModel('file'); + + // SWFUploader에 세팅할 업로드 설정 구함 + $file_config = $oFileModel->getUploadConfig(); + $file_config->allowed_attach_size = $file_config->allowed_attach_size*1024*1024; + $file_config->allowed_filesize = $file_config->allowed_filesize*1024*1024; + + Context::set('file_config',$file_config); + + // 업로드 가능 용량등에 대한 정보를 세팅 + $upload_status = $oFileModel->getUploadStatus(); + Context::set('upload_status', $upload_status); + + // upload가능하다고 설정 (내부적으로 캐싱하여 처리) + $oFileController = &getController('file'); + $oFileController->setUploadInfo($editor_sequence, $upload_target_srl); + + // 이미 등록된 파일이 있는지 검사 + if($upload_target_srl) $files_count = $oFileModel->getFilesCount($upload_target_srl); + } + Context::set('files_count', (int)$files_count); + + Context::set('allow_fileupload', $allow_fileupload); + + // 에디터 동작을 위한 editor_sequence값 설정 + Context::set('editor_sequence', $editor_sequence); + + // 파일 첨부 관련 행동을 하기 위해 문서 번호를 upload_target_srl로 설정 + // 신규문서일 경우 upload_target_srl=0 이고 첨부파일 관련 동작이 요청될때 이 값이 변경됨 + Context::set('upload_target_srl', $upload_target_srl); + + // 문서 혹은 댓글의 primary key값을 세팅한다. + Context::set('editor_primary_key_name', $option->primary_key_name); + + // 내용을 sync 맞추기 위한 content column name을 세팅한다 + Context::set('editor_content_key_name', $option->content_key_name); + + + /** + * 에디터 컴포넌트 체크 + **/ + $site_module_info = Context::get('site_module_info'); + $site_srl = (int)$site_module_info->site_srl; + if($enable_component) { + if(!Context::get('component_list')) { + $component_list = $this->getComponentList(true, $site_srl); + Context::set('component_list', $component_list); + } + } + Context::set('enable_component', $enable_component); + Context::set('enable_default_component', $enable_default_component); + + /** + * html_mode 가능한지 변수 설정 + **/ + Context::set('html_mode', $html_mode); + + /** + * 에디터 세로 크기 설정 + **/ + Context::set('editor_height', $editor_height); + + // 에디터의 초기화를 수동으로하는 것에 대한 값 체크 + Context::set('editor_manual_start', $option->manual_start); + + /** + * 템플릿을 미리 컴파일해서 컴파일된 소스를 하기 위해 스킨의 경로를 설정 + **/ + $tpl_path = sprintf('%sskins/%s/', $this->module_path, $skin); + $tpl_file = 'editor.html'; + + if(!file_exists($tpl_path.$tpl_file)) { + $skin = 'xpresseditor'; + $tpl_path = sprintf('%sskins/%s/', $this->module_path, $skin); + } + Context::set('editor_path', $tpl_path); + + // load editor skin lang + Context::loadLang($tpl_path.'lang'); + + // tpl 파일을 compile한 결과를 return + $oTemplate = new TemplateHandler(); + return $oTemplate->compile($tpl_path, $tpl_file); + } + + /** + * @brief 모듈별 설정이 반영된 에디터 template을 return + * getEditor() 와 동일한 결과물을 return하지만 getModuleEditor()는 각 모듈별 추가 설정을 통해 직접 제어되는 설정을 이용하여 에디터를 생성함 + * + * document/ comment 2가지 종류를 이용함. + * 굳이 나눈 이유는 하나의 모듈에서 2개 종류의 에디터 사용을 위해서인데 게시판이나 블로그등 원글과 그에 연관된 글(댓글)을 위한 용도임. + **/ + 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->content_style = $editor_config->content_style; + $config->content_font = $editor_config->content_font; + $config->content_font_size = $editor_config->content_font_size; + $config->sel_editor_colorset = $editor_config->sel_editor_colorset; + $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_autosave = $editor_config->enable_autosave; + } else { + $config->editor_skin = $editor_config->comment_editor_skin; + $config->content_style = $editor_config->content_style; + $config->content_font = $editor_config->content_font; + $config->content_font_size = $editor_config->content_font_size; + $config->sel_editor_colorset = $editor_config->sel_comment_editor_colorset; + $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_autosave = 'N'; + } + + // 권한 체크를 위한 현재 로그인 사용자의 그룹 설정 체크 + if(Context::get('is_logged')) { + $logged_info = Context::get('logged_info'); + $group_list = $logged_info->group_list; + } else { + $group_list = array(); + } + + // 에디터 옵션 변수를 미리 설정 + $option->skin = $config->editor_skin; + $option->content_style = $config->content_style; + $option->content_font = $config->content_font; + $option->content_font_size = $config->content_font_size; + $option->colorset = $config->sel_editor_colorset; + + // 파일 업로드 권한 체크 + $option->allow_fileupload = false; + if(count($config->upload_file_grant)) { + foreach($group_list as $group_srl => $group_info) { + if(in_array($group_srl, $config->upload_file_grant)) { + $option->allow_fileupload = true; + break; + } + } + } else $option->allow_fileupload = true; + + // 기본 컴포넌트 사용 권한 + $option->enable_default_component = false; + if(count($config->enable_default_component_grant)) { + foreach($group_list as $group_srl => $group_info) { + if(in_array($group_srl, $config->enable_default_component_grant)) { + $option->enable_default_component = true; + break; + } + } + } else $option->enable_default_component = true; + + // 확장 컴포넌트 사용 권한 + $option->enable_component = false; + if(count($config->enable_component_grant)) { + foreach($group_list as $group_srl => $group_info) { + if(in_array($group_srl, $config->enable_component_grant)) { + $option->enable_component = true; + break; + } + } + } else $option->enable_component = true; + + // 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->height = $config->editor_height; + + // 자동 저장 유무 옵션 설정 + $option->enable_autosave = $config->enable_autosave=='Y'?true:false; + + // 기타 설정 + $option->primary_key_name = $primary_key_name; + $option->content_key_name = $content_key_name; + + return $this->getEditor($upload_target_srl, $option); + } + + /** + * @brief 자동저장되어 있는 정보를 가져옴 + **/ + function getSavedDoc($upload_target_srl) { + // 로그인 회원이면 member_srl, 아니면 ipaddress로 저장되어 있는 문서를 찾음 + if(Context::get('is_logged')) { + $logged_info = Context::get('logged_info'); + $auto_save_args->member_srl = $logged_info->member_srl; + } else { + $auto_save_args->ipaddress = $_SERVER['REMOTE_ADDR']; + } + $auto_save_args->module_srl = Context::get('module_srl'); + // module_srl이 없으면 현재 모듈 + if(!$auto_save_args->module_srl) { + $current_module_info = Context::get('current_module_info'); + $auto_save_args->module_srl = $current_module_info->module_srl; + } + + // DB에서 자동저장 데이터 추출 + $output = executeQuery('editor.getSavedDocument', $auto_save_args); + $saved_doc = $output->data; + + // 자동저장한 결과가 없으면 null값 return + if(!$saved_doc) return; + + // 자동저장된 값이 혹시 이미 등록된 글인지 확인 + $oDocumentModel = &getModel('document'); + $oSaved = $oDocumentModel->getDocument($saved_doc->document_srl); + if($oSaved->isExists()) return; + + // 자동저장 데이터에 문서번호가 있고 이 번호에 파일이 있다면 파일을 모두 이동하고 + // 해당 문서 번호를 editor_sequence로 세팅함 + if($saved_doc->document_srl && $upload_target_srl && !Context::get('document_srl')) { + $saved_doc->module_srl = $auto_save_args->module_srl; + $oFileController = &getController('file'); + $oFileController->moveFile($saved_doc->document_srl, $saved_doc->module_srl, $upload_target_srl); + } + else if($upload_target_srl) $saved_doc->document_srl = $upload_target_srl; + + // 자동 저장 데이터 변경 + $oEditorController = &getController('editor'); + $oEditorController->deleteSavedDoc(false); + $oEditorController->doSaveDoc($saved_doc); + + return $saved_doc; + } + + /** + * @brief component의 객체 생성 + **/ + function getComponentObject($component, $editor_sequence = 0, $site_srl = 0) { + if(!$this->loaded_component_list[$component][$editor_sequence]) { + // 해당 컴포넌트의 객체를 생성해서 실행 + $class_path = sprintf('%scomponents/%s/', $this->module_path, $component); + $class_file = sprintf('%s%s.class.php', $class_path, $component); + if(!file_exists($class_file)) return new Object(-1, sprintf(Context::getLang('msg_component_is_not_founded'), $component)); + + // 클래스 파일을 읽은 후 객체 생성 + require_once($class_file); + $eval_str = sprintf('$oComponent = new %s("%s","%s");', $component, $editor_sequence, $class_path); + @eval($eval_str); + if(!$oComponent) return new Object(-1, sprintf(Context::getLang('msg_component_is_not_founded'), $component)); + + // 설정 정보를 추가 + $component_info = $this->getComponent($component, $site_srl); + $oComponent->setInfo($component_info); + $this->loaded_component_list[$component][$editor_sequence] = $oComponent; + } + + return $this->loaded_component_list[$component][$editor_sequence]; + } + + /** + * @brief editor skin 목록을 return + **/ + function getEditorSkinList() { + return FileHandler::readDir('./modules/editor/skins'); + } + + /** + * @brief 에디터 컴포넌트 목록 캐시 파일 이름 return + **/ + function getCacheFile($filter_enabled= true, $site_srl = 0) { + $lang = Context::getLangType(); + $cache_path = _XE_PATH_.'files/cache/editor/cache/'; + if(!is_dir($cache_path)) FileHandler::makeDir($cache_path); + $cache_file = $cache_path.'component_list.' . $lang .'.'; + if($filter_enabled) $cache_file .= 'filter.'; + if($site_srl) $cache_file .= $site_srl.'.'; + $cache_file .= 'php'; + return $cache_file; + } + + /** + * @brief component 목록을 return (DB정보 보함) + **/ + function getComponentList($filter_enabled = true, $site_srl=0) { + $cache_file = $this->getCacheFile($filter_enabled, $site_srl); + if(!file_exists($cache_file)) { + $oEditorController = &getController('editor'); + $oEditorController->makeCache($filter_enabled, $site_srl); + } + + if(!file_exists($cache_file)) return; + @include($cache_file); + + if(count($component_list)) { + foreach($component_list as $key => $val) { + if(!trim($key)) continue; + if(!is_dir(_XE_PATH_.'modules/editor/components/'.$key)) { + FileHandler::removeFile($cache_file); + return $this->getComponentList($filter_enabled, $site_srl); + } + } + + } + return $component_list; + } + + /** + * @brief compnent의 xml+db정보를 구함 + **/ + function getComponent($component_name, $site_srl = 0) { + $args->component_name = $component_name; + + if($site_srl) { + $args->site_srl = $site_srl; + $output = executeQuery('editor.getSiteComponent', $args); + } else { + $output = executeQuery('editor.getComponent', $args); + } + $component = $output->data; + + $component_name = $component->component_name; + + unset($xml_info); + $xml_info = $this->getComponentXmlInfo($component_name); + $xml_info->enabled = $component->enabled; + + $xml_info->target_group = array(); + + $xml_info->mid_list = array(); + + if($component->extra_vars) { + $extra_vars = unserialize($component->extra_vars); + + if($extra_vars->target_group) { + $xml_info->target_group = $extra_vars->target_group; + unset($extra_vars->target_group); + } + + if($extra_vars->mid_list) { + $xml_info->mid_list = $extra_vars->mid_list; + unset($extra_vars->mid_list); + } + + + if($xml_info->extra_vars) { + foreach($xml_info->extra_vars as $key => $val) { + $xml_info->extra_vars->{$key}->value = $extra_vars->{$key}; + } + } + } + + return $xml_info; + } + + /** + * @brief component의 xml정보를 읽음 + **/ + function getComponentXmlInfo($component) { + $lang_type = Context::getLangType(); + + // 요청된 컴포넌트의 xml파일 위치를 구함 + $component_path = sprintf('%s/components/%s/', $this->module_path, $component); + + $xml_file = sprintf('%sinfo.xml', $component_path); + $cache_file = sprintf('./files/cache/editor/%s.%s.php', $component, $lang_type); + + // 캐시된 xml파일이 있으면 include 후 정보 return + if(file_exists($cache_file) && file_exists($xml_file) && filemtime($cache_file) > filemtime($xml_file)) { + include($cache_file); + return $xml_info; + } + + // 캐시된 파일이 없으면 파싱후 캐싱 후 return + $oParser = new XmlParser(); + $xml_doc = $oParser->loadXmlFile($xml_file); + + // 정보 정리 + if($xml_doc->component->version && $xml_doc->component->attrs->version == '0.2') { + $component_info->component_name = $component; + $component_info->title = $xml_doc->component->title->body; + $component_info->description = str_replace('\n', "\n", $xml_doc->component->description->body); + $component_info->version = $xml_doc->component->version->body; + $component_info->date = $xml_doc->component->date->body; + $component_info->homepage = $xml_doc->component->link->body; + $component_info->license = $xml_doc->component->license->body; + $component_info->license_link = $xml_doc->component->license->attrs->link; + + $buff = 'component_name = "%s";', $component_info->component_name); + $buff .= sprintf('$xml_info->title = "%s";', $component_info->title); + $buff .= sprintf('$xml_info->description = "%s";', $component_info->description); + $buff .= sprintf('$xml_info->version = "%s";', $component_info->version); + $buff .= sprintf('$xml_info->date = "%s";', $component_info->date); + $buff .= sprintf('$xml_info->homepage = "%s";', $component_info->homepage); + $buff .= sprintf('$xml_info->license = "%s";', $component_info->license); + $buff .= sprintf('$xml_info->license_link = "%s";', $component_info->license_link); + + // 작성자 정보 + if(!is_array($xml_doc->component->author)) $author_list[] = $xml_doc->component->author; + else $author_list = $xml_doc->component->author; + + for($i=0; $i < count($author_list); $i++) { + $buff .= sprintf('$xml_info->author['.$i.']->name = "%s";', $author_list[$i]->name->body); + $buff .= sprintf('$xml_info->author['.$i.']->email_address = "%s";', $author_list[$i]->attrs->email_address); + $buff .= sprintf('$xml_info->author['.$i.']->homepage = "%s";', $author_list[$i]->attrs->link); + } + + // history + if($xml_doc->component->history) { + if(!is_array($xml_doc->component->history)) $history_list[] = $xml_doc->component->history; + else $history_list = $xml_doc->component->history; + + for($i=0; $i < count($history_list); $i++) { + unset($obj); + sscanf($history_list[$i]->attrs->date, '%d-%d-%d', $date_obj->y, $date_obj->m, $date_obj->d); + $date = sprintf('%04d%02d%02d', $date_obj->y, $date_obj->m, $date_obj->d); + $buff .= sprintf('$xml_info->history['.$i.']->description = "%s";', $history_list[$i]->description->body); + $buff .= sprintf('$xml_info->history['.$i.']->version = "%s";', $history_list[$i]->attrs->version); + $buff .= sprintf('$xml_info->history['.$i.']->date = "%s";', $date); + + if($history_list[$i]->author) { + (!is_array($history_list[$i]->author)) ? $obj->author_list[] = $history_list[$i]->author : $obj->author_list = $history_list[$i]->author; + + for($j=0; $j < count($obj->author_list); $j++) { + $buff .= sprintf('$xml_info->history['.$i.']->author['.$j.']->name = "%s";', $obj->author_list[$j]->name->body); + $buff .= sprintf('$xml_info->history['.$i.']->author['.$j.']->email_address = "%s";', $obj->author_list[$j]->attrs->email_address); + $buff .= sprintf('$xml_info->history['.$i.']->author['.$j.']->homepage = "%s";', $obj->author_list[$j]->attrs->link); + } + } + + if($history_list[$i]->log) { + (!is_array($history_list[$i]->log)) ? $obj->log_list[] = $history_list[$i]->log : $obj->log_list = $history_list[$i]->log; + + for($j=0; $j < count($obj->log_list); $j++) { + $buff .= sprintf('$xml_info->history['.$i.']->logs['.$j.']->text = "%s";', $obj->log_list[$j]->body); + $buff .= sprintf('$xml_info->history['.$i.']->logs['.$j.']->link = "%s";', $obj->log_list[$j]->attrs->link); + } + } + } + } + + + } else { + sscanf($xml_doc->component->author->attrs->date, '%d. %d. %d', $date_obj->y, $date_obj->m, $date_obj->d); + $date = sprintf('%04d%02d%02d', $date_obj->y, $date_obj->m, $date_obj->d); + $xml_info->component_name = $component; + $xml_info->title = $xml_doc->component->title->body; + $xml_info->description = str_replace('\n', "\n", $xml_doc->component->author->description->body); + $xml_info->version = $xml_doc->component->attrs->version; + $xml_info->date = $date; + $xml_info->author->name = $xml_doc->component->author->name->body; + $xml_info->author->email_address = $xml_doc->component->author->attrs->email_address; + $xml_info->author->homepage = $xml_doc->component->author->attrs->link; + + $buff = 'component_name = "%s";', $xml_info->component_name); + $buff .= sprintf('$xml_info->title = "%s";', $xml_info->title); + $buff .= sprintf('$xml_info->description = "%s";', $xml_info->description); + $buff .= sprintf('$xml_info->version = "%s";', $xml_info->version); + $buff .= sprintf('$xml_info->date = "%s";', $xml_info->date); + $buff .= sprintf('$xml_info->author[0]->name = "%s";', $xml_info->author->name); + $buff .= sprintf('$xml_info->author[0]->email_address = "%s";', $xml_info->author->email_address); + $buff .= sprintf('$xml_info->author[0]->homepage = "%s";', $xml_info->author->homepage); + } + + // 추가 변수 정리 (에디터 컴포넌트에서는 text형만 가능) + $extra_vars = $xml_doc->component->extra_vars->var; + if($extra_vars) { + if(!is_array($extra_vars)) $extra_vars = array($extra_vars); + foreach($extra_vars as $key => $val) { + unset($obj); + $key = $val->attrs->name; + $title = $val->title->body; + $description = $val->description->body; + $xml_info->extra_vars->{$key}->title = $title; + $xml_info->extra_vars->{$key}->description = $description; + + $buff .= sprintf('$xml_info->extra_vars->%s->%s = "%s";', $key, 'title', $title); + $buff .= sprintf('$xml_info->extra_vars->%s->%s = "%s";', $key, 'description', $description); + } + } + + $buff .= ' ?>'; + + FileHandler::writeFile($cache_file, $buff, "w"); + + unset($xml_info); + include($cache_file); + return $xml_info; + } + } +?> diff --git a/modules/editor/editor.view.php b/modules/editor/editor.view.php index 29e5f89b8..332cd4933 100644 --- a/modules/editor/editor.view.php +++ b/modules/editor/editor.view.php @@ -21,7 +21,7 @@ Context::addCssFile($this->module_path."tpl/css/editor.css"); // 변수 정리 - $editor_sequence = Context::get('editor_sequence '); + $editor_sequence = Context::get('editor_sequence'); $component = Context::get('component'); $site_module_info = Context::get('site_module_info'); diff --git a/modules/editor/lang/en.lang.php b/modules/editor/lang/en.lang.php index d4b1615fd..00508c8a0 100644 --- a/modules/editor/lang/en.lang.php +++ b/modules/editor/lang/en.lang.php @@ -18,6 +18,7 @@ $lang->component_grant = 'Permission Setting'; $lang->content_style = 'Content Style'; $lang->content_font = 'Content Font'; + $lang->content_font_size = 'Content Font Size'; $lang->about_component = 'About component'; $lang->about_component_grant = 'Selected group(s) will be able to use expanded components of editor.
(Leave them blank if you want all groups to have permission)'; @@ -43,8 +44,9 @@ $lang->editor_height = 'Height of Editor'; $lang->about_editor_skin = 'You may select the skin of editor.'; - $lang->about_content_style = '문서 편집 및 내용 출력시 원하는 서식을 지정할 수 있습니다'; - $lang->about_content_font = '문서 편집 및 내용 출력시 원하는 폰트를 지정할 수 있습니다.
지정하지 않으면 사용자 설정에 따르게 됩니다
,(콤마)로 여러 폰트를 지정할 수 있습니다.'; + $lang->about_content_style = 'You may select style for editting article or displaying content'; + $lang->about_content_font = 'You may select font for editting article or displaying content.
Default font is your own font
Please use comma(,) for multiple input.'; + $lang->about_content_font_size = 'You may select font size for editting article or displaying content.
Please input units such as px or em.'; $lang->about_upload_file_grant = 'Selected group(s) will be able to upload files. (Leave them blank if you want all groups to have permission)'; $lang->about_default_component_grant = 'Selected group(s) will be able to use default components of editor. (Leave them blank if you want all groups to have permission)'; $lang->about_editor_height = 'You may set the height of editor.'; @@ -154,67 +156,69 @@ $lang->edit->hyperlink = 'Hyperlink'; $lang->edit->target_blank = 'New Window'; - $lang->edit->quotestyle1 = '왼쪽 실선'; - $lang->edit->quotestyle2 = '인용부호'; - $lang->edit->quotestyle3 = '실선'; - $lang->edit->quotestyle4 = '실선 + 배경'; - $lang->edit->quotestyle5 = '굵은 실선'; - $lang->edit->quotestyle6 = '점선'; - $lang->edit->quotestyle7 = '점선 + 배경'; - $lang->edit->quotestyle8 = '적용 취소'; + $lang->edit->quotestyle1 = 'Left Solid'; + $lang->edit->quotestyle2 = 'Quote'; + $lang->edit->quotestyle3 = 'Solid'; + $lang->edit->quotestyle4 = 'Solid + Background'; + $lang->edit->quotestyle5 = 'Bold Solid'; + $lang->edit->quotestyle6 = 'Dotted'; + $lang->edit->quotestyle7 = 'Dotted + Background'; + $lang->edit->quotestyle8 = 'Cancel'; - $lang->edit->jumptoedit = '편집 도구모음 건너뛰기'; - $lang->edit->set_sel = '칸 수 지정'; - $lang->edit->row = '행'; - $lang->edit->col = '열'; - $lang->edit->add_one_row = '1행추가'; - $lang->edit->del_one_row = '1행삭제'; - $lang->edit->add_one_col = '1열추가'; - $lang->edit->del_one_col = '1열삭제'; + $lang->edit->jumptoedit = 'Skip Edit Toolbox'; + $lang->edit->set_sel = 'Set Cell Count'; + $lang->edit->row = 'Row'; + $lang->edit->col = 'Column'; + $lang->edit->add_one_row = 'Add 1 Row'; + $lang->edit->del_one_row = 'Remove 1 Row'; + $lang->edit->add_one_col = 'Add 1 Column'; + $lang->edit->del_one_col = 'Remove 1 Column'; - $lang->edit->table_config = '표 속성 지정'; - $lang->edit->border_width = '테두리 굵기'; - $lang->edit->border_color = '테두리 색'; - $lang->edit->add = '더하기'; - $lang->edit->del = '빼기'; - $lang->edit->search_color = '색상찾기'; - $lang->edit->table_backgroundcolor = '표 배경색'; - $lang->edit->special_character = '특수문자'; - $lang->edit->insert_special_character = '특수문자 삽입'; - $lang->edit->close_special_character = '특수문자 레이어 닫기'; - $lang->edit->symbol = '일반기호'; - $lang->edit->number_unit = '숫자와 단위'; - $lang->edit->circle_bracket = '원,괄호'; + $lang->edit->table_config = 'Table Config'; + $lang->edit->border_width = 'Border Width'; + $lang->edit->border_color = 'Border Color'; + $lang->edit->add = 'Add'; + $lang->edit->del = 'Sub'; + $lang->edit->search_color = 'Search Colors'; + $lang->edit->table_backgroundcolor = 'Table Background Color'; + $lang->edit->special_character = 'Special Characters'; + $lang->edit->insert_special_character = 'Insert Special Characters'; + $lang->edit->close_special_character = 'Close Special Characters Layer'; + $lang->edit->symbol = 'Symbols'; + $lang->edit->number_unit = 'Numbers and Units'; + $lang->edit->circle_bracket = 'Circles, Brackets'; $lang->edit->korean = 'Korean'; $lang->edit->greece = 'Greek'; $lang->edit->Latin = 'Latin'; $lang->edit->japan = 'Japanese'; - $lang->edit->selected_symbol = '선택한 기호'; + $lang->edit->selected_symbol = 'Selected Symbols'; $lang->edit->search_replace = 'Find/Replace'; - $lang->edit->close_search_replace = '찾기/바꾸기 레이어 닫기'; + $lang->edit->close_search_replace = 'Close Find/Replace Layer'; $lang->edit->replace_all = 'Replace All'; - $lang->edit->search_words = '찾을단어'; - $lang->edit->replace_words = '바꿀단어'; - $lang->edit->next_search_words = '다음찾기'; - $lang->edit->edit_height_control = '입력창 크기 조절'; + $lang->edit->search_words = 'Words to Find'; + $lang->edit->replace_words = 'Words to Replace'; + $lang->edit->next_search_words = 'Find Next'; + $lang->edit->edit_height_control = 'Set Edit Form Size'; $lang->edit->merge_cells = 'Merge Table Cells'; - $lang->edit->split_row = '행 분할'; - $lang->edit->split_col = '열 분할'; + $lang->edit->split_row = 'Split Row'; + $lang->edit->split_col = 'Split Column'; - $lang->edit->toggle_list = '목록 접기/펼치기'; - $lang->edit->minimize_list = '최소화'; + $lang->edit->toggle_list = 'Fold/Unfold'; + $lang->edit->minimize_list = 'Minimize'; - $lang->edit->move = '이동'; - $lang->edit->materials = '글감보관함'; - $lang->edit->temporary_savings = '임시저장목록'; + $lang->edit->move = 'Move'; + $lang->edit->materials = 'Materials'; + $lang->edit->temporary_savings = 'Temporary Saved List'; - $lang->edit->drag_here = '글감 보관함에 글이 있으면 이곳으로 끌어 넣기 할 수 있습니다.'; + $lang->edit->drag_here = 'You can start writting with a selected paragraph from paragraph toolbar below.
If there is an article in temporary saved list, you can drag it to edit form.'; - $lang->edit->paging_prev = '이전'; - $lang->edit->paging_next = '다음'; - $lang->edit->paging_prev_help = '이전 페이지로 이동합니다.'; - $lang->edit->paging_next_help = '다음 페이지로 이동합니다.'; + $lang->edit->paging_prev = 'Prev'; + $lang->edit->paging_next = 'Next'; + $lang->edit->paging_prev_help = 'Move to previous page.'; + $lang->edit->paging_next_help = 'Move to next page.'; + + $lang->edit->toc = 'Table of Contents'; ?> diff --git a/modules/editor/lang/es.lang.php b/modules/editor/lang/es.lang.php index 786ec7efd..a63168858 100644 --- a/modules/editor/lang/es.lang.php +++ b/modules/editor/lang/es.lang.php @@ -18,6 +18,7 @@ $lang->component_grant = 'Ajuste de las atribuciones'; $lang->content_style = 'Content Style'; $lang->content_font = 'Content Font'; + $lang->content_font_size = '문서 폰트 크기'; $lang->about_component = 'Presentación del componente'; $lang->about_component_grant = 'Usted puede configurar el permiso de utilizar la ampliación de los componentes de editor.
(Todo el mundo tendría permiso si no comprobado)'; @@ -45,6 +46,7 @@ $lang->about_editor_skin = 'Usted puede seleccionar la piel del editor.'; $lang->about_content_style = '문서 편집 및 내용 출력시 원하는 서식을 지정할 수 있습니다'; $lang->about_content_font = '문서 편집 및 내용 출력시 원하는 폰트를 지정할 수 있습니다.
지정하지 않으면 사용자 설정에 따르게 됩니다
,(콤마)로 여러 폰트를 지정할 수 있습니다.'; + $lang->about_content_font_size = '문서 편집 및 내용 출력시 원하는 폰트의 크기를 지정할 수 있습니다.
12px, 1em등 단위까지 포함해서 입력해주세요.'; $lang->about_upload_file_grant = 'Usted puede configurar el permiso de archivo adjunto. (Todo el mundo tendría permiso si no comprobado)'; $lang->about_default_component_grant = 'Usted puede configurar el permiso de uso de los componentes de editor por defecto. (Todo el mundo tendría permiso si no comprobado)'; $lang->about_editor_height = 'Usted puede configurar la altura del editor.'; @@ -207,10 +209,12 @@ $lang->edit->materials = '글감보관함'; $lang->edit->temporary_savings = '임시저장목록'; - $lang->edit->drag_here = '글감 보관함에 글이 있으면 이곳으로 끌어 넣기 할 수 있습니다.'; + $lang->edit->drag_here = '아래의 단락추가 툴바에서 원하는 유형의 단락을 추가해 글 쓰기를 시작하세요.
글감 보관함에 글이 있으면 이곳으로 끌어 넣기 할 수 있습니다.'; $lang->edit->paging_prev = '이전'; $lang->edit->paging_next = '다음'; $lang->edit->paging_prev_help = '이전 페이지로 이동합니다.'; $lang->edit->paging_next_help = '다음 페이지로 이동합니다.'; + + $lang->edit->toc = '목차'; ?> diff --git a/modules/editor/lang/fr.lang.php b/modules/editor/lang/fr.lang.php index 9370d13ab..7486c20e5 100644 --- a/modules/editor/lang/fr.lang.php +++ b/modules/editor/lang/fr.lang.php @@ -18,6 +18,7 @@ $lang->component_grant = 'Configuration de la Permission'; $lang->content_style = 'Content Style'; $lang->content_font = 'Content Font'; + $lang->content_font_size = '문서 폰트 크기'; $lang->about_component = 'Sur le Composant'; $lang->about_component_grant = 'Vous pouvez configurer la Permission d\'utiliser des composants additionnels de l\'Editeur.
(Tout le monde aura la Permission si vous ne cochez rien)'; @@ -45,6 +46,7 @@ $lang->about_editor_skin = 'Vous pouvez choisir l\'habillage de l\'Editeur.'; $lang->about_content_style = '문서 편집 및 내용 출력시 원하는 서식을 지정할 수 있습니다'; $lang->about_content_font = '문서 편집 및 내용 출력시 원하는 폰트를 지정할 수 있습니다.
지정하지 않으면 사용자 설정에 따르게 됩니다
,(콤마)로 여러 폰트를 지정할 수 있습니다.'; + $lang->about_content_font_size = '문서 편집 및 내용 출력시 원하는 폰트의 크기를 지정할 수 있습니다.
12px, 1em등 단위까지 포함해서 입력해주세요.'; $lang->about_upload_file_grant = 'Vous pouvez configurer la permission d\'attacher les fichiers. (Tout le monde aura la permission si vous ne cochez rien)'; $lang->about_default_component_grant = 'Vous pouvez configurer la permission d\'utiliser les Composants Par Défaut de l\'Editeur. (Tout le monde aura la permission si vous ne cochez rien)'; $lang->about_editor_height = 'Vous pouvez configurer l\'hauteur de l\'Editeur.'; @@ -211,10 +213,12 @@ $lang->edit->materials = '글감보관함'; $lang->edit->temporary_savings = '임시저장목록'; - $lang->edit->drag_here = '글감 보관함에 글이 있으면 이곳으로 끌어 넣기 할 수 있습니다.'; + $lang->edit->drag_here = '아래의 단락추가 툴바에서 원하는 유형의 단락을 추가해 글 쓰기를 시작하세요.
글감 보관함에 글이 있으면 이곳으로 끌어 넣기 할 수 있습니다.'; $lang->edit->paging_prev = '이전'; $lang->edit->paging_next = '다음'; $lang->edit->paging_prev_help = '이전 페이지로 이동합니다.'; $lang->edit->paging_next_help = '다음 페이지로 이동합니다.'; + + $lang->edit->toc = '목차'; ?> diff --git a/modules/editor/lang/jp.lang.php b/modules/editor/lang/jp.lang.php index 1e7e25ad6..8f3b98005 100644 --- a/modules/editor/lang/jp.lang.php +++ b/modules/editor/lang/jp.lang.php @@ -5,218 +5,222 @@ * @brief ウィジウィグエディター(editor)モジュールの基本言語パッケージ **/ - $lang->editor = 'ウイジウイグエディター'; - $lang->component_name = 'コンポーネント'; - $lang->component_version = 'バージョン'; - $lang->component_author = '作者'; - $lang->component_link = 'リンク'; - $lang->component_date = '作成日'; - $lang->component_license = 'ライセンス'; - $lang->component_history = '変更履歴'; - $lang->component_description = '説明'; - $lang->component_extra_vars = '設定変数'; - $lang->component_grant = '権限設定'; - $lang->content_style = 'コンテンツスタイル'; - $lang->content_font = 'コンテンツフォント'; + $lang->editor = 'ウイジウイグエディター'; + $lang->component_name = 'コンポーネント'; + $lang->component_version = 'バージョン'; + $lang->component_author = '作者'; + $lang->component_link = 'リンク'; + $lang->component_date = '作成日'; + $lang->component_license = 'ライセンス'; + $lang->component_history = '変更履歴'; + $lang->component_description = '説明'; + $lang->component_extra_vars = '設定変数'; + $lang->component_grant = '権限設定'; + $lang->content_style = 'コンテンツスタイル'; + $lang->content_font = 'コンテンツフォント'; + $lang->content_font_size = '문서 폰트 크기'; - $lang->about_component = 'コンポーネント情報'; - $lang->about_component_grant = '基本コンポーネント以外の拡張コンポーネント機能が利用可能な権限の設定が出来ます。
(選択なしの場合、誰でも利用可能)'; - $lang->about_component_mid = 'エディターコンポーネントが使われる対象を指定します。
(選択なしの場合、全ての対象で利用可能)'; + $lang->about_component = 'コンポーネント情報'; + $lang->about_component_grant = '基本コンポーネント以外の拡張コンポーネント機能が利用可能な権限の設定が出来ます。
(選択なしの場合、誰でも利用可能)'; + $lang->about_component_mid = 'エディターコンポーネントが使われる対象を指定します。
(選択なしの場合、全ての対象で利用可能)'; - $lang->msg_component_is_not_founded = '%s エディターのコンポーネントが見つかりません。'; - $lang->msg_component_is_inserted = '選択されたコンポーネントは既に入力されています。'; - $lang->msg_component_is_first_order = '選択されたコンポーネントは最初に位置しています。'; - $lang->msg_component_is_last_order = '選択されたコンポーネントは最後に位置しています。'; - $lang->msg_load_saved_doc = "自動保存された書き込みがあります。復旧しますか?\n書き終わってから登録すると前の自動保存データは削除されます。"; - $lang->msg_auto_saved = '自動保存されました。'; + $lang->msg_component_is_not_founded = '%s エディターのコンポーネントが見つかりません。'; + $lang->msg_component_is_inserted = '選択されたコンポーネントは既に入力されています。'; + $lang->msg_component_is_first_order = '選択されたコンポーネントは最初に位置しています。'; + $lang->msg_component_is_last_order = '選択されたコンポーネントは最後に位置しています。'; + $lang->msg_load_saved_doc = "自動保存された書き込みがあります。復旧しますか?\n書き終わってから登録すると前の自動保存データは削除されます。"; + $lang->msg_auto_saved = '自動保存されました。'; - $lang->cmd_disable = '未使用'; - $lang->cmd_enable = '使用'; + $lang->cmd_disable = '未使用'; + $lang->cmd_enable = '使用'; - $lang->editor_skin = 'エディタースキン'; - $lang->upload_file_grant = 'ファイル添付権限'; - $lang->enable_default_component_grant = '基本コンポーネント使用権限'; - $lang->enable_component_grant = 'コンポーネント使用権限'; - $lang->enable_html_grant = 'HTML編集権限'; - $lang->enable_autosave = '自動保存使用'; - $lang->height_resizable = '高さの調整'; - $lang->editor_height = 'エディターの高さ'; + $lang->editor_skin = 'エディタースキン'; + $lang->upload_file_grant = 'ファイル添付権限'; + $lang->enable_default_component_grant = '基本コンポーネント使用権限'; + $lang->enable_component_grant = 'コンポーネント使用権限'; + $lang->enable_html_grant = 'HTML編集権限'; + $lang->enable_autosave = '自動保存使用'; + $lang->height_resizable = '高さの調整'; + $lang->editor_height = 'エディターの高さ'; - $lang->about_editor_skin = 'エディターのスキンの選択が出来ます。'; - $lang->about_content_style = 'コンテンツの編集、および内容表示の際のスタイルを指定します。'; - $lang->about_content_font = 'コンテンツの編集、および内容表示の際のフォントを指定します。
指定してない場合、ユーザーの設定を従います。
半角コンマ(,)区切りで複数フォントの登録が出来ます。'; - $lang->about_upload_file_grant = 'ファイル添付可能な権限の設定が出来ます。(選択なしの場合、誰でも添付が可能)'; - $lang->about_default_component_grant = 'エディターでの基本コンポーネントを使用可能な権限の設定が出来ます。(選択なしの場合、誰でも利用可能)'; - $lang->about_editor_height = 'エディターの基本高さを設定します。'; - $lang->about_editor_height_resizable = 'エディターの高さを変更出来るようにします。'; - $lang->about_enable_html_grant = 'HTML編集権限を設定します。'; - $lang->about_enable_autosave = '書き込みのとき、自動保存機能をオンにします。'; + $lang->about_editor_skin = 'エディターのスキンの選択が出来ます。'; + $lang->about_content_style = 'コンテンツの編集、および内容表示の際のスタイルを指定します。'; + $lang->about_content_font = 'コンテンツの編集、および内容表示の際のフォントを指定します。
指定してない場合、ユーザーの設定を従います。
半角コンマ(,)区切りで複数フォントの登録が出来ます。'; + $lang->about_content_font_size = '문서 편집 및 내용 출력시 원하는 폰트의 크기를 지정할 수 있습니다.
12px, 1em등 단위까지 포함해서 입력해주세요.'; + $lang->about_upload_file_grant = 'ファイル添付可能な権限の設定が出来ます。(選択なしの場合、誰でも添付が可能)'; + $lang->about_default_component_grant = 'エディターでの基本コンポーネントを使用可能な権限の設定が出来ます。(選択なしの場合、誰でも利用可能)'; + $lang->about_editor_height = 'エディターの基本高さを設定します。'; + $lang->about_editor_height_resizable = 'エディターの高さを変更出来るようにします。'; + $lang->about_enable_html_grant = 'HTML編集権限を設定します。'; + $lang->about_enable_autosave = '書き込みのとき、自動保存機能をオンにします。'; - $lang->edit->fontname = 'フォント'; - $lang->edit->fontsize = 'フォントサイズ'; - $lang->edit->use_paragraph = '段落機能'; - $lang->edit->fontlist = array( - 'MS PGothic'=>'MS Pゴシック', - 'MS PMincho'=>'MS P明朝', - 'MS UI Gothic'=>'MS UI Gothic', - 'Arial'=>'Arial', - 'Arial Black'=>'Arial Black', - 'Tahoma'=>'Tahoma', - 'Verdana'=>'Verdana', - 'Sans-serif'=>'Sans-serif', - 'Serif'=>'Serif', - 'Monospace'=>'Monospace', - 'Cursive'=>'Cursive', - 'Fantasy'=>'Fantasy', - ); + $lang->edit->fontname = 'フォント'; + $lang->edit->fontsize = 'フォントサイズ'; + $lang->edit->use_paragraph = '段落機能'; + $lang->edit->fontlist = array( + 'MS PGothic' => 'MS Pゴシック', + 'MS PMincho' => 'MS P明朝', + 'MS UI Gothic' => 'MS UI Gothic', + 'Arial' => 'Arial', + 'Arial Black' => 'Arial Black', + 'Tahoma' => 'Tahoma', + 'Verdana' => 'Verdana', + 'Sans-serif' => 'Sans-serif', + 'Serif' => 'Serif', + 'Monospace' => 'Monospace', + 'Cursive' => 'Cursive', + 'Fantasy' => 'Fantasy', + ); - $lang->edit->header = '見出し'; - $lang->edit->header_list = array( - 'h1' => '見出し1', - 'h2' => '見出し2', - 'h3' => '見出し3', - 'h4' => '見出し4', - 'h5' => '見出し5', - 'h6' => '見出し6', - ); + $lang->edit->header = '見出し'; + $lang->edit->header_list = array( + 'h1' => '見出し1', + 'h2' => '見出し2', + 'h3' => '見出し3', + 'h4' => '見出し4', + 'h5' => '見出し5', + 'h6' => '見出し6', + ); - $lang->edit->submit = '送信'; + $lang->edit->submit = '送信'; - $lang->edit->fontcolor = 'テキストの色'; - $lang->edit->fontbgcolor = 'ハイライト カラー'; - $lang->edit->bold = '太字'; - $lang->edit->italic = '斜体'; - $lang->edit->underline = '下線'; - $lang->edit->strike = '取り消し線'; - $lang->edit->sup = '上付き文字'; - $lang->edit->sub = '下付き文字'; - $lang->edit->redo = '繰り返し'; - $lang->edit->undo = '元に戻す'; - $lang->edit->align_left = '左揃え'; - $lang->edit->align_center = '中央揃え'; - $lang->edit->align_right = '右揃え'; - $lang->edit->align_justify = '均等割付'; - $lang->edit->add_indent = 'インデント増'; - $lang->edit->remove_indent = 'インデント減'; - $lang->edit->list_number = '番号付リスト'; - $lang->edit->list_bullet = '箇条書き'; - $lang->edit->remove_format = '書式をクリア'; + $lang->edit->fontcolor = 'テキストの色'; + $lang->edit->fontbgcolor = 'テキストの背景色'; + $lang->edit->bold = '太字'; + $lang->edit->italic = '斜体'; + $lang->edit->underline = '下線'; + $lang->edit->strike = '取り消し線'; + $lang->edit->sup = '上付き文字'; + $lang->edit->sub = '下付き文字'; + $lang->edit->redo = '繰り返し'; + $lang->edit->undo = '元に戻す'; + $lang->edit->align_left = '左揃え'; + $lang->edit->align_center = '中央揃え'; + $lang->edit->align_right = '右揃え'; + $lang->edit->align_justify = '均等割付'; + $lang->edit->add_indent = 'インデント増'; + $lang->edit->remove_indent = 'インデント減'; + $lang->edit->list_number = '番号付リスト'; + $lang->edit->list_bullet = '箇条書き'; + $lang->edit->remove_format = '書式をクリア'; - $lang->edit->help_remove_format = '選択領域の中のタグを消します。'; - $lang->edit->help_strike_through = 'テキストに取り消し線を表示します。'; - $lang->edit->help_align_full = '左右の余白に合わせて文字列を配置します。'; + $lang->edit->help_remove_format = '選択領域の中のタグを消します。'; + $lang->edit->help_strike_through = 'テキストに取り消し線を表示します。'; + $lang->edit->help_align_full = '左右の余白に合わせて文字列を配置します。'; - $lang->edit->help_fontcolor = 'テキストの色を指定します。'; - $lang->edit->help_fontbgcolor = 'テキストの背景色を指定します。'; - $lang->edit->help_bold = 'テキストを太字に指定します。'; - $lang->edit->help_italic = 'テキストを斜体にします。'; - $lang->edit->help_underline = 'テキストに下線(アンダーライン)を引きます。'; - $lang->edit->help_strike = '取り消し線を引きます。'; - $lang->edit->help_sup = '上付き文字'; - $lang->edit->help_sub = '下付き文字'; - $lang->edit->help_redo = '繰り返し'; - $lang->edit->help_undo = '元に戻す'; - $lang->edit->help_align_left = 'テキストを左揃えで表示します。'; - $lang->edit->help_align_center = 'テキストを中央揃えで表示します。'; - $lang->edit->help_align_right = 'テキストを右揃えで表示します。'; - $lang->edit->help_add_indent = 'インデントを増やします。'; - $lang->edit->help_remove_indent = 'インデントを減らします。'; - $lang->edit->help_list_number = '番号付リスト'; - $lang->edit->help_list_bullet = '箇条書き'; - $lang->edit->help_use_paragraph = '段落機能を使用する場合は、「Ctrl+Enter」を押します(書き終わった後、「Alt+S」を押すと保存されます)。'; + $lang->edit->help_fontcolor = 'テキストの色を指定します。'; + $lang->edit->help_fontbgcolor = 'テキストの背景色を指定します。'; + $lang->edit->help_bold = 'テキストを太字に指定します。'; + $lang->edit->help_italic = 'テキストを斜体にします。'; + $lang->edit->help_underline = 'テキストに下線(アンダーライン)を引きます。'; + $lang->edit->help_strike = '取り消し線を引きます。'; + $lang->edit->help_sup = '上付き文字'; + $lang->edit->help_sub = '下付き文字'; + $lang->edit->help_redo = '繰り返し'; + $lang->edit->help_undo = '元に戻す'; + $lang->edit->help_align_left = 'テキストを左揃えで表示します。'; + $lang->edit->help_align_center = 'テキストを中央揃えで表示します。'; + $lang->edit->help_align_right = 'テキストを右揃えで表示します。'; + $lang->edit->help_add_indent = 'インデントを増やします。'; + $lang->edit->help_remove_indent = 'インデントを減らします。'; + $lang->edit->help_list_number = '番号付リスト'; + $lang->edit->help_list_bullet = '箇条書き'; + $lang->edit->help_use_paragraph = '段落機能を使用する場合は、「Ctrl+Enter」を押します(書き終わった後、「Alt+S」を押すと保存されます)。'; - $lang->edit->url = 'リンク'; - $lang->edit->blockquote = '引用文'; - $lang->edit->table = '表'; - $lang->edit->image = 'イメージ'; - $lang->edit->multimedia = '動画'; - $lang->edit->emoticon = '絵文字'; + $lang->edit->url = 'リンク'; + $lang->edit->blockquote = '引用文'; + $lang->edit->table = '表'; + $lang->edit->image = 'イメージ'; + $lang->edit->multimedia = '動画'; + $lang->edit->emoticon = '絵文字'; - $lang->edit->upload = '添付'; - $lang->edit->upload_file = 'ファイル添付'; - $lang->edit->link_file = 'テキスト挿入'; - $lang->edit->delete_selected = '選択リスト削除'; + $lang->edit->upload = '添付'; + $lang->edit->upload_file = 'ファイル添付'; + $lang->edit->link_file = 'テキスト挿入'; + $lang->edit->delete_selected = '選択リスト削除'; - $lang->edit->icon_align_article = '一段落'; - $lang->edit->icon_align_left = '左揃え'; - $lang->edit->icon_align_middle = '中央揃え'; - $lang->edit->icon_align_right = '右揃え'; + $lang->edit->icon_align_article = '一段落'; + $lang->edit->icon_align_left = '左揃え'; + $lang->edit->icon_align_middle = '中央揃え'; + $lang->edit->icon_align_right = '右揃え'; - $lang->about_dblclick_in_editor = '背景、文字、イメージ、引用文の上にカーソルを合わせ、ダブルクリックすると詳細設定出来るコンポーネントを表示します。'; + $lang->about_dblclick_in_editor = '背景、文字、イメージ、引用文の上にカーソルを合わせ、ダブルクリックすると詳細設定出来るコンポーネントを表示します。'; - $lang->edit->rich_editor = 'ウイジウイグ編集'; - $lang->edit->html_editor = 'HTMLタグ編集'; - $lang->edit->extension ='拡張コンポーネント'; - $lang->edit->help = 'ヘルプ'; - $lang->edit->help_command = 'ショートカット‐キーの説明'; + $lang->edit->rich_editor = 'ウイジウイグ編集'; + $lang->edit->html_editor = 'HTMLタグ編集'; + $lang->edit->extension ='拡張コンポーネント'; + $lang->edit->help = 'ヘルプ'; + $lang->edit->help_command = 'ショートカット‐キーの説明'; - $lang->edit->lineheight = '行間'; - $lang->edit->fontbgsampletext = 'あいうえお'; + $lang->edit->lineheight = '行間'; + $lang->edit->fontbgsampletext = 'あいうえお'; - $lang->edit->hyperlink = 'ハイパーリンク'; - $lang->edit->target_blank = '別のウィンドウズで'; + $lang->edit->hyperlink = 'ハイパーリンク'; + $lang->edit->target_blank = '別のウィンドウズで'; - $lang->edit->quotestyle1 = '左側実線'; - $lang->edit->quotestyle2 = '引用記号'; - $lang->edit->quotestyle3 = '実線'; - $lang->edit->quotestyle4 = '実線 + 背景'; - $lang->edit->quotestyle5 = '太い実線'; - $lang->edit->quotestyle6 = '点線'; - $lang->edit->quotestyle7 = '点線 + 背景'; - $lang->edit->quotestyle8 = '適用取り消し'; + $lang->edit->quotestyle1 = '左側実線'; + $lang->edit->quotestyle2 = '引用記号'; + $lang->edit->quotestyle3 = '実線'; + $lang->edit->quotestyle4 = '実線 + 背景'; + $lang->edit->quotestyle5 = '太い実線'; + $lang->edit->quotestyle6 = '点線'; + $lang->edit->quotestyle7 = '点線 + 背景'; + $lang->edit->quotestyle8 = '適用取り消し'; - $lang->edit->jumptoedit = '編集ツール省略'; - $lang->edit->set_sel = 'マス数の指定'; - $lang->edit->row = '行'; - $lang->edit->col = '列'; - $lang->edit->add_one_row = '1行追加'; - $lang->edit->del_one_row = '1行削除'; - $lang->edit->add_one_col = '1列追加'; - $lang->edit->del_one_col = '1列削除'; + $lang->edit->jumptoedit = '編集ツール省略'; + $lang->edit->set_sel = 'マス数の指定'; + $lang->edit->row = '行'; + $lang->edit->col = '列'; + $lang->edit->add_one_row = '1行追加'; + $lang->edit->del_one_row = '1行削除'; + $lang->edit->add_one_col = '1列追加'; + $lang->edit->del_one_col = '1列削除'; - $lang->edit->table_config = '표属性の設定'; - $lang->edit->border_width = '外枠太さ'; - $lang->edit->border_color = '外枠色'; - $lang->edit->add = '挿入'; - $lang->edit->del = '削除'; - $lang->edit->search_color = 'その他の色'; - $lang->edit->table_backgroundcolor = '表の背景色'; - $lang->edit->special_character = '特殊文字'; - $lang->edit->insert_special_character = '特殊文字挿入'; - $lang->edit->close_special_character = '特殊文字レイヤーを閉じる'; - $lang->edit->symbol = '一般記号'; - $lang->edit->number_unit = '数字と単位'; - $lang->edit->circle_bracket = '円、括弧'; - $lang->edit->korean = '韓国語'; - $lang->edit->greece = 'ギリシャ語'; - $lang->edit->Latin = 'ラテン語'; - $lang->edit->japan = '日本語'; - $lang->edit->selected_symbol = '選択した記号'; + $lang->edit->table_config = 'テーブル属性の設定'; + $lang->edit->border_width = '外枠太さ'; + $lang->edit->border_color = '外枠色'; + $lang->edit->add = '挿入'; + $lang->edit->del = '削除'; + $lang->edit->search_color = 'その他の色'; + $lang->edit->table_backgroundcolor = '表の背景色'; + $lang->edit->special_character = '特殊文字'; + $lang->edit->insert_special_character = '特殊文字挿入'; + $lang->edit->close_special_character = '特殊文字レイヤーを閉じる'; + $lang->edit->symbol = '一般記号'; + $lang->edit->number_unit = '数字と単位'; + $lang->edit->circle_bracket = '円、括弧'; + $lang->edit->korean = '韓国語'; + $lang->edit->greece = 'ギリシャ語'; + $lang->edit->Latin = 'ラテン語'; + $lang->edit->japan = '日本語'; + $lang->edit->selected_symbol = '選択した記号'; - $lang->edit->search_replace = '検索/置換'; - $lang->edit->close_search_replace = '検索/置換レイヤーを閉じる'; - $lang->edit->replace_all = 'すべて置換'; - $lang->edit->search_words = '検索テキスト'; - $lang->edit->replace_words = '置換テキスト'; - $lang->edit->next_search_words = '次を検索'; - $lang->edit->edit_height_control = '入力サイズ調整'; - - $lang->edit->merge_cells = 'セルの結合'; - $lang->edit->split_row = '行の挿入'; - $lang->edit->split_col = '列の挿入'; + $lang->edit->search_replace = '検索/置換'; + $lang->edit->close_search_replace = '検索/置換レイヤーを閉じる'; + $lang->edit->replace_all = 'すべて置換'; + $lang->edit->search_words = '検索テキスト'; + $lang->edit->replace_words = '置換テキスト'; + $lang->edit->next_search_words = '次を検索'; + $lang->edit->edit_height_control = '入力サイズ調整'; + + $lang->edit->merge_cells = 'セルの結合'; + $lang->edit->split_row = '行の挿入'; + $lang->edit->split_col = '列の挿入'; + + $lang->edit->toggle_list = 'リストを折りたたむ/展開する'; + $lang->edit->minimize_list = '最小化'; + + $lang->edit->move = '移動'; + $lang->edit->materials = '文面テンプレート保存箱'; + $lang->edit->temporary_savings = '下書きリスト'; - $lang->edit->toggle_list = '목록 접기/펼치기'; - $lang->edit->minimize_list = '최소화'; - - $lang->edit->move = '이동'; - $lang->edit->materials = '글감보관함'; - $lang->edit->temporary_savings = '임시저장목록'; - - $lang->edit->drag_here = '글감 보관함에 글이 있으면 이곳으로 끌어 넣기 할 수 있습니다.'; + $lang->edit->drag_here = '下の段落追加ツールバーから、好きなタイプの段落を追加してから書き込みを始めて下さい。
文面テンプレート保存箱の中からここにドラッグ・アンド・ドロップ出来ます。'; - $lang->edit->paging_prev = '이전'; - $lang->edit->paging_next = '다음'; - $lang->edit->paging_prev_help = '이전 페이지로 이동합니다.'; - $lang->edit->paging_next_help = '다음 페이지로 이동합니다.'; + $lang->edit->paging_prev = '前へ'; + $lang->edit->paging_next = '次へ'; + $lang->edit->paging_prev_help = '前のページへ移動します。'; + $lang->edit->paging_next_help = '次のページへ移動します。'; + + $lang->edit->toc = 'リスト'; ?> diff --git a/modules/editor/lang/ko.lang.php b/modules/editor/lang/ko.lang.php index dcae5fcf0..8735b17f6 100644 --- a/modules/editor/lang/ko.lang.php +++ b/modules/editor/lang/ko.lang.php @@ -1,222 +1,227 @@ - - * @brief 위지윅에디터(editor) 모듈의 기본 언어팩 - **/ - - $lang->editor = '위지윅 에디터'; - $lang->component_name = '컴포넌트'; - $lang->component_version = '버전'; - $lang->component_author = '제작자 '; - $lang->component_link = '링크'; - $lang->component_date = '제작일'; - $lang->component_license = '라이선스'; - $lang->component_history = '변경 이력'; - $lang->component_description = '설명'; - $lang->component_extra_vars = '설정 변수'; - $lang->component_grant = '권한설정'; - $lang->content_style = '문서 서식'; - $lang->content_font = '문서 폰트'; - - $lang->about_component = '컴포넌트 소개'; - $lang->about_component_grant = '기본 컴포넌트외의 확장 컴포넌트 기능을 사용할 수 있는 권한을 지정할 수 있습니다.
(모두 해제시 아무나 사용 가능합니다)'; - $lang->about_component_mid = '에디터 컴포넌트가 사용될 대상을 지정할 수 있습니다.
(모두 해제 시 모든 대상에서 사용 가능합니다)'; - - $lang->msg_component_is_not_founded = '%s 에디터 컴포넌트를 찾을 수 없습니다.'; - $lang->msg_component_is_inserted = '선택하신 컴포넌트는 이미 입력되어 있습니다.'; - $lang->msg_component_is_first_order = '선택하신 컴포넌트는 첫번째에 위치하고 있습니다.'; - $lang->msg_component_is_last_order = '선택하신 컴포넌트는 마지막에 위치하고 있습니다.'; - $lang->msg_load_saved_doc = "자동 저장된 글이 있습니다. 복구하시겠습니까?\n글을 다 쓰신 후 저장하시면 자동 저장본은 사라집니다."; - $lang->msg_auto_saved = '자동 저장되었습니다.'; - - $lang->cmd_disable = '비활성'; - $lang->cmd_enable = '활성'; - - $lang->editor_skin = '에디터 스킨'; - $lang->upload_file_grant = '파일 첨부 권한'; - $lang->enable_default_component_grant = '기본 컴포넌트 사용 권한'; - $lang->enable_component_grant = '컴포넌트 사용 권한'; - $lang->enable_html_grant = 'HTML편집 권한'; - $lang->enable_autosave = '자동저장 사용'; - $lang->height_resizable = '높이 조절 가능'; - $lang->editor_height = '에디터 높이'; - - $lang->about_editor_skin = '에디터 스킨을 선택하실 수 있습니다'; - $lang->about_content_style = '문서 편집 및 내용 출력시 원하는 서식을 지정할 수 있습니다'; - $lang->about_content_font = '문서 편집 및 내용 출력시 원하는 폰트를 지정할 수 있습니다.
지정하지 않으면 사용자 설정에 따르게 됩니다
,(콤마)로 여러 폰트를 지정할 수 있습니다.'; - $lang->about_upload_file_grant = '파일을 첨부할 수 있는 권한을 지정하실 수 있습니다. (모두 해제 시 아무나 첨부 가능합니다)'; - $lang->about_default_component_grant = '에디터에서 사용되는 기본 컴포넌트를 사용할 수 있는 권한을 지정할 수 있습니다. (모두 해제 시 아무나 사용 가능합니다)'; - $lang->about_editor_height = '에디터의 기본 높이를 지정하실 수 있습니다.'; - $lang->about_editor_height_resizable = '에디터의 높이를 직접 변경할 수 있도록 허용합니다.'; - $lang->about_enable_html_grant = 'HTML편집 권한을 부여할 수 있습니다.'; - $lang->about_enable_autosave = '글 작성시 자동 저장 기능을 활성화 시킬 수 있습니다.'; - - $lang->edit->fontname = '글꼴'; - $lang->edit->fontsize = '크기'; - $lang->edit->use_paragraph = '문단기능'; - $lang->edit->fontlist = array( - 'Dotum' => '돋움', - 'Gulim' => '굴림', - 'Batang' => '바탕', - 'Arial' => 'Arial', - 'Arial Black' => 'Arial Black', - 'Tahoma' => 'Tahoma', - 'Verdana' => 'Verdana', - 'Sans-serif' => 'Sans-serif', - 'Serif' => 'Serif', - 'Monospace' => 'Monospace', - 'Cursive' => 'Cursive', - 'Fantasy' => 'Fantasy', - ); - - $lang->edit->header = '형식'; - $lang->edit->header_list = array( - 'h1' => '제목 1', - 'h2' => '제목 2', - 'h3' => '제목 3', - 'h4' => '제목 4', - 'h5' => '제목 5', - 'h6' => '제목 6', - ); - - $lang->edit->submit = '확인'; - - $lang->edit->fontcolor = '글자 색'; - $lang->edit->fontbgcolor = '글자 배경색'; - $lang->edit->bold = '진하게'; - $lang->edit->italic = '기울임'; - $lang->edit->underline = '밑줄'; - $lang->edit->strike = '취소선'; - $lang->edit->sup = '위 첨자'; - $lang->edit->sub = '아래 첨자'; - $lang->edit->redo = '다시 실행'; - $lang->edit->undo = '되돌리기'; - $lang->edit->align_left = '왼쪽 정렬'; - $lang->edit->align_center = '가운데 정렬'; - $lang->edit->align_right = '오른쪽 정렬'; - $lang->edit->align_justify = '양쪽 정렬'; - $lang->edit->add_indent = '들여쓰기'; - $lang->edit->remove_indent = '내어쓰기'; - $lang->edit->list_number = '번호 매기기'; - $lang->edit->list_bullet = '목록'; - $lang->edit->remove_format = '글맵시 지우기'; - - $lang->edit->help_remove_format = '선택된 영역 내의 태그를 지웁니다.'; - $lang->edit->help_strike_through = '글자에 취소선을 표시합니다.'; - $lang->edit->help_align_full = '좌우 폭에 맞게 정렬을 합니다.'; - - $lang->edit->help_fontcolor = '글자의 색상을 지정합니다.'; - $lang->edit->help_fontbgcolor = '글자의 배경색상을 지정합니다.'; - $lang->edit->help_bold = '글자를 진하게 합니다.'; - $lang->edit->help_italic = '글자를 기울이게 합니다.'; - $lang->edit->help_underline = '밑줄을 긋습니다.'; - $lang->edit->help_strike = '취소선을 긋습니다.'; - $lang->edit->help_sup = '위 첨자를 입력합니다.'; - $lang->edit->help_sub = '아래 첨자를 입력합니다.'; - $lang->edit->help_redo = '다음 동작으로 돌아갑니다.'; - $lang->edit->help_undo = '이전 동작으로 돌아갑니다.'; - $lang->edit->help_align_left = '왼쪽 정렬을 합니다.'; - $lang->edit->help_align_center = '가운데 정렬을 합니다.'; - $lang->edit->help_align_right = '오른쪽 정렬을 합니다.'; - $lang->edit->help_add_indent = '단락의 들여쓰기 수준을 높입니다.'; - $lang->edit->help_remove_indent = '단락의 들여쓰기 수준을 낮춥니다.'; - $lang->edit->help_list_number = '숫자로된 목록을 적용합니다.'; - $lang->edit->help_list_bullet = '기호로된 목록을 적용합니다.'; - $lang->edit->help_use_paragraph = '문단 나누기를 하시려면 Ctrl+Enter를 누르시면 됩니다. (글 작성완료 후 Alt+S를 누르면 저장이 됩니다.)'; - - $lang->edit->url = '링크'; - $lang->edit->blockquote = '인용문'; - $lang->edit->table = '표'; - $lang->edit->image = '그림'; - $lang->edit->multimedia = '동영상'; - $lang->edit->emoticon = '이모티콘'; - - $lang->edit->upload = '첨부'; - $lang->edit->upload_file = '파일 첨부'; - $lang->edit->link_file = '본문 삽입'; - $lang->edit->delete_selected = '선택 삭제'; - - $lang->edit->icon_align_article = '한 문단을 차지'; - $lang->edit->icon_align_left = '글의 왼쪽으로'; - $lang->edit->icon_align_middle = '가운데 정렬'; - $lang->edit->icon_align_right = '글의 우측으로'; - - $lang->about_dblclick_in_editor = '배경, 글자, 이미지, 인용문등에서 더블클릭을 하시면 상세한 컴포넌트 설정이 가능합니다.'; - - $lang->edit->rich_editor = '스타일 편집기'; - $lang->edit->html_editor = 'HTML 편집기'; - $lang->edit->extension ='확장 컴포넌트'; - $lang->edit->help = '도움말'; - $lang->edit->help_command = '단축키 안내'; - - $lang->edit->lineheight = '줄간격'; - $lang->edit->fontbgsampletext = '가나다'; - - $lang->edit->hyperlink = '하이퍼링크'; - $lang->edit->target_blank = '새창으로'; - - $lang->edit->quotestyle1 = '왼쪽 실선'; - $lang->edit->quotestyle2 = '인용 부호'; - $lang->edit->quotestyle3 = '실선'; - $lang->edit->quotestyle4 = '실선 + 배경'; - $lang->edit->quotestyle5 = '굵은 실선'; - $lang->edit->quotestyle6 = '점선'; - $lang->edit->quotestyle7 = '점선 + 배경'; - $lang->edit->quotestyle8 = '적용 취소'; - - - $lang->edit->jumptoedit = '편집 도구모음 건너뛰기'; - $lang->edit->set_sel = '칸 수 지정'; - $lang->edit->row = '행'; - $lang->edit->col = '열'; - $lang->edit->add_one_row = '1행추가'; - $lang->edit->del_one_row = '1행삭제'; - $lang->edit->add_one_col = '1열추가'; - $lang->edit->del_one_col = '1열삭제'; - - $lang->edit->table_config = '표 속성 지정'; - $lang->edit->border_width = '테두리 굵기'; - $lang->edit->border_color = '테두리 색'; - $lang->edit->add = '더하기'; - $lang->edit->del = '빼기'; - $lang->edit->search_color = '색상찾기'; - $lang->edit->table_backgroundcolor = '표 배경색'; - $lang->edit->special_character = '특수문자'; - $lang->edit->insert_special_character = '특수문자 삽입'; - $lang->edit->close_special_character = '특수문자 레이어 닫기'; - $lang->edit->symbol = '일반기호'; - $lang->edit->number_unit = '숫자와 단위'; - $lang->edit->circle_bracket = '원,괄호'; - $lang->edit->korean = '한글'; - $lang->edit->greece = '그리스'; - $lang->edit->Latin = '라틴어'; - $lang->edit->japan = '일본어'; - $lang->edit->selected_symbol = '선택한 기호'; - - $lang->edit->search_replace = '찾기/바꾸기'; - $lang->edit->close_search_replace = '찾기/바꾸기 레이어 닫기'; - $lang->edit->replace_all = '모두바꾸기'; - $lang->edit->search_words = '찾을단어'; - $lang->edit->replace_words = '바꿀단어'; - $lang->edit->next_search_words = '다음찾기'; - $lang->edit->edit_height_control = '입력창 크기 조절'; - - $lang->edit->merge_cells = '셀 병합'; - $lang->edit->split_row = '행 분할'; - $lang->edit->split_col = '열 분할'; - - $lang->edit->toggle_list = '목록 접기/펼치기'; - $lang->edit->minimize_list = '최소화'; - - $lang->edit->move = '이동'; - $lang->edit->materials = '글감보관함'; - $lang->edit->temporary_savings = '임시저장목록'; - - $lang->edit->drag_here = '글감 보관함에 글이 있으면 이곳으로 끌어 넣기 할 수 있습니다.'; - - $lang->edit->paging_prev = '이전'; - $lang->edit->paging_next = '다음'; - $lang->edit->paging_prev_help = '이전 페이지로 이동합니다.'; - $lang->edit->paging_next_help = '다음 페이지로 이동합니다.'; -?> + + * @brief 위지윅에디터(editor) 모듈의 기본 언어팩 + **/ + + $lang->editor = '위지윅 에디터'; + $lang->component_name = '컴포넌트'; + $lang->component_version = '버전'; + $lang->component_author = '제작자 '; + $lang->component_link = '링크'; + $lang->component_date = '제작일'; + $lang->component_license = '라이선스'; + $lang->component_history = '변경 이력'; + $lang->component_description = '설명'; + $lang->component_extra_vars = '설정 변수'; + $lang->component_grant = '권한설정'; + $lang->content_style = '문서 서식'; + $lang->content_font = '문서 폰트'; + $lang->content_font_size = '문서 폰트 크기'; + + $lang->about_component = '컴포넌트 소개'; + $lang->about_component_grant = '기본 컴포넌트외의 확장 컴포넌트 기능을 사용할 수 있는 권한을 지정할 수 있습니다.
(모두 해제시 아무나 사용 가능합니다)'; + $lang->about_component_mid = '에디터 컴포넌트가 사용될 대상을 지정할 수 있습니다.
(모두 해제 시 모든 대상에서 사용 가능합니다)'; + + $lang->msg_component_is_not_founded = '%s 에디터 컴포넌트를 찾을 수 없습니다.'; + $lang->msg_component_is_inserted = '선택하신 컴포넌트는 이미 입력되어 있습니다.'; + $lang->msg_component_is_first_order = '선택하신 컴포넌트는 첫번째에 위치하고 있습니다.'; + $lang->msg_component_is_last_order = '선택하신 컴포넌트는 마지막에 위치하고 있습니다.'; + $lang->msg_load_saved_doc = "자동 저장된 글이 있습니다. 복구하시겠습니까?\n글을 다 쓰신 후 저장하시면 자동 저장본은 사라집니다."; + $lang->msg_auto_saved = '자동 저장되었습니다.'; + + $lang->cmd_disable = '비활성'; + $lang->cmd_enable = '활성'; + + $lang->editor_skin = '에디터 스킨'; + $lang->upload_file_grant = '파일 첨부 권한'; + $lang->enable_default_component_grant = '기본 컴포넌트 사용 권한'; + $lang->enable_component_grant = '컴포넌트 사용 권한'; + $lang->enable_html_grant = 'HTML편집 권한'; + $lang->enable_autosave = '자동저장 사용'; + $lang->height_resizable = '높이 조절 가능'; + $lang->editor_height = '에디터 높이'; + + $lang->about_editor_skin = '에디터 스킨을 선택하실 수 있습니다'; + $lang->about_content_style = '문서 편집 및 내용 출력시 원하는 서식을 지정할 수 있습니다'; + $lang->about_content_font = '문서 편집 및 내용 출력시 원하는 폰트를 지정할 수 있습니다.
지정하지 않으면 사용자 설정에 따르게 됩니다
,(콤마)로 여러 폰트를 지정할 수 있습니다.'; + $lang->about_content_font_size = '문서 편집 및 내용 출력시 원하는 폰트의 크기를 지정할 수 있습니다.
12px, 1em등 단위까지 포함해서 입력해주세요.'; + $lang->about_upload_file_grant = '파일을 첨부할 수 있는 권한을 지정하실 수 있습니다. (모두 해제 시 아무나 첨부 가능합니다)'; + $lang->about_default_component_grant = '에디터에서 사용되는 기본 컴포넌트를 사용할 수 있는 권한을 지정할 수 있습니다. (모두 해제 시 아무나 사용 가능합니다)'; + $lang->about_editor_height = '에디터의 기본 높이를 지정하실 수 있습니다.'; + $lang->about_editor_height_resizable = '에디터의 높이를 직접 변경할 수 있도록 허용합니다.'; + $lang->about_enable_html_grant = 'HTML편집 권한을 부여할 수 있습니다.'; + $lang->about_enable_autosave = '글 작성시 자동 저장 기능을 활성화 시킬 수 있습니다.'; + + $lang->edit->fontname = '글꼴'; + $lang->edit->fontsize = '크기'; + $lang->edit->use_paragraph = '문단기능'; + $lang->edit->fontlist = array( + 'Dotum' => '돋움', + 'Gulim' => '굴림', + 'Batang' => '바탕', + 'Arial' => 'Arial', + 'Arial Black' => 'Arial Black', + 'Tahoma' => 'Tahoma', + 'Verdana' => 'Verdana', + 'Sans-serif' => 'Sans-serif', + 'Serif' => 'Serif', + 'Monospace' => 'Monospace', + 'Cursive' => 'Cursive', + 'Fantasy' => 'Fantasy', + ); + + $lang->edit->header = '형식'; + $lang->edit->header_list = array( + 'h1' => '제목 1', + 'h2' => '제목 2', + 'h3' => '제목 3', + 'h4' => '제목 4', + 'h5' => '제목 5', + 'h6' => '제목 6', + ); + + $lang->edit->submit = '확인'; + + $lang->edit->fontcolor = '글자 색'; + $lang->edit->fontbgcolor = '글자 배경색'; + $lang->edit->bold = '진하게'; + $lang->edit->italic = '기울임'; + $lang->edit->underline = '밑줄'; + $lang->edit->strike = '취소선'; + $lang->edit->sup = '위 첨자'; + $lang->edit->sub = '아래 첨자'; + $lang->edit->redo = '다시 실행'; + $lang->edit->undo = '되돌리기'; + $lang->edit->align_left = '왼쪽 정렬'; + $lang->edit->align_center = '가운데 정렬'; + $lang->edit->align_right = '오른쪽 정렬'; + $lang->edit->align_justify = '양쪽 정렬'; + $lang->edit->add_indent = '들여쓰기'; + $lang->edit->remove_indent = '내어쓰기'; + $lang->edit->list_number = '번호 매기기'; + $lang->edit->list_bullet = '목록'; + $lang->edit->remove_format = '글맵시 지우기'; + + $lang->edit->help_remove_format = '선택된 영역 내의 태그를 지웁니다.'; + $lang->edit->help_strike_through = '글자에 취소선을 표시합니다.'; + $lang->edit->help_align_full = '좌우 폭에 맞게 정렬을 합니다.'; + + $lang->edit->help_fontcolor = '글자의 색상을 지정합니다.'; + $lang->edit->help_fontbgcolor = '글자의 배경색상을 지정합니다.'; + $lang->edit->help_bold = '글자를 진하게 합니다.'; + $lang->edit->help_italic = '글자를 기울이게 합니다.'; + $lang->edit->help_underline = '밑줄을 긋습니다.'; + $lang->edit->help_strike = '취소선을 긋습니다.'; + $lang->edit->help_sup = '위 첨자를 입력합니다.'; + $lang->edit->help_sub = '아래 첨자를 입력합니다.'; + $lang->edit->help_redo = '다음 동작으로 돌아갑니다.'; + $lang->edit->help_undo = '이전 동작으로 돌아갑니다.'; + $lang->edit->help_align_left = '왼쪽 정렬을 합니다.'; + $lang->edit->help_align_center = '가운데 정렬을 합니다.'; + $lang->edit->help_align_right = '오른쪽 정렬을 합니다.'; + $lang->edit->help_add_indent = '단락의 들여쓰기 수준을 높입니다.'; + $lang->edit->help_remove_indent = '단락의 들여쓰기 수준을 낮춥니다.'; + $lang->edit->help_list_number = '숫자로된 목록을 적용합니다.'; + $lang->edit->help_list_bullet = '기호로된 목록을 적용합니다.'; + $lang->edit->help_use_paragraph = '문단 나누기를 하시려면 Ctrl+Enter를 누르시면 됩니다. (글 작성완료 후 Alt+S를 누르면 저장이 됩니다.)'; + + $lang->edit->url = '링크'; + $lang->edit->blockquote = '인용문'; + $lang->edit->table = '표'; + $lang->edit->image = '그림'; + $lang->edit->multimedia = '동영상'; + $lang->edit->emoticon = '이모티콘'; + + $lang->edit->upload = '첨부'; + $lang->edit->upload_file = '파일 첨부'; + $lang->edit->link_file = '본문 삽입'; + $lang->edit->delete_selected = '선택 삭제'; + + $lang->edit->icon_align_article = '한 문단을 차지'; + $lang->edit->icon_align_left = '글의 왼쪽으로'; + $lang->edit->icon_align_middle = '가운데 정렬'; + $lang->edit->icon_align_right = '글의 우측으로'; + + $lang->about_dblclick_in_editor = '배경, 글자, 이미지, 인용문등에서 더블클릭을 하시면 상세한 컴포넌트 설정이 가능합니다.'; + + $lang->edit->rich_editor = '스타일 편집기'; + $lang->edit->html_editor = 'HTML 편집기'; + $lang->edit->extension ='확장 컴포넌트'; + $lang->edit->help = '도움말'; + $lang->edit->help_command = '단축키 안내'; + + $lang->edit->lineheight = '줄간격'; + $lang->edit->fontbgsampletext = '가나다'; + + $lang->edit->hyperlink = '하이퍼링크'; + $lang->edit->target_blank = '새창으로'; + + $lang->edit->quotestyle1 = '왼쪽 실선'; + $lang->edit->quotestyle2 = '인용 부호'; + $lang->edit->quotestyle3 = '실선'; + $lang->edit->quotestyle4 = '실선 + 배경'; + $lang->edit->quotestyle5 = '굵은 실선'; + $lang->edit->quotestyle6 = '점선'; + $lang->edit->quotestyle7 = '점선 + 배경'; + $lang->edit->quotestyle8 = '적용 취소'; + + + $lang->edit->jumptoedit = '편집 도구모음 건너뛰기'; + $lang->edit->set_sel = '칸 수 지정'; + $lang->edit->row = '행'; + $lang->edit->col = '열'; + $lang->edit->add_one_row = '1행추가'; + $lang->edit->del_one_row = '1행삭제'; + $lang->edit->add_one_col = '1열추가'; + $lang->edit->del_one_col = '1열삭제'; + + $lang->edit->table_config = '표 속성 지정'; + $lang->edit->border_width = '테두리 굵기'; + $lang->edit->border_color = '테두리 색'; + $lang->edit->add = '더하기'; + $lang->edit->del = '빼기'; + $lang->edit->search_color = '색상찾기'; + $lang->edit->table_backgroundcolor = '표 배경색'; + $lang->edit->special_character = '특수문자'; + $lang->edit->insert_special_character = '특수문자 삽입'; + $lang->edit->close_special_character = '특수문자 레이어 닫기'; + $lang->edit->symbol = '일반기호'; + $lang->edit->number_unit = '숫자와 단위'; + $lang->edit->circle_bracket = '원,괄호'; + $lang->edit->korean = '한글'; + $lang->edit->greece = '그리스'; + $lang->edit->Latin = '라틴어'; + $lang->edit->japan = '일본어'; + $lang->edit->selected_symbol = '선택한 기호'; + + $lang->edit->search_replace = '찾기/바꾸기'; + $lang->edit->close_search_replace = '찾기/바꾸기 레이어 닫기'; + $lang->edit->replace_all = '모두바꾸기'; + $lang->edit->search_words = '찾을단어'; + $lang->edit->replace_words = '바꿀단어'; + $lang->edit->next_search_words = '다음찾기'; + $lang->edit->edit_height_control = '입력창 크기 조절'; + + $lang->edit->merge_cells = '셀 병합'; + $lang->edit->split_row = '행 분할'; + $lang->edit->split_col = '열 분할'; + + $lang->edit->toggle_list = '목록 접기/펼치기'; + $lang->edit->minimize_list = '최소화'; + + $lang->edit->move = '이동'; + $lang->edit->refresh = '새로고침'; + $lang->edit->materials = '글감보관함'; + $lang->edit->temporary_savings = '임시저장목록'; + + $lang->edit->drag_here = '아래의 단락추가 툴바에서 원하는 유형의 단락을 추가해 글 쓰기를 시작하세요.
글감 보관함에 글이 있으면 이곳으로 끌어 넣기 할 수 있습니다.'; + + $lang->edit->paging_prev = '이전'; + $lang->edit->paging_next = '다음'; + $lang->edit->paging_prev_help = '이전 페이지로 이동합니다.'; + $lang->edit->paging_next_help = '다음 페이지로 이동합니다.'; + + $lang->edit->toc = '목차'; +?> diff --git a/modules/editor/lang/ru.lang.php b/modules/editor/lang/ru.lang.php index 31b0d24ef..0dfd4c5c2 100644 --- a/modules/editor/lang/ru.lang.php +++ b/modules/editor/lang/ru.lang.php @@ -18,6 +18,7 @@ $lang->component_grant = 'Настройки прав доступа'; $lang->content_style = 'Content Style'; $lang->content_font = 'Content Font'; + $lang->content_font_size = '문서 폰트 크기'; $lang->about_component = 'О компоненте'; $lang->about_component_grant = 'Только выбранным группам позволено использование.
(Каждый может использовать его, если режим выключен)'; @@ -45,6 +46,7 @@ $lang->about_editor_skin = '에디터 스킨을 선택하실 수 있습니다'; $lang->about_content_style = '문서 편집 및 내용 출력시 원하는 서식을 지정할 수 있습니다'; $lang->about_content_font = '문서 편집 및 내용 출력시 원하는 폰트를 지정할 수 있습니다.
지정하지 않으면 사용자 설정에 따르게 됩니다
,(콤마)로 여러 폰트를 지정할 수 있습니다.'; + $lang->about_content_font_size = '문서 편집 및 내용 출력시 원하는 폰트의 크기를 지정할 수 있습니다.
12px, 1em등 단위까지 포함해서 입력해주세요.'; $lang->about_upload_file_grant = '파일을 첨부할 수 있는 권한을 지정하실 수 있습니다 (모두 해제시 아무나 첨부 가능합니다)'; $lang->about_default_component_grant = '에디터에서 사용되는 기본 컴포넌트를 사용할 수 있는 권한을 지정할 수 있습니다. (모두 해제시 아무나 사용 가능합니다)'; $lang->about_editor_height = '에디터의 기본 높이를 지정하실 수 있습니다'; @@ -207,10 +209,12 @@ $lang->edit->materials = '글감보관함'; $lang->edit->temporary_savings = '임시저장목록'; - $lang->edit->drag_here = '글감 보관함에 글이 있으면 이곳으로 끌어 넣기 할 수 있습니다.'; + $lang->edit->drag_here = '아래의 단락추가 툴바에서 원하는 유형의 단락을 추가해 글 쓰기를 시작하세요.
글감 보관함에 글이 있으면 이곳으로 끌어 넣기 할 수 있습니다.'; $lang->edit->paging_prev = '이전'; $lang->edit->paging_next = '다음'; $lang->edit->paging_prev_help = '이전 페이지로 이동합니다.'; $lang->edit->paging_next_help = '다음 페이지로 이동합니다.'; + + $lang->edit->toc = '목차'; ?> diff --git a/modules/editor/lang/zh-CN.lang.php b/modules/editor/lang/zh-CN.lang.php index 81b4c7b46..1c39a264b 100644 --- a/modules/editor/lang/zh-CN.lang.php +++ b/modules/editor/lang/zh-CN.lang.php @@ -18,6 +18,7 @@ $lang->component_grant = '权限设置'; $lang->content_style = 'Content Style'; $lang->content_font = 'Content Font'; + $lang->content_font_size = '문서 폰트 크기'; $lang->about_component = '组件简介'; $lang->about_component_grant = '可以设置除默认组件外的扩展组件使用权限
(全部解除时任何用户都可以使用)。'; @@ -45,6 +46,7 @@ $lang->about_editor_skin = '可以选择编辑器皮肤。'; $lang->about_content_style = '문서 편집 및 내용 출력시 원하는 서식을 지정할 수 있습니다'; $lang->about_content_font = '문서 편집 및 내용 출력시 원하는 폰트를 지정할 수 있습니다.
지정하지 않으면 사용자 설정에 따르게 됩니다
,(콤마)로 여러 폰트를 지정할 수 있습니다.'; + $lang->about_content_font_size = '문서 편집 및 내용 출력시 원하는 폰트의 크기를 지정할 수 있습니다.
12px, 1em등 단위까지 포함해서 입력해주세요.'; $lang->about_upload_file_grant = '可以设置上传文件的权限(全部解除为无限制)。'; $lang->about_default_component_grant = '可以设置编辑器默认组件的使用权限(全部解除为无限制)。'; $lang->about_editor_height = '可以指定编辑器的默认高度。'; @@ -213,10 +215,12 @@ $lang->edit->materials = '글감보관함'; $lang->edit->temporary_savings = '임시저장목록'; - $lang->edit->drag_here = '글감 보관함에 글이 있으면 이곳으로 끌어 넣기 할 수 있습니다.'; + $lang->edit->drag_here = '아래의 단락추가 툴바에서 원하는 유형의 단락을 추가해 글 쓰기를 시작하세요.
글감 보관함에 글이 있으면 이곳으로 끌어 넣기 할 수 있습니다.'; $lang->edit->paging_prev = '이전'; $lang->edit->paging_next = '다음'; $lang->edit->paging_prev_help = '이전 페이지로 이동합니다.'; $lang->edit->paging_next_help = '다음 페이지로 이동합니다.'; + + $lang->edit->toc = '목차'; ?> diff --git a/modules/editor/lang/zh-TW.lang.php b/modules/editor/lang/zh-TW.lang.php index 2393576ae..1045a8549 100644 --- a/modules/editor/lang/zh-TW.lang.php +++ b/modules/editor/lang/zh-TW.lang.php @@ -18,6 +18,7 @@ $lang->component_grant = '權限設置'; $lang->content_style = '內容樣式'; $lang->content_font = '內容字體'; + $lang->content_font_size = '문서 폰트 크기'; $lang->about_component = '組件簡介'; $lang->about_component_grant = '除預設組件外,可設置延伸組件的使用權限
(全部解除時,任何用戶都可使用)。'; @@ -45,6 +46,7 @@ $lang->about_editor_skin = '選擇編輯器面板。'; $lang->about_content_style = '문서 편집 및 내용 출력시 원하는 서식을 지정할 수 있습니다'; $lang->about_content_font = '문서 편집 및 내용 출력시 원하는 폰트를 지정할 수 있습니다.
지정하지 않으면 사용자 설정에 따르게 됩니다
,(콤마)로 여러 폰트를 지정할 수 있습니다.'; + $lang->about_content_font_size = '문서 편집 및 내용 출력시 원하는 폰트의 크기를 지정할 수 있습니다.
12px, 1em등 단위까지 포함해서 입력해주세요.'; $lang->about_upload_file_grant = '設置上傳檔案的權限(全部解除為無限制)。'; $lang->about_default_component_grant = '設置編輯器預設組件的使用權限(全部解除為無限制)。'; $lang->about_editor_height = '指定編輯器的預設高度。'; @@ -214,10 +216,12 @@ $lang->edit->materials = '글감보관함'; $lang->edit->temporary_savings = '임시저장목록'; - $lang->edit->drag_here = '글감 보관함에 글이 있으면 이곳으로 끌어 넣기 할 수 있습니다.'; + $lang->edit->drag_here = '아래의 단락추가 툴바에서 원하는 유형의 단락을 추가해 글 쓰기를 시작하세요.
글감 보관함에 글이 있으면 이곳으로 끌어 넣기 할 수 있습니다.'; $lang->edit->paging_prev = '이전'; $lang->edit->paging_next = '다음'; $lang->edit->paging_prev_help = '이전 페이지로 이동합니다.'; $lang->edit->paging_next_help = '다음 페이지로 이동합니다.'; + + $lang->edit->toc = '목차'; ?> diff --git a/modules/editor/queries/deleteSavedDoc.xml b/modules/editor/queries/deleteSavedDoc.xml index 0f1dae294..e6189f731 100644 --- a/modules/editor/queries/deleteSavedDoc.xml +++ b/modules/editor/queries/deleteSavedDoc.xml @@ -2,8 +2,10 @@ + - - + + + diff --git a/modules/editor/queries/getSavedDocument.xml b/modules/editor/queries/getSavedDocument.xml index e2f53e4f3..50c194fe2 100644 --- a/modules/editor/queries/getSavedDocument.xml +++ b/modules/editor/queries/getSavedDocument.xml @@ -4,6 +4,7 @@ + diff --git a/modules/editor/queries/insertSavedDoc.xml b/modules/editor/queries/insertSavedDoc.xml index 63d6b54b3..78e1d1d7b 100644 --- a/modules/editor/queries/insertSavedDoc.xml +++ b/modules/editor/queries/insertSavedDoc.xml @@ -3,6 +3,7 @@
+ diff --git a/modules/editor/schemas/editor_autosave.xml b/modules/editor/schemas/editor_autosave.xml index 3327cf9f5..94ae49f50 100644 --- a/modules/editor/schemas/editor_autosave.xml +++ b/modules/editor/schemas/editor_autosave.xml @@ -1,6 +1,7 @@
+ diff --git a/modules/editor/skins/fckeditor/editor.html b/modules/editor/skins/fckeditor/editor.html index 81de53c6d..8f54e812d 100644 --- a/modules/editor/skins/fckeditor/editor.html +++ b/modules/editor/skins/fckeditor/editor.html @@ -13,6 +13,7 @@ + diff --git a/modules/editor/skins/fckeditor/js/xe_interface.js b/modules/editor/skins/fckeditor/js/xe_interface.js index eca723345..7ac9a653b 100644 --- a/modules/editor/skins/fckeditor/js/xe_interface.js +++ b/modules/editor/skins/fckeditor/js/xe_interface.js @@ -51,13 +51,22 @@ function editorStart_fck(editor, element, editor_sequence, content_key, editor_h if(typeof(fo_obj._saved_doc_title)!="undefined" ) { ///<< _saved_doc_title field가 없으면 자동저장 하지 않음 var saved_title = fo_obj._saved_doc_title.value; var saved_content = fo_obj._saved_doc_content.value; + var saved_srl = fo_obj._saved_doc_srl.value; if(saved_title || saved_content) { // 자동저장된 문서 활용여부를 물은 후 사용하지 않는다면 자동저장된 문서 삭제 if(confirm(fo_obj._saved_doc_message.value)) { if(typeof(fo_obj.title)!='undefined') fo_obj.title.value = saved_title; setTimeout(function(){ + editorRelKeys[editor_sequence]['primary'].value = saved_srl; setContent(editor_sequence,saved_content); }, 100); + xAddEventListener(window,"load",function() { var param = new Array(); + param['editor_sequence'] = editor_sequence; + param['primary_key'] = primary_key; + param['mid'] = current_mid; + var response_tags = new Array("error","message","editor_sequence","key","title","content","document_srl"); + exec_xml('editor',"procEditorLoadSavedDocument", param, null, response_tags); + }); } else { editorRemoveSavedDoc(); } diff --git a/modules/editor/skins/xpresseditor/css/default.css b/modules/editor/skins/xpresseditor/css/default.css index 68521f732..8e6cdc1db 100644 --- a/modules/editor/skins/xpresseditor/css/default.css +++ b/modules/editor/skins/xpresseditor/css/default.css @@ -7,7 +7,7 @@ /* Type Selector */ .xpress-editor *{margin:0; padding:0; font-style:normal; font-size:12px; } -.xpress-editor img, +.xpress-editor img, .xpress-editor fieldset, .xpress-editor button{ border:0;} .xpress-editor button{ background:none; background-repeat:no-repeat; cursor:pointer; _cursor /**/:hand;} @@ -20,6 +20,7 @@ /* Layout Selector */ .xpress-editor{ position:relative; background:transparent;} .xpress-editor #smart_content{ position:relative; clear:both; margin:0 0 10px 0; border:1px solid #c2c2c2; *zoom:1; z-index:5; background:#fff;} +.xpress-editor.black #smart_content {background:transparent;} .xpress-editor #smart_footer{ position:relative; text-align:center; padding:10px 0;} /* Footer */ diff --git a/modules/editor/skins/xpresseditor/editor.html b/modules/editor/skins/xpresseditor/editor.html index 76eb90478..871894acc 100644 --- a/modules/editor/skins/xpresseditor/editor.html +++ b/modules/editor/skins/xpresseditor/editor.html @@ -4,16 +4,17 @@ + + + {@ $editor_class = "black" } + + - - - {@ $editor_class = "black" } -
nbr" /> - +
- -
-
-
- -
-
- - - -
-
{$upload_status}
-
- - - - + ); + //]]> + +
+
+
+ +
+
+ + + +
+
{$upload_status}
+
+ + + + diff --git a/modules/editor/skins/xpresseditor/js/Xpress_Editor.js b/modules/editor/skins/xpresseditor/js/Xpress_Editor.js index c041d75b9..491f78e3c 100644 --- a/modules/editor/skins/xpresseditor/js/Xpress_Editor.js +++ b/modules/editor/skins/xpresseditor/js/Xpress_Editor.js @@ -1,6180 +1,6215 @@ -// extends jQuery object -(function($){ - -$.extend({ - Class : function(def) { - function c(){ - if (typeof this.$super != 'undefined') this.$super.$this = this; - if ($.isFunction(this.$init)) this.$init.apply(this, arguments); - } - c.prototype = def; - c.constructor = c; - c.extend = Class_extend; - - return c; - }, - $ : function(id) { - if(typeof id == 'string') { - if (id.substring(0,1) == '<') return $(id).get(0); - return $('#'+id).get(0); - } else { - return id; - } - }, - fnBind : function(fn, th/* , args... */) { - var args = $.makeArray(arguments); - args.shift(); args.shift(); - - return function() { - var a = args.concat($.makeArray(arguments)); - - return fn.apply(th, a); - }; - } -}); - -$.browser.nVersion = parseFloat($.browser.version); - -function Class_extend(superDef) { - var Super = superDef.prototype; - - this.prototype.$super = {}; - - function bind(fn) { - return function() { - return fn.apply(this.$this, arguments); - }; - } - - for(var x in Super) { - if (!Super.propertyIsEnumerable(x)) continue; - - if (typeof this.prototype[x] == 'undefined') this.prototype[x] = Super[x]; - this.prototype.$super[x] = $.isFunction(Super[x])?bind(Super[x]):Super[x]; - } - - return this; -} - -})(jQuery); - -if (typeof window.xe == 'undefined') window.xe = {}; - -//{ - /** - * @fileOverview This file contains Xpress framework core - * @name XpressCore.js - */ -xe.XpressCore = jQuery.Class({ - name : "XpressCore", - - $init : function(htOptions){ - htOptions = !htOptions?{}:jQuery.Class({}).extend({ - oDebugger : null - }).extend(htOptions); - if(htOptions.oDebugger){ - this.oDebugger = htOptions.oDebugger; - this.oDebugger.oApp = this; - } - - // To prevent processing a Xpress command before all the plugins are registered and ready, - // Queue up all the commands here until the application's status is changed to READY - this.commandQueue = []; - - this.oCommandMap = {}; - this.oDisabledCommand = {}; - this.aPlugins = []; - - this.appStatus = xe.APP_STATUS["NOT_READY"]; - - // Register the core as a plugin so it can receive messages - this.registerPlugin(this); - }, - - exec : function(msg, args, oEvent){ - // If the application is not yet ready just queue the command - if(this.appStatus == xe.APP_STATUS["NOT_READY"]){ - this.commandQueue[this.commandQueue.length] = {'msg':msg, 'args':args, 'event':oEvent}; - return true; - } - - this.exec = this._exec; - this.exec(msg, args, oEvent); - }, - - delayedExec : function(msg, args, nDelay, oEvent){ - var fExec = jQuery.fnBind(this.exec, this, msg, args, oEvent); - setTimeout(fExec, nDelay); - }, - - _exec : function(msg, args, oEvent){return (this._exec = this.oDebugger?this._execWithDebugger:this._execWithoutDebugger).call(this, msg, args, oEvent);}, - _execWithDebugger : function(msg, args, oEvent){this.oDebugger.log_MessageStart(msg, args);var bResult = this._doExec(msg, args, oEvent);this.oDebugger.log_MessageEnd(msg, args);return bResult; }, - _execWithoutDebugger : function(msg, args, oEvent){return this._doExec(msg, args, oEvent);}, - _doExec : function(msg, args, oEvent){ - var bContinue = false; - - if(!this.oDisabledCommand[msg]){ - var allArgs = []; - if(args && args.length){ - var iLen = args.length; - for(var i=0; i= 0 && xe.DOMFix.parentNode(aAllNodes[iChildIdx]) == aAllNodes[iCurIdx]){ - iChildIdx = this._recurConstructClonedTree(aAllNodes, iChildIdx, aAllNodes[iCurIdx], oCurNodeCloneWithChildren, oClonedStartContainer, oClonedEndContainer); - } - - // this may trigger an error message in IE when an erroneous script is inserted - oClonedParentNode.insertBefore(oCurNodeCloneWithChildren, oClonedParentNode.firstChild); - - return iChildIdx; - }; - - aNodes[aNodes.length] = xe.DOMFix.parentNode(aNodes[aNodes.length-1]); - _recurConstructClonedTree(aNodes, aNodes.length-1, aNodes[aNodes.length-1], oClonedParentNode); - - return {oStartContainer: oClonedStartContainer, oEndContainer: oClonedEndContainer}; - }, - - cloneRange : function(){ - return this._copyRange(new xe.W3CDOMRange(this._document)); - }, - - _copyRange : function(oClonedRange){ - oClonedRange.collapsed = this.collapsed; - oClonedRange.commonAncestorContainer = this.commonAncestorContainer; - oClonedRange.endContainer = this.endContainer; - oClonedRange.endOffset = this.endOffset; - oClonedRange.startContainer = this.startContainer; - oClonedRange.startOffset = this.startOffset; - oClonedRange._document = this._document; - - return oClonedRange; - }, - - collapse : function(toStart){ - if(toStart){ - this.endContainer = this.startContainer; - this.endOffset = this.startOffset; - }else{ - this.startContainer = this.endContainer; - this.startOffset = this.endOffset; - } - - this._updateRangeInfo(); - }, - - compareBoundaryPoints : function(how, sourceRange){ - switch(how){ - case xe.W3CDOMRange.START_TO_START: - return this._compareEndPoint(this.startContainer, this.startOffset, sourceRange.startContainer, sourceRange.startOffset); - case xe.W3CDOMRange.START_TO_END: - return this._compareEndPoint(this.endContainer, this.endOffset, sourceRange.startContainer, sourceRange.startOffset); - case xe.W3CDOMRange.END_TO_END: - return this._compareEndPoint(this.endContainer, this.endOffset, sourceRange.endContainer, sourceRange.endOffset); - case xe.W3CDOMRange.END_TO_START: - return this._compareEndPoint(this.startContainer, this.startOffset, sourceRange.endContainer, sourceRange.endOffset); - } - }, - - _findBody : function(oNode){ - if(!oNode) return null; - while(oNode){ - if(oNode.tagName == "BODY") return oNode; - oNode = xe.DOMFix.parentNode(oNode); - } - return null; - }, - - _compareEndPoint : function(oContainerA, iOffsetA, oContainerB, iOffsetB){ - var iIdxA, iIdxB; - - if(!oContainerA || this._findBody(oContainerA) != this._document.body){ - oContainerA = this._document.body; - iOffsetA = 0; - } - - if(!oContainerB || this._findBody(oContainerB) != this._document.body){ - oContainerB = this._document.body; - iOffsetB = 0; - } - - var compareIdx = function(iIdxA, iIdxB){ - // iIdxX == -1 when the node is the commonAncestorNode - // if iIdxA == -1 - // -> [[...]]... - // if iIdxB == -1 - // -> ...[[...]] - if(iIdxB == -1) iIdxB = iIdxA+1; - if(iIdxA < iIdxB) return -1; - if(iIdxA == iIdxB) return 0; - return 1; - }; - - var oCommonAncestor = this._getCommonAncestorContainer(oContainerA, oContainerB); - - // ================================================================================================================================================ - // Move up both containers so that both containers are direct child nodes of the common ancestor node. From there, just compare the offset - // Add 0.5 for each contaienrs that has "moved up" since the actual node is wrapped by 1 or more parent nodes and therefore its position is somewhere between idx & idx+1 - // NODE1

NODE2

NODE3
- // The position of NODE2 in COMMON_ANCESTOR is somewhere between after NODE1(idx1) and before NODE3(idx2), so we let that be 1.5 - - // container node A in common ancestor container - var oNodeA = oContainerA; - if(oNodeA != oCommonAncestor){ - while((oTmpNode = xe.DOMFix.parentNode(oNodeA)) != oCommonAncestor){oNodeA = oTmpNode;} - - iIdxA = this._getPosIdx(oNodeA)+0.5; - }else iIdxA = iOffsetA; - - // container node B in common ancestor container - var oNodeB = oContainerB; - if(oNodeB != oCommonAncestor){ - while((oTmpNode = xe.DOMFix.parentNode(oNodeB)) != oCommonAncestor){oNodeB = oTmpNode;} - - iIdxB = this._getPosIdx(oNodeB)+0.5; - }else iIdxB = iOffsetB; - - return compareIdx(iIdxA, iIdxB); - }, - - _getCommonAncestorContainer : function(oNode1, oNode2){ - var oComparingNode = oNode2; - - while(oNode1){ - while(oComparingNode){ - if(oNode1 == oComparingNode) return oNode1; - oComparingNode = xe.DOMFix.parentNode(oComparingNode); - } - oComparingNode = oNode2; - oNode1 = xe.DOMFix.parentNode(oNode1); - } - - return this._document.body; - }, - - deleteContents : function(){ - if(this.collapsed) return; - - this._splitTextEndNodesOfTheRange(); - - var aNodes = this._getNodesInRange(); - - if(aNodes.length < 1) return; - - var oPrevNode = aNodes[0].previousSibling; - while(oPrevNode && this._isBlankTextNode(oPrevNode)) oPrevNode = oPrevNode.previousSibling; - - var oNewStartContainer, iNewOffset; - if(!oPrevNode){ - oNewStartContainer = xe.DOMFix.parentNode(aNodes[0]); - iNewOffset = 0; - } - - for(var i=0; i oNode.nodeValue.length) iOffset = oNode.nodeValue.length; - }else{ - if(iOffset > xe.DOMFix.childNodes(oNode).length) iOffset = xe.DOMFix.childNodes(oNode).length; - } - - return iOffset; - }, - - - setEnd : function(refNode, offset){ - offset = this._endsNodeValidation(refNode, offset); - - this.endContainer = refNode; - this.endOffset = offset; - if(!this.startContainer || this._compareEndPoint(this.startContainer, this.startOffset, this.endContainer, this.endOffset) != -1) this.collapse(false); - - this._updateRangeInfo(); - }, - - setEndAfter : function(refNode){ - if(!refNode) throw new Error("INVALID_NODE_TYPE_ERR in setEndAfter"); - - if(refNode.tagName == "BODY"){ - this.setEnd(refNode, xe.DOMFix.childNodes(refNode).length); - return; - } - this.setEnd(xe.DOMFix.parentNode(refNode), this._getPosIdx(refNode)+1); - }, - - setEndBefore : function(refNode){ - if(!refNode) throw new Error("INVALID_NODE_TYPE_ERR in setEndBefore"); - - if(refNode.tagName == "BODY"){ - this.setEnd(refNode, 0); - return; - } - - this.setEnd(xe.DOMFix.parentNode(refNode), this._getPosIdx(refNode)); - }, - - setStart : function(refNode, offset){ - offset = this._endsNodeValidation(refNode, offset); - - this.startContainer = refNode; - this.startOffset = offset; - - if(!this.endContainer || this._compareEndPoint(this.startContainer, this.startOffset, this.endContainer, this.endOffset) != -1) this.collapse(true); - this._updateRangeInfo(); - }, - - setStartAfter : function(refNode){ - if(!refNode) throw new Error("INVALID_NODE_TYPE_ERR in setStartAfter"); - - if(refNode.tagName == "BODY"){ - this.setStart(refNode, xe.DOMFix.childNodes(refNode).length); - return; - } - - this.setStart(xe.DOMFix.parentNode(refNode), this._getPosIdx(refNode)+1); - }, - - setStartBefore : function(refNode){ - if(!refNode) throw new Error("INVALID_NODE_TYPE_ERR in setStartBefore"); - - if(refNode.tagName == "BODY"){ - this.setStart(refNode, 0); - return; - } - this.setStart(xe.DOMFix.parentNode(refNode), this._getPosIdx(refNode)); - }, - - surroundContents : function(newParent){ - newParent.appendChild(this.extractContents()); - this.insertNode(newParent); - this.selectNode(newParent); - }, - - toString : function(){ - var oTmpContainer = this._document.createElement("DIV"); - oTmpContainer.appendChild(this.cloneContents()); - - return oTmpContainer.textContent || oTmpContainer.innerText || ""; - }, - - _isBlankTextNode : function(oNode){ - if(oNode.nodeType == 3 && oNode.nodeValue == "") return true; - return false; - }, - - _getPosIdx : function(refNode){ - var idx = 0; - for(var node = refNode.previousSibling; node; node = node.previousSibling) idx++; - - return idx; - }, - - _updateRangeInfo : function(){ - if(!this.startContainer){ - this.init(this._document); - return; - } - - this.collapsed = this._isCollapsed(this.startContainer, this.startOffset, this.endContainer, this.endOffset); - - this.commonAncestorContainer = this._getCommonAncestorContainer(this.startContainer, this.endContainer); - }, - - _isCollapsed : function(oStartContainer, iStartOffset, oEndContainer, iEndOffset){ - var bCollapsed = false; - - if(oStartContainer == oEndContainer && iStartOffset == iEndOffset){ - bCollapsed = true; - }else{ - var oActualStartNode = this._getActualStartNode(oStartContainer, iStartOffset); - var oActualEndNode = this._getActualEndNode(oEndContainer, iEndOffset); - - // Take the parent nodes on the same level for easier comparison when they're next to each other - // eg) From - // - // - // - // - // - // - // - // - // - // - // - // - // , it's easier to compare the position of B and D rather than C and F because they are siblings - // - // If the range were collapsed, oActualEndNode will precede oActualStartNode by doing this - oActualStartNode = this._getNextNode(this._getPrevNode(oActualStartNode)); - oActualEndNode = this._getPrevNode(this._getNextNode(oActualEndNode)); - - if(oActualStartNode && oActualEndNode && oActualEndNode.tagName != "BODY" && - (this._getNextNode(oActualEndNode) == oActualStartNode || (oActualEndNode == oActualStartNode && this._isBlankTextNode(oActualEndNode))) - ) - bCollapsed = true; - } - - return bCollapsed; - }, - - _splitTextEndNodesOfTheRange : function(){ - var oEndPoints = this._splitTextEndNodes({oStartContainer: this.startContainer, iStartOffset: this.startOffset, - oEndContainer: this.endContainer, iEndOffset: this.endOffset}); - - this.startContainer = oEndPoints.oStartContainer; - this.startOffset = oEndPoints.iStartOffset; - - this.endContainer = oEndPoints.oEndContainer; - this.endOffset = oEndPoints.iEndOffset; - }, - - _splitTextEndNodes : function(oEndPoints){ - oEndPoints = this._splitStartTextNode(oEndPoints); - oEndPoints = this._splitEndTextNode(oEndPoints); - - return oEndPoints; - }, - - _splitStartTextNode : function(oEndPoints){ - var oStartContainer = oEndPoints.oStartContainer; - var iStartOffset = oEndPoints.iStartOffset; - - var oEndContainer = oEndPoints.oEndContainer; - var iEndOffset = oEndPoints.iEndOffset; - - if(!oStartContainer) return oEndPoints; - if(oStartContainer.nodeType != 3) return oEndPoints; - if(iStartOffset == 0) return oEndPoints; - - if(oStartContainer.nodeValue.length <= iStartOffset) return oEndPoints; - - var oLastPart = oStartContainer.splitText(iStartOffset); - - if(oStartContainer == oEndContainer){ - iEndOffset -= iStartOffset; - oEndContainer = oLastPart; - } - oStartContainer = oLastPart; - iStartOffset = 0; - - return {oStartContainer: oStartContainer, iStartOffset: iStartOffset, oEndContainer: oEndContainer, iEndOffset: iEndOffset}; - }, - - _splitEndTextNode : function(oEndPoints){ - var oStartContainer = oEndPoints.oStartContainer; - var iStartOffset = oEndPoints.iStartOffset; - - var oEndContainer = oEndPoints.oEndContainer; - var iEndOffset = oEndPoints.iEndOffset; - - if(!oEndContainer) return oEndPoints; - if(oEndContainer.nodeType != 3) return oEndPoints; - - if(iEndOffset >= oEndContainer.nodeValue.length) return oEndPoints; - if(iEndOffset == 0) return oEndPoints; - - oEndContainer.splitText(iEndOffset); - - return {oStartContainer: oStartContainer, iStartOffset: iStartOffset, oEndContainer: oEndContainer, iEndOffset: iEndOffset}; - }, - - _getNodesInRange : function(){ - if(this.collapsed) return []; - - var oStartNode = this._getActualStartNode(this.startContainer, this.startOffset); - var oEndNode = this._getActualEndNode(this.endContainer, this.endOffset); - - return this._getNodesBetween(oStartNode, oEndNode); - }, - - _getActualStartNode : function(oStartContainer, iStartOffset){ - var oStartNode = oStartContainer;; - - if(oStartContainer.nodeType == 3){ - if(iStartOffset >= oStartContainer.nodeValue.length){ - oStartNode = this._getNextNode(oStartContainer); - if(oStartNode.tagName == "BODY") oStartNode = null; - }else{ - oStartNode = oStartContainer; - } - }else{ - if(iStartOffset < xe.DOMFix.childNodes(oStartContainer).length){ - oStartNode = xe.DOMFix.childNodes(oStartContainer)[iStartOffset]; - }else{ - oStartNode = this._getNextNode(oStartContainer); - if(oStartNode.tagName == "BODY") oStartNode = null; - } - } - - return oStartNode; - }, - - _getActualEndNode : function(oEndContainer, iEndOffset){ - var oEndNode = oEndContainer; - - if(iEndOffset == 0){ - oEndNode = this._getPrevNode(oEndContainer); - if(oEndNode.tagName == "BODY") oEndNode = null; - }else if(oEndContainer.nodeType == 3){ - oEndNode = oEndContainer; - }else{ - oEndNode = xe.DOMFix.childNodes(oEndContainer)[iEndOffset-1]; - } - - return oEndNode; - }, - - _getNextNode : function(oNode){ - if(!oNode || oNode.tagName == "BODY") return this._document.body; - - if(oNode.nextSibling) return oNode.nextSibling; - - return this._getNextNode(xe.DOMFix.parentNode(oNode)); - }, - - _getPrevNode : function(oNode){ - if(!oNode || oNode.tagName == "BODY") return this._document.body; - - if(oNode.previousSibling) return oNode.previousSibling; - - return this._getPrevNode(xe.DOMFix.parentNode(oNode)); - }, - - // includes partially selected - // for
, _getNodesBetween(b, c) will yield to b, "a" and c - _getNodesBetween : function(oStartNode, oEndNode){ - var aNodesBetween = []; - - if(!oStartNode || !oEndNode) return aNodesBetween; - - this._recurGetNextNodesUntil(oStartNode, oEndNode, aNodesBetween); - return aNodesBetween; - }, - - _recurGetNextNodesUntil : function(oNode, oEndNode, aNodesBetween){ - if(!oNode) return false; - - if(!this._recurGetChildNodesUntil(oNode, oEndNode, aNodesBetween)) return false; - - var oNextToChk = oNode.nextSibling; - - while(!oNextToChk){ - if(!xe.DOMFix.parentNode(oNode)) return false; - oNode = xe.DOMFix.parentNode(oNode); - - aNodesBetween[aNodesBetween.length] = oNode; - - if(oNode == oEndNode) return false; - - oNextToChk = oNode.nextSibling; - } - - return this._recurGetNextNodesUntil(oNextToChk, oEndNode, aNodesBetween); - }, - - _recurGetChildNodesUntil : function(oNode, oEndNode, aNodesBetween){ - if(!oNode) return false; - - var bEndFound = false; - var oCurNode = oNode; - if(oCurNode.firstChild){ - oCurNode = oCurNode.firstChild; - while(oCurNode){ - if(!this._recurGetChildNodesUntil(oCurNode, oEndNode, aNodesBetween)){ - bEndFound = true; - break; - } - oCurNode = oCurNode.nextSibling; - } - } - - aNodesBetween[aNodesBetween.length] = oNode; - - if(bEndFound) return false; - if(oNode == oEndNode) return false; - - return true; - } -}); - -xe.W3CDOMRange.START_TO_START = 0; -xe.W3CDOMRange.START_TO_END = 1; -xe.W3CDOMRange.END_TO_END = 2; -xe.W3CDOMRange.END_TO_START = 3; - - -/** - * @fileOverview This file contains a cross-browser function that implements all of the W3C's DOM Range specification and some more - * @name XpressRange.js - */ -xe.XpressRange = jQuery.Class({ - setWindow : function(win){ - this._window = win; - this._document = win.document; - }, - - $init : function(win){ - this.HUSKY_BOOMARK_START_ID_PREFIX = "xpress_bookmark_start_"; - this.HUSKY_BOOMARK_END_ID_PREFIX = "xpress_bookmark_end_"; - - this.sBlockElement = "P|DIV|LI|H[1-6]|PRE"; - this.sBlockContainer = "BODY|TABLE|TH|TR|TD|UL|OL|BLOCKQUOTE|FORM"; - - this.rxBlockElement = new RegExp("^("+this.sBlockElement+")$"); - this.rxBlockContainer = new RegExp("^("+this.sBlockContainer+")$") - this.rxLineBreaker = new RegExp("^("+this.sBlockElement+"|"+this.sBlockContainer+")$") - - this.setWindow(win); - - this.oSimpleSelection = new xe.SimpleSelection(this._window); - this.selectionLoaded = this.oSimpleSelection.selectionLoaded; - - this.$super.$init(this._document); - }, - - select : function(){ - this.oSimpleSelection.selectRange(this); - }, - - setFromSelection : function(iNum){ - this.setRange(this.oSimpleSelection.getRangeAt(iNum)); - }, - - setRange : function(oW3CRange){ - this.setStart(oW3CRange.startContainer, oW3CRange.startOffset); - this.setEnd(oW3CRange.endContainer, oW3CRange.endOffset); - }, - - setEndNodes : function(oSNode, oENode){ - this.setEndAfter(oENode); - this.setStartBefore(oSNode); - }, - - splitTextAtBothEnds : function(){ - this._splitTextEndNodesOfTheRange(); - }, - - getStartNode : function(){ - if(this.collapsed){ - if(this.startContainer.nodeType == 3){ - if(this.startOffset == 0) return null; - if(this.startContainer.nodeValue.length <= this.startOffset) return null; - return this.startContainer; - } - return null; - } - - if(this.startContainer.nodeType == 3){ - if(this.startOffset >= this.startContainer.nodeValue.length) return this._getNextNode(this.startContainer); - return this.startContainer; - }else{ - if(this.startOffset >= xe.DOMFix.childNodes(this.startContainer).length) return this._getNextNode(this.startContainer); - return xe.DOMFix.childNodes(this.startContainer)[this.startOffset]; - } - }, - - getEndNode : function(){ - if(this.collapsed) return this.getStartNode(); - - if(this.endContainer.nodeType == 3){ - if(this.endOffset == 0) return this._getPrevNode(this.endContainer); - return this.endContainer; - }else{ - if(this.endOffset == 0) return this._getPrevNode(this.endContainer); - return xe.DOMFix.childNodes(this.endContainer)[this.endOffset-1]; - } - }, - - getNodeAroundRange : function(bBefore, bStrict){ - if(this.collapsed && this.startContainer && this.startContainer.nodeType == 3) return this.startContainer; - if(!this.collapsed || (this.startContainer && this.startContainer.nodeType == 3)) return this.getStartNode(); - - var oBeforeRange, oAfterRange, oResult; - - if(this.startOffset >= xe.DOMFix.childNodes(this.startContainer).length) - oAfterRange = this._getNextNode(this.startContainer); - else - oAfterRange = xe.DOMFix.childNodes(this.startContainer)[this.startOffset]; - - if(this.endOffset == 0) - oBeforeRange = this._getPrevNode(this.endContainer); - else - oBeforeRange = xe.DOMFix.childNodes(this.endContainer)[this.endOffset-1]; - - if(bBefore){ - oResult = oBeforeRange; - if(!oResult && !bStrict) oResult = oAfterRange; - }else{ - oResult = oAfterRange; - if(!oResult && !bStrict) oResult = oBeforeRange; - } - - return oResult; - }, - - _getXPath : function(elNode){ - var sXPath = ""; - - while(elNode && elNode.nodeType == 1){ - sXPath = "/" + elNode.tagName+"["+this._getPosIdx4XPath(elNode)+"]" + sXPath; - elNode = xe.DOMFix.parentNode(elNode); - } - - return sXPath; - }, - - _getPosIdx4XPath : function(refNode){ - var idx = 0; - for(var node = refNode.previousSibling; node; node = node.previousSibling) - if(node.tagName == refNode.tagName) idx++; - - return idx; - }, - - // this was written specifically for XPath Bookmark and it may not perform correctly for general purposes - _evaluateXPath : function(sXPath, oDoc){ - sXPath = sXPath.substring(1, sXPath.length-1); - var aXPath = sXPath.split(/\//); - var elNode = oDoc.body; - - for(var i=2; i -1 && elContainer){ - var aChildNodes = xe.DOMFix.childNodes(elContainer); - var elNode = null; - - var nIdx = nTextNodeIdx; - var nOffsetLeft = nOffset; - - while((elNode = aChildNodes[nIdx]) && elNode.nodeType == 3 && elNode.nodeValue.length < nOffsetLeft){ - nOffsetLeft -= elNode.nodeValue.length; - nIdx++; - } - - elContainer = xe.DOMFix.childNodes(elContainer)[nIdx]; - nOffset = nOffsetLeft; - } - - if(!elContainer){ - elContainer = this._document.body; - nOffset = 0; - } - return {elContainer: elContainer, nOffset: nOffset}; - }, - - // this was written specifically for XPath Bookmark and it may not perform correctly for general purposes - getXPathBookmark : function(){ - var nTextNodeIdx1 = -1; - var htEndPt1 = {elContainer: this.startContainer, nOffset: this.startOffset}; - var elNode1 = this.startContainer; - if(elNode1.nodeType == 3){ - htEndPt1 = this._getFixedStartTextNode(); - nTextNodeIdx1 = this._getPosIdx(htEndPt1.elContainer); - elNode1 = xe.DOMFix.parentNode(elNode1); - } - var sXPathNode1 = this._getXPath(elNode1); - var oBookmark1 = {sXPath:sXPathNode1, nTextNodeIdx:nTextNodeIdx1, nOffset: htEndPt1.nOffset}; - - var nTextNodeIdx2 = -1; - var htEndPt2 = {elContainer: this.endContainer, nOffset: this.endOffset}; - var elNode2 = this.endContainer; - if(elNode2.nodeType == 3){ - htEndPt2 = this._getFixedEndTextNode(); - nTextNodeIdx2 = this._getPosIdx(htEndPt2.elContainer); - elNode2 = xe.DOMFix.parentNode(elNode2); - } - var sXPathNode2 = this._getXPath(elNode2); - var oBookmark2 = {sXPath:sXPathNode2, nTextNodeIdx:nTextNodeIdx2, nOffset: htEndPt2.nOffset}; - - return [oBookmark1, oBookmark2]; - }, - - moveToXPathBookmark : function(aBookmark){ - if(!aBookmark) return; - - var oBookmarkInfo1 = this._evaluateXPathBookmark(aBookmark[0]); - var oBookmarkInfo2 = this._evaluateXPathBookmark(aBookmark[1]); - - if(!oBookmarkInfo1["elContainer"] || !oBookmarkInfo2["elContainer"]) return; - - this.startContainer = oBookmarkInfo1["elContainer"]; - this.startOffset = oBookmarkInfo1["nOffset"]; - - this.endContainer = oBookmarkInfo2["elContainer"]; - this.endOffset = oBookmarkInfo2["nOffset"]; - }, - - _getFixedTextContainer : function(elNode, nOffset){ - while(elNode && elNode.nodeType == 3 && elNode.previousSibling && elNode.previousSibling.nodeType == 3){ - nOffset += elNode.previousSibling.nodeValue.length; - elNode = elNode.previousSibling; - } - - return {elContainer:elNode, nOffset:nOffset}; - }, - - _getFixedStartTextNode : function(){ - return this._getFixedTextContainer(this.startContainer, this.startOffset); - }, - - _getFixedEndTextNode : function(){ - return this._getFixedTextContainer(this.endContainer, this.endOffset); - }, - - placeStringBookmark : function(){ - var sTmpId = (new Date()).getTime(); - - var oInsertionPoint = this.cloneRange(); - oInsertionPoint.collapseToEnd(); - var oEndMarker = this._document.createElement("A"); - oEndMarker.id = this.HUSKY_BOOMARK_END_ID_PREFIX+sTmpId; - oInsertionPoint.insertNode(oEndMarker); - - var oInsertionPoint = this.cloneRange(); - oInsertionPoint.collapseToStart(); - var oStartMarker = this._document.createElement("A"); - oStartMarker.id = this.HUSKY_BOOMARK_START_ID_PREFIX+sTmpId; - oInsertionPoint.insertNode(oStartMarker); - - this.moveToBookmark(sTmpId); - - return sTmpId; - }, - - cloneRange : function(){ - return this._copyRange(new xe.XpressRange(this._window)); - }, - - moveToBookmark : function(vBookmark){ - if(typeof(vBookmark) != "object") - this.moveToStringBookmark(vBookmark); - else - this.moveToXPathBookmark(vBookmark); - }, - - moveToStringBookmark : function(sBookmarkID){ - var oStartMarker = this._document.getElementById(this.HUSKY_BOOMARK_START_ID_PREFIX+sBookmarkID); - var oEndMarker = this._document.getElementById(this.HUSKY_BOOMARK_END_ID_PREFIX+sBookmarkID); - - if(!oStartMarker || !oEndMarker) return; - - this.setEndBefore(oEndMarker); - this.setStartAfter(oStartMarker); - }, - - removeStringBookmark : function(sBookmarkID){ - var oStartMarker = this._document.getElementById(this.HUSKY_BOOMARK_START_ID_PREFIX+sBookmarkID); - var oEndMarker = this._document.getElementById(this.HUSKY_BOOMARK_END_ID_PREFIX+sBookmarkID); - - if(oStartMarker) xe.DOMFix.parentNode(oStartMarker).removeChild(oStartMarker); - if(oEndMarker) xe.DOMFix.parentNode(oEndMarker).removeChild(oEndMarker); - }, - - collapseToStart : function(){ - this.collapse(true); - }, - - collapseToEnd : function(){ - this.collapse(false); - }, - - createAndInsertNode : function(sTagName){ - tmpNode = this._document.createElement(tagName); - this.insertNode(tmpNode) - return tmpNode - }, - - getNodes : function(bSplitTextEndNodes, fnFilter){ - if(bSplitTextEndNodes) this._splitTextEndNodesOfTheRange(); - - var aAllNodes = this._getNodesInRange(); - var aFilteredNodes = []; - - if(!fnFilter) return aAllNodes; - - for(var i=0; i= 0) return true; - - if(bIncludePartlyIncluded){ - if(startToEnd == 1) return false; - if(endToStart == -1) return false; - return true; - } - - return false; - }, - - isNodeInRange : function(oNode, bIncludePartlySelected, bContentOnly){ - var oTmpRange = new xe.XpressRange(this._window); - - if(bContentOnly && oNode.firstChild){ - oTmpRange.setStartBefore(oNode.firstChild); - oTmpRange.setEndAfter(oNode.lastChild); - }else{ - oTmpRange.selectNode(oNode); - } - - return isRangeInRange(oTmpRange, bIncludePartlySelected); - }, - - pasteHTML : function(sHTML){ - if(sHTML == ""){ - this.deleteContents(); - return; - } - - var oTmpDiv = this._document.createElement("DIV"); - oTmpDiv.innerHTML = sHTML; - - var oFirstNode = oTmpDiv.firstChild; - var oLastNode = oTmpDiv.lastChild; - - var clone = this.cloneRange(); - var sBM = clone.placeStringBookmark(); - - while(oTmpDiv.lastChild) this.insertNode(oTmpDiv.lastChild); - - this.setEndNodes(oFirstNode, oLastNode); - - // delete the content later as deleting it first may mass up the insertion point - // eg)

[A]BCD

---paste O---> O

BCD

- clone.moveToBookmark(sBM); - clone.deleteContents(); - clone.removeStringBookmark(sBM); - }, - - toString : function(){ - this.toString = xe.W3CDOMRange.prototype.toString; - return this.toString(); - }, - - toHTMLString : function(){ - var oTmpContainer = this._document.createElement("DIV"); - oTmpContainer.appendChild(this.cloneContents()); - - return oTmpContainer.innerHTML; - }, - - findAncestorByTagName : function(sTagName){ - var oNode = this.commonAncestorContainer; - while(oNode && oNode.tagName != sTagName) oNode = xe.DOMFix.parentNode(oNode); - - return oNode; - }, - - selectNodeContents : function(oNode){ - if(!oNode) return; - - var oFirstNode = oNode.firstChild?oNode.firstChild:oNode; - var oLastNode = oNode.lastChild?oNode.lastChild:oNode; - - if(oFirstNode.nodeType == 3) - this.setStart(oFirstNode, 0); - else - this.setStartBefore(oFirstNode); - - if(oLastNode.nodeType == 3) - this.setEnd(oLastNode, oLastNode.nodeValue.length); - else - this.setEndAfter(oLastNode); - }, - - styleRange : function(oStyle, oAttribute, sNewSpanMarker){ - var aStyleParents = this._getStyleParentNodes(sNewSpanMarker); - if(aStyleParents.length < 1) return; - - var sName, sValue; - - for(var i=0; i= 0)){ - oSNode = this.getNodeAroundRange(false, true); - oENode = this.getNodeAroundRange(false, true); - oStart = this._getLineStartInfo(oSNode); - oEnd = this._getLineEndInfo(oENode); - } - - return {oStart: oStart, oEnd: oEnd}; - } -}).extend(xe.W3CDOMRange); - -/** - * @fileOverview This file contains cross-browser selection function - * @name SimpleSelection.js - */ -xe.SimpleSelection = function(win){ - this.init = function(win){ - this._window = win || window; - this._document = this._window.document; - }; - - this.init(win); - - if(jQuery.browser.msie) - xe.SimpleSelectionImpl_IE.apply(this); - else - xe.SimpleSelectionImpl_FF.apply(this); - - this.selectRange = function(oRng){ - this.selectNone(); - this.addRange(oRng); - }; - - this.selectionLoaded = true; - if(!this._oSelection) this.selectionLoaded = false; -}; - -xe.SimpleSelectionImpl_FF = function(){ - this._oSelection = this._window.getSelection(); - - this.getRangeAt = function(iNum){ - iNum = iNum || 0; - - try{ - var oFFRange = this._oSelection.getRangeAt(iNum); - }catch(e){return new xe.W3CDOMRange(this._document);} - - return this._FFRange2W3CRange(oFFRange); - }; - - this.addRange = function(oW3CRange){ - var oFFRange = this._W3CRange2FFRange(oW3CRange); - this._oSelection.addRange(oFFRange); - }; - - this.selectNone = function(){ - this._oSelection.removeAllRanges(); - }; - - this._FFRange2W3CRange = function(oFFRange){ - var oW3CRange = new xe.W3CDOMRange(this._document); - oW3CRange.setStart(oFFRange.startContainer, oFFRange.startOffset); - oW3CRange.setEnd(oFFRange.endContainer, oFFRange.endOffset); - return oW3CRange; - }; - - this._W3CRange2FFRange = function(oW3CRange){ - var oFFRange = this._document.createRange(); - oFFRange.setStart(oW3CRange.startContainer, oW3CRange.startOffset); - oFFRange.setEnd(oW3CRange.endContainer, oW3CRange.endOffset); - - return oFFRange; - }; -}; - -xe.SimpleSelectionImpl_IE = function(){ - this._oSelection = this._document.selection; - - this.getRangeAt = function(iNum){ - iNum = iNum || 0; - - if(this._oSelection.type == "Control"){ - var oW3CRange = new xe.W3CDOMRange(this._document); - - var oSelectedNode = this._oSelection.createRange().item(iNum); - - // if the selction occurs in a different document, ignore - if(!oSelectedNode || oSelectedNode.ownerDocument != this._document) return oW3CRange; - - oW3CRange.selectNode(oSelectedNode); - - return oW3CRange; - }else{ - var oSelectedNode = this._oSelection.createRangeCollection().item(iNum).parentElement(); - - // if the selction occurs in a different document, ignore - if(!oSelectedNode || oSelectedNode.ownerDocument != this._document){ - var oW3CRange = new xe.W3CDOMRange(this._document); - return oW3CRange; - } - return this._IERange2W3CRange(this._oSelection.createRangeCollection().item(iNum)); - } - }; - - this.addRange = function(oW3CRange){ - var oIERange = this._W3CRange2IERange(oW3CRange); - oIERange.select(); - }; - - this.selectNone = function(){ - this._oSelection.empty(); - }; - - this._W3CRange2IERange = function(oW3CRange){ - var oStartIERange = this._getIERangeAt(oW3CRange.startContainer, oW3CRange.startOffset); - var oEndIERange = this._getIERangeAt(oW3CRange.endContainer, oW3CRange.endOffset); - oStartIERange.setEndPoint("EndToEnd", oEndIERange); - - return oStartIERange; - }; - - this._getIERangeAt = function(oW3CContainer, iW3COffset){ - var oIERange = this._document.body.createTextRange(); - - var oEndPointInfoForIERange = this._getSelectableNodeAndOffsetForIE(oW3CContainer, iW3COffset); - - var oSelectableNode = oEndPointInfoForIERange.oSelectableNodeForIE; - var iIEOffset = oEndPointInfoForIERange.iOffsetForIE; - - oIERange.moveToElementText(oSelectableNode); - oIERange.collapse(oEndPointInfoForIERange.bCollapseToStart); - oIERange.moveStart("character", iIEOffset); - - return oIERange; - }; - - this._getSelectableNodeAndOffsetForIE = function(oW3CContainer, iW3COffset){ - var oIERange = this._document.body.createTextRange(); - - var oNonTextNode = null; - var aChildNodes = null; - var iNumOfLeftNodesToCount = 0; - - if(oW3CContainer.nodeType == 3){ - oNonTextNode = xe.DOMFix.parentNode(oW3CContainer); - aChildNodes = xe.DOMFix.childNodes(oNonTextNode); - iNumOfLeftNodesToCount = aChildNodes.length; - }else{ - oNonTextNode = oW3CContainer; - aChildNodes = xe.DOMFix.childNodes(oNonTextNode); - iNumOfLeftNodesToCount = iW3COffset; - } - - var oNodeTester = null; - - var iResultOffset = 0; - - var bCollapseToStart = true; - - for(var i=0; i=0) break; - - oPrevNonTextNode = aChildNodes[i]; - } - - var pointRangeIdx = i; - - if(pointRangeIdx != 0 && aChildNodes[pointRangeIdx-1].nodeType == 3){ - var oRgTextStart = this._document.body.createTextRange(); - var oCurTextNode = null; - if(oPrevNonTextNode){ - oRgTextStart.moveToElementText(oPrevNonTextNode); - oRgTextStart.collapse(false); - oCurTextNode = oPrevNonTextNode.nextSibling; - }else{ - oRgTextStart.moveToElementText(oContainer); - oRgTextStart.collapse(true); - oCurTextNode = oContainer.firstChild; - } - - var oRgTextsUpToThePoint = oRgOrigPoint.duplicate(); - oRgTextsUpToThePoint.setEndPoint("StartToStart", oRgTextStart); - - var textCount = oRgTextsUpToThePoint.text.length - - while(textCount > oCurTextNode.nodeValue.length && oCurTextNode.nextSibling){ - textCount -= oCurTextNode.nodeValue.length; - oCurTextNode = oCurTextNode.nextSibling; - } - - // this will enforce IE to re-reference oCurTextNode - var oTmp = oCurTextNode.nodeValue; - - if(bStartPt && oCurTextNode.nextSibling && oCurTextNode.nextSibling.nodeType == 3 && textCount == oCurTextNode.nodeValue.length){ - textCount -= oCurTextNode.nodeValue.length; - oCurTextNode = oCurTextNode.nextSibling; - } - - oContainer = oCurTextNode; - offset = textCount; - }else{ - oContainer = oRgOrigPoint.parentElement(); - offset = pointRangeIdx; - } - - return {"oContainer" : oContainer, "iOffset" : offset}; - }; -} - -xe.DOMFix = new (jQuery.Class({ - $init : function(){ - if(jQuery.browser.msie || jQuery.browser.opera){ - this.childNodes = this._childNodes_Fix; - this.parentNode = this._parentNode_Fix; - }else{ - this.childNodes = this._childNodes_Native; - this.parentNode = this._parentNode_Native; - } - }, - - _parentNode_Native : function(elNode){ - return elNode.parentNode; - }, - - _parentNode_Fix : function(elNode){ - if(!elNode) return elNode; - - while(elNode.previousSibling){elNode = elNode.previousSibling;} - - return elNode.parentNode; - }, - - _childNodes_Native : function(elNode){ - return elNode.childNodes; - }, - - _childNodes_Fix : function(elNode){ - var aResult = null; - var nCount = 0; - - if(elNode){ - var aResult = []; - elNode = elNode.firstChild; - while(elNode){ - aResult[nCount++] = elNode; - elNode=elNode.nextSibling; - } - } - - return aResult; - } -}))(); -/** - * @fileOverview This file contains a function that takes care of various operations related to find and replace - * @name N_FindReplace.js - */ -xe.FindReplace = jQuery.Class({ - sKeyword : "", - window : null, - document : null, - bBrowserSupported : false, - - // true if End Of Contents is reached during last execution of find - bEOC : false, - - $init : function(win){ - this.window = win; - this.document = this.window.document; - - if(this.document.domain != this.document.location.hostname){ - if(jQuery.browser.mozilla && jQuery.browser.nVersion < 3){ - this.bBrowserSupported = false; - this.find = function(){return 3}; - return; - } - } - - this.bBrowserSupported = true; - }, - - // 0: found - // 1: not found - // 2: keyword required - // 3: browser not supported - find : function(sKeyword, bCaseMatch, bBackwards, bWholeWord){ - var bSearchResult, bFreshSearch; - - this.window.focus(); - - if(!sKeyword) return 2; - - // try find starting from current cursor position - this.bEOC = false; - bSearchResult = this.findNext(sKeyword, bCaseMatch, bBackwards, bWholeWord); - if(bSearchResult) return 0; - - // end of the contents could have been reached so search again from the beginning - this.bEOC = true; - bSearchResult = this.findNew(sKeyword, bCaseMatch, bBackwards, bWholeWord); - - if(bSearchResult) return 0; - - return 1; - }, - - findNew : function (sKeyword, bCaseMatch, bBackwards, bWholeWord){ - this.findReset(); - return this.findNext(sKeyword, bCaseMatch, bBackwards, bWholeWord); - }, - - findNext : function(sKeyword, bCaseMatch, bBackwards, bWholeWord){ - var bSearchResult; - bCaseMatch = bCaseMatch || false; - bWholeWord = bWholeWord || false; - bBackwards = bBackwards || false; - - if(this.window.find){ - var bWrapAround = false; - return this.window.find(sKeyword, bCaseMatch, bBackwards, bWrapAround, bWholeWord); - } - - // IE solution - if(this.document.body.createTextRange){ - var iOption = 0; - if(bBackwards) iOption += 1; - if(bWholeWord) iOption += 2; - if(bCaseMatch) iOption += 4; - - this.window.focus(); - this._range = this.document.selection.createRangeCollection().item(0); - this._range.collapse(false); - bSearchResult = this._range.findText(sKeyword, 1, iOption); - - this._range.select(); - return bSearchResult; - } - - return false; - }, - - findReset : function() { - if (this.window.find){ - this.window.getSelection().removeAllRanges(); - return; - } - - // IE solution - if(this.document.body.createTextRange){ - this._range = this.document.body.createTextRange(); - this._range.collapse(true); - this._range.select(); - } - }, - - // 0: replaced & next word found - // 1: replaced & next word not found - // 2: not replaced & next word found - // 3: not replaced & next word not found - // 4: sOriginalWord required - replace : function(sOriginalWord, Replacement, bCaseMatch, bBackwards, bWholeWord){ - if(!sOriginalWord) return 4; - - var oSelection = new xe.XpressRange(this.window); - oSelection.setFromSelection(); - - bCaseMatch = bCaseMatch || false; - var bMatch, selectedText = oSelection.toString(); - if(bCaseMatch) - bMatch = (selectedText == sOriginalWord); - else - bMatch = (selectedText.toLowerCase() == sOriginalWord.toLowerCase()); - - if(!bMatch) - return this.find(sOriginalWord, bCaseMatch, bBackwards, bWholeWord)+2; - - if(typeof Replacement == "function"){ - // the returned oSelection must contain the replacement - oSelection = Replacement(oSelection); - }else{ - oSelection.pasteHTML(Replacement); - } - - // force it to find the NEXT occurance of sOriginalWord - oSelection.select(); - - return this.find(sOriginalWord, bCaseMatch, bBackwards, bWholeWord); - }, - - // returns number of replaced words - // -1 : if original word is not given - replaceAll : function(sOriginalWord, Replacement, bCaseMatch, bWholeWord){ - if(!sOriginalWord) return -1; - - var bBackwards = false; - - var iReplaceResult; - var iResult = 0; - var win = this.window; - var oSelection = new xe.XpressRange(this.window); - oSelection.setFromSelection(); - var sBookmark = oSelection.placeStringBookmark(); - - this.bEOC = false; - while(!this.bEOC){ - iReplaceResult = this.replace(sOriginalWord, Replacement, bCaseMatch, bBackwards, bWholeWord); - if(iReplaceResult == 0 || iReplaceResult == 1) iResult++; - } - - var startingPointReached = function(){ - var oCurSelection = new xe.XpressRange(win); - oCurSelection.setFromSelection(); - - oSelection.moveToBookmark(sBookmark); - var pos = oSelection.compareBoundaryPoints(xe.W3CDOMRange.START_TO_END, oCurSelection); - - if(pos == 1) return false; - return true; - } - - iReplaceResult = 0; - this.bEOC = false; - while(!startingPointReached() && iReplaceResult == 0 && !this.bEOC){ - iReplaceResult = this.replace(sOriginalWord, Replacement, bCaseMatch, bBackwards, bWholeWord); - if(iReplaceResult == 0 || iReplaceResult == 1) iResult++; - } - - oSelection.moveToBookmark(sBookmark); - oSelection.select(); - oSelection.removeStringBookmark(sBookmark); - - return iResult; - } -}); - -/** - * @fileOverview This file contains a function that takes care of the draggable layers - * @name N_DraggableLayer.js - */ -xe.DraggableLayer = jQuery.Class({ - $init : function(oLayer, oOptions){ - this.oOptions = jQuery.extend({ - bModal : "false", - oHandle : oLayer, - iMinX : -999999, - iMinY : -999999, - iMaxX : 999999, - iMaxY : 999999 - }, oOptions); - - this.oHandle = this.oOptions.oHandle; - - oLayer.style.display = "block"; - oLayer.style.position = "absolute"; - oLayer.style.zIndex = "9999"; - - this.aBasePosition = this.getBaseOffset(oLayer); - - // "number-ize" the position and set it as inline style. (the position could've been set as "auto" or set by css, not inline style) - oLayer.style.top = (this.toInt(jQuery(oLayer).offset().top) - this.aBasePosition.top)+"px"; - oLayer.style.left = (this.toInt(jQuery(oLayer).offset().left) - this.aBasePosition.left)+"px"; - - this.$FnMouseDown = jQuery.fnBind(this._mousedown, this, oLayer); - this.$FnMouseMove = jQuery.fnBind(this._mousemove, this, oLayer); - this.$FnMouseUp = jQuery.fnBind(this._mouseup, this, oLayer); - - jQuery(this.oHandle).bind("mousedown", this.$FnMouseDown); - }, - - _mousedown : function(oLayer, oEvent){ - if(oEvent.target.tagName == "INPUT") return; - - this.MouseOffsetY = (oEvent.pageY-this.toInt(oLayer.style.top)-this.aBasePosition['top']); - this.MouseOffsetX = (oEvent.pageX-this.toInt(oLayer.style.left)-this.aBasePosition['left']); - - jQuery(oLayer).bind("mousemove", this.$FnMouseMove); - jQuery(oLayer).bind("mouseup", this.$FnMouseUp); - }, - - _mousemove : function(oLayer, oEvent){ - var iTop = (oEvent.pageY-this.MouseOffsetY-this.aBasePosition['top']); - var iLeft = (oEvent.pageX-this.MouseOffsetX-this.aBasePosition['left']); - - if(iTopthis.oOptions.iMaxY) iTop = this.oOptions.iMaxY; - - if(iLeftthis.oOptions.iMaxX) iLeft = this.oOptions.iMaxX; - - oLayer.style.top = iTop + "px"; - oLayer.style.left = iLeft + "px"; - }, - - _mouseup : function(oLayer, oEvent){ - jQuery(oLayer).unbind("mousemove", this.$FnMouseMove); - jQuery(oLayer).unbind("mouseup", this.$FnMouseUp); - }, - - toInt : function(num){ - var result = parseInt(num); - return result || 0; - }, - - findNonStatic : function(oEl){ - if(!oEl) return null; - if(oEl.tagName == "BODY") return oEl; - - if(jQuery(oEl).css("position").match(/absolute|relative/i)) return oEl; - - return this.findNonStatic(oEl.offsetParent); - }, - - getBaseOffset : function(oEl){ - var oBase = this.findNonStatic(oEl.offsetParent); - var tmp = jQuery(oBase).offset(); - - return {top: tmp.top, left: tmp.left}; - } -}); -//{ -/** - * @fileOverview This file contains Xpress plugin that takes care of the messages related to core operations - * @name hp_CorePlugin.js - */ -xe.CorePlugin = jQuery.Class({ - name : "CorePlugin", - - $init : function(funcOnReady){ - this.funcOnReady = funcOnReady; - }, - - $AFTER_MSG_APP_READY : function(){ - this.oApp.exec("EXEC_ON_READY_FUNCTION", []); - }, - - $ON_ADD_APP_PROPERTY : function(sPropertyName, oProperty){ - this.oApp[sPropertyName] = oProperty; - }, - - $ON_REGISTER_BROWSER_EVENT : function(obj, sEvent, sCMD, aParams, nDelay){ - this.oApp.registerBrowserEvent(obj, sEvent, sCMD, aParams, nDelay); - }, - - $ON_DISABLE_COMMAND : function(sCommand){ - this.oApp.disableCommand(sCommand, true); - }, - - $ON_ENABLE_COMMAND : function(sCommand){ - this.oApp.disableCommand(sCommand, false); - }, - - $ON_EXEC_ON_READY_FUNCTION : function(){ - if(typeof this.funcOnReady == "function") this.funcOnReady(); - } -}); -//} -//{ -/** - * @fileOverview This file contains Xpress plugin that helps various operations. - * @name hp_Utils.js - */ - xe.Utils = jQuery.Class({ - name : "Utils", - - $init : function(){ - if(jQuery.browser.msie && jQuery.browser.nVersion == 6){ - try{ - document.execCommand('BackgroundImageCache', false, true); - }catch(e){} - } - }, - - $ON_ATTACH_HOVER_EVENTS : function(aElms, sHoverClass){ - sHoverClass = sHoverClass || "hover"; - - if(!aElms) return; - - jQuery(aElms).hover( - function(){jQuery(this).addClass(sHoverClass)}, - function(){jQuery(this).removeClass(sHoverClass)} - ); - } -}); -//} - -//{ -/** - * @fileOverview This file contains Xpress plugin that bridges the XpressRange function - * @name hp_XpressRangeManager.js - */ -xe.XpressRangeManager = jQuery.Class({ - name : "XpressRangeManager", - - oWindow : null, - - $init : function(win){ - this.oWindow = win || window; - }, - - $BEFORE_MSG_APP_READY : function(){ - if(this.oWindow && this.oWindow.tagName == "IFRAME") - this.oWindow = this.oWindow.contentWindow; - - this.oApp.exec("ADD_APP_PROPERTY", ["getSelection", jQuery.fnBind(this.getSelection, this)]); - this.oApp.exec("ADD_APP_PROPERTY", ["getEmptySelection", jQuery.fnBind(this.getEmptySelection, this)]); - }, - - $ON_SET_EDITING_WINDOW : function(oWindow){ - this.oWindow = oWindow; - }, - - getEmptySelection : function(){ - var oXpressRange = new xe.XpressRange(this.oWindow); - return oXpressRange; - }, - - getSelection : function(){ - this.oApp.exec("RESTORE_IE_SELECTION", []); - - var oXpressRange = this.getEmptySelection(); - - // this may throw an exception if the selected is area is not yet shown - try{ - oXpressRange.setFromSelection(); - }catch(e){} - - return oXpressRange; - } -}); -//} -xe.Hotkey = jQuery.Class({ - name : "Hotkey", - - storage : {}, - keyhash : {}, - - $init : function(){ - this.storage = {}; - - this.keyhash = { - backspace : 8, - tab : 9, - enter : 13, - shift : 16, - ctrl : 17, - alt : 18, - meta : 224, - esc : 27, - space : 32, - pageup : 33, - pagedown : 34, - end : 35, - home : 36, - left : 37, - up : 38, - right : 39, - down : 40, - del : 46, - comma : 188,//(,) - period : 190,//(.) - slash : 191,//(/) - hyphen : 109, - equal : 61 - }; - - if (jQuery.browser.msie || jQuery.browser.safari) { - this.keyhash.hyphen = 189; // (-) - this.keyhash.equal = 187; // (=) - this.keyhash.meta = 91; // meta - } - - - }, - - $ON_MSG_APP_READY : function(){ - jQuery(this.oApp.getWYSIWYGDocument() || document).keydown(jQuery.fnBind(this.keydown, this)); - }, - - $ON_REGISTER_HOTKEY : function(sHotkey, sCMD, sArgs){ - if(!sArgs) sArgs = []; - var func = jQuery.fnBind(this.oApp.exec, this.oApp, sCMD, sArgs); - - sHotkey = this.normalize(sHotkey); - if (!sHotkey) return false; - - this.add(sHotkey, func); - }, - - add : function(sHotkey, func) { - if (typeof this.storage[sHotkey] == 'undefined') { - this.storage[sHotkey] = [func]; - } else { - this.storage[sHotkey].push(func); - } - }, - - keydown : function(event) { - var key = [], kh = this.keyhash; - - if (jQuery.inArray(event.keyCode, [kh.shift, kh.ctrl, kh.alt, kh.meta]) >= 0) return; - - if (event.shiftKey) key.push('shift'); - if (event.altKey) key.push('alt'); - if (event.ctrlKey) key.push('ctrl'); - if (event.metaKey) key.push('meta'); - if (!key.length) return; - if (key.length == 1 && event.metaKey) key = ['ctrl', 'meta']; - - key.push(event.keyCode); - - key = key.join('+'); - - if (!this.storage[key]) return; - - jQuery.each(this.storage[key], function(){ this(); }); - - return false; - }, - - normalize : function(sHotkey) { - var shift, ctrl, alt, meta, key, keys = (sHotkey||"").toLowerCase().split('+'); - - shift = ctrl = alt = meta = key = false; - - jQuery.each(keys, function(){ - var s = ""+this; - switch(s) { - case 'shift': shift = true; - case 'alt' : alt = true; - case 'ctrl' : ctrl = true; - case 'meta' : meta = true; - default: - key = s; - } - }); - - if (!key) return ''; - - keys = []; - if (shift) keys.push('shift'); - if (alt) keys.push('alt'); - if (ctrl) keys.push('ctrl'); - if (meta || (ctrl && !shift && !alt)) keys.push('meta'); - - keys.push(this.keyhash[key] || key.toUpperCase().charCodeAt(0)); - - return keys.join('+'); - } -}); - -//{ -/** - * @fileOverview This file contains Xpress plugin that takes care of the draggable layers - * @name hp_DialogLayerManager.js - */ -xe.DialogLayerManager = jQuery.Class({ - name : "DialogLayerManager", - aMadeDraggable : null, - aOpenedLayers : null, - - $init : function(){ - this.aMadeDraggable = []; - this.aOpenedLayers = []; - }, - - $ON_SHOW_DIALOG_LAYER : function(oLayer, bModal){ - oLayer = jQuery.$(oLayer); - bModal = jQuery.$(bModal) || false; - if(!oLayer) return; - - if(jQuery.inArray(oLayer, this.aOpenedLayers)) return; - - this.oApp.exec("POSITION_DIALOG_LAYER", [oLayer]); - - this.aOpenedLayers[this.aOpenedLayers.length] = oLayer; - - if(!jQuery.inArray(oLayer, this.aMadeDraggable)){ - new xe.DraggableLayer(oLayer, {bModal: bModal, iMinY: 0}); - this.aMadeDraggable[this.aMadeDraggable.length] = oLayer; - }else{ - oLayer.style.display = "block"; - } - }, - - $ON_HIDE_LAST_DIALOG_LAYER : function(){ - this.oApp.exec("HIDE_DIALOG_LAYER", [this.aOpenedLayers[this.aOpenedLayers.length-1]]); - }, - - $ON_HIDE_ALL_DIALOG_LAYER : function(){ - for(var i=this.aOpenedLayers.length-1; i>=0; i--) - this.oApp.exec("HIDE_DIALOG_LAYER", [this.aOpenedLayers[i]]); - }, - - $ON_HIDE_DIALOG_LAYER : function(oLayer){ - oLayer = jQuery.$(oLayer); - - if(oLayer) oLayer.style.display = "none"; - this.aOpenedLayers = jQuery.grep(this.aOpenedLayers, function(a){return a!=oLayer}); - }, - - $ON_SET_DIALOG_LAYER_POSITION : function(oLayer, iTop, iLeft){ - oLayer.style.top = iTop; - oLayer.style.left = iLeft; - } -}); -//} -//{ -/** - * @fileOverview This file contains Xpress plugin that takes care of the layers that should disappear when the focus is lost - * @name hp_ActiveLayerManager.js - */ -xe.ActiveLayerManager = jQuery.Class({ - name : "ActiveLayerManager", - oCurrentLayer : null, - - $ON_TOGGLE_ACTIVE_LAYER : function(oLayer, sOnOpenCmd, aOnOpenParam, sOnCloseCmd, aOnCloseParam){ - if(oLayer == this.oCurrentLayer){ - this.oApp.exec("HIDE_ACTIVE_LAYER", []); - }else{ - this.oApp.exec("SHOW_ACTIVE_LAYER", [oLayer, sOnCloseCmd, aOnCloseParam]); - if(sOnOpenCmd) this.oApp.exec(sOnOpenCmd, aOnOpenParam); - } - }, - - $ON_SHOW_ACTIVE_LAYER : function(oLayer, sOnCloseCmd, aOnCloseParam){ - oLayer = jQuery.$(oLayer); - this.sOnCloseCmd = sOnCloseCmd; - this.aOnCloseParam = aOnCloseParam; - - var oPrevLayer = this.oCurrentLayer; - - if(oLayer == oPrevLayer) return; - - this.oApp.exec("HIDE_ACTIVE_LAYER", []); - - oLayer.style.display = "block"; - this.oCurrentLayer = oLayer; - }, - - $ON_HIDE_ACTIVE_LAYER : function(){ - var oLayer = this.oCurrentLayer; - if(!oLayer) return; - oLayer.style.display = "none"; - this.oCurrentLayer = null; - - if(this.sOnCloseCmd) - this.oApp.exec(this.sOnCloseCmd, this.aOnCloseParam); - }, - - // for backward compatibility only. - // use HIDE_ACTIVE_LAYER instead! - $ON_HIDE_CURRENT_ACTIVE_LAYER : function(){ - this.oApp.exec("HIDE_ACTIVE_LAYER", []); - }, - - $ON_EVENT_EDITING_AREA_KEYDOWN : function(){ - this.oApp.exec("HIDE_ACTIVE_LAYER", []); - }, - - $ON_EVENT_EDITING_AREA_MOUSEDOWN : function(){ - this.oApp.exec("HIDE_ACTIVE_LAYER", []); - } -}); -//} -//{ -/** - * @fileOverview This file contains Xpress plugin that takes care of the operations related to string conversion. Ususally used to convert the IR value. - * @name hp_StringConverterManager.js - */ -xe.StringConverterManager = jQuery.Class({ - name : "StringConverterManager", - - oConverters : null, - - $init : function(){ - this.oConverters = {}; - }, - - $BEFORE_MSG_APP_READY : function(){ - this.oApp.exec("ADD_APP_PROPERTY", ["applyConverter", jQuery.fnBind(this.applyConverter, this)]); - this.oApp.exec("ADD_APP_PROPERTY", ["addConverter", jQuery.fnBind(this.addConverter, this)]); - }, - - applyConverter : function(sRuleName, sContent){ - var aConverters = this.oConverters[sRuleName]; - if(!aConverters) return sContent; - - for(var i=0; i*:first-child", aAllLi[i]).get(0); - } - } - }, - - $ON_MSG_APP_READY : function(){ - this.oApp.registerBrowserEvent(this.toolbarArea, "mouseover", "EVENT_TOOLBAR_MOUSEOVER", []); - this.oApp.registerBrowserEvent(this.toolbarArea, "mouseout", "EVENT_TOOLBAR_MOUSEOUT", []); - - this.oApp.exec("ADD_APP_PROPERTY", ["getToolbarButtonByUIName", jQuery.fnBind(this.getToolbarButtonByUIName, this)]); - }, - - $ON_EVENT_TOOLBAR_MOUSEOVER : function(weEvent){ - if(weEvent.target.tagName == "BUTTON") jQuery(weEvent.target).addClass("hover").parent("span").addClass("hover"); - }, - - $ON_EVENT_TOOLBAR_MOUSEOUT : function(weEvent){ - if(weEvent.target.tagName == "BUTTON") jQuery(weEvent.target).removeClass("hover").parent("span").removeClass("hover"); - }, - - $ON_TOGGLE_TOOLBAR_ACTIVE_LAYER : function(oLayer, oBtn, sOpenCmd, aOpenArgs, sCloseCmd, aCloseArgs){ - this.oApp.exec("TOGGLE_ACTIVE_LAYER", [oLayer, "MSG_TOOLBAR_LAYER_SHOWN", [oLayer, oBtn, sOpenCmd, aOpenArgs], sCloseCmd, aCloseArgs]); - }, - - $ON_MSG_TOOLBAR_LAYER_SHOWN : function(oLayer, oBtn, aOpenCmd, aOpenArgs){ - this.oApp.exec("POSITION_TOOLBAR_LAYER", [oLayer, oBtn]); - if(aOpenCmd) this.oApp.exec(aOpenCmd, aOpenArgs); - }, - - $ON_SHOW_TOOLBAR_ACTIVE_LAYER : function(oLayer, sCmd, aArgs, oBtn){ - this.oApp.exec("SHOW_ACTIVE_LAYER", [oLayer, sCmd, aArgs]); - this.oApp.exec("POSITION_TOOLBAR_LAYER", [oLayer, oBtn]); - }, - - $ON_ENABLE_UI : function(sUIName){ - var elUI = this.htUIList[sUIName]; - if(!elUI) return; - jQuery(elUI).removeClass("off"); - elUI.disabled = false; - - // enable related commands - var sCmd = ""; - if(this.aUICmdMap[sUIName]){ - for(var i=0; i nToolbarLeft) oLayer.style.left = (nToolbarLeft-nLayerLeft-5)+"px"; - }, - - getToolbarButtonByUIName : function(sUIName){ - return this.htUIList[sUIName]; - } -}); -//} -//{ -/** - * @fileOverview This file contains Xpress plugin that manages multiple number editing area plugins and the IR value - * @name hp_XE_EditingAreaManager.js - */ -xe.XE_EditingAreaManager = jQuery.Class({ - name : "XE_EditingAreaManager", - - // Currently active plugin instance(XE_EditingArea_???) - oActivePlugin : null, - - // Intermediate Representation of the content being edited. - // This should be a textarea element. - oIRField : null, - - bIsDirty : false, - - $init : function(sInitialMode, oIRField, oDimension, fOnBeforeUnload, oAppContainer){ - this.sInitialMode = sInitialMode; - this.oIRField = jQuery.$(oIRField); - this._assignHTMLObjects(oAppContainer); - this.fOnBeforeUnload = fOnBeforeUnload; - - this.oEditingMode = {}; - - this.elEditingAreaContainer.style.height = parseInt(oDimension.nHeight || this.elEditingAreaContainer.offsetHeight)+"px"; - - this.nMinHeight = oDimension.nMinHeight || 10; - this.niMinWidth = oDimension.nMinWidth || 10; - }, - - _assignHTMLObjects : function(oAppContainer){ - oAppContainer = jQuery.$(oAppContainer) || document; - this.elEditingAreaContainer = jQuery("DIV.xpress_xeditor_editing_area_container", oAppContainer).get(0); - this.elEditingAreaSkipUI = jQuery("A.skip", oAppContainer).get(0); - }, - - $BEFORE_MSG_APP_READY : function(msg){ - this.oApp.exec("ADD_APP_PROPERTY", ["elEditingAreaContainer", this.elEditingAreaContainer]); - this.oApp.exec("ADD_APP_PROPERTY", ["getIR", jQuery.fnBind(this.getIR, this)]); - this.oApp.exec("ADD_APP_PROPERTY", ["setIR", this.setIR]); - this.oApp.exec("ADD_APP_PROPERTY", ["getEditingMode", jQuery.fnBind(this.getEditingMode, this)]); - }, - - $ON_MSG_APP_READY : function(){ - this.oApp.exec("CHANGE_EDITING_MODE", [this.sInitialMode, true]); - this.oApp.exec("LOAD_IR_FIELD", [false]); - - this.oApp.registerBrowserEvent(this.elEditingAreaSkipUI, "focus", "MSG_EDITING_AREA_SIZE_CHANGED", [], 50); - this.oApp.registerBrowserEvent(this.elEditingAreaSkipUI, "blur", "MSG_EDITING_AREA_SIZE_CHANGED", [], 50); - - var fOnBeforeUnload = this.fOnBeforeUnload||function(){if(this.getIR() != this.oIRField.value || this.bIsDirty) return this.oApp.$MSG("XE_EditingAreaManager.onExit")}; - jQuery(window).bind("beforeunload", jQuery.fnBind(fOnBeforeUnload, this)); - }, - - $AFTER_MSG_APP_READY : function(){ - this.oApp.exec("UPDATE_IR_FIELD", []); - }, - - $ON_LOAD_IR_FIELD : function(bDontAddUndo){ - this.oApp.setIR(this.oIRField.value, bDontAddUndo); - }, - - $ON_UPDATE_IR_FIELD : function(){ - this.oIRField.value = this.oApp.getIR(); - }, - - $BEFORE_CHANGE_EDITING_MODE : function(sMode){ - this._oPrevActivePlugin = this.oActivePlugin; - this.oActivePlugin = this.oEditingMode[sMode]; - }, - - $AFTER_CHANGE_EDITING_MODE : function(sMode, bNoFocus){ - if(this._oPrevActivePlugin){ - var sIR = this._oPrevActivePlugin.getIR(); - this.oApp.exec("SET_IR", [sIR]); - - this.oApp.exec("ENABLE_UI", [this._oPrevActivePlugin.sMode]); - - this._setEditingAreaDimension(); - } - this.oApp.exec("DISABLE_UI", [this.oActivePlugin.sMode]); - - if(!bNoFocus){ - this.oApp.exec("FOCUS", []); - } - }, - - $ON_SET_IS_DIRTY : function(bIsDirty){ - this.bIsDirty = bIsDirty; - }, - - $ON_FOCUS : function(){ - if(!this.oActivePlugin || typeof this.oActivePlugin.setIR != "function") return - - this.oActivePlugin.focus(); - }, - - $BEFORE_SET_IR : function(sIR, bDontAddUndoHistory){ - bDontAddUndoHistory = bDontAddUndoHistory || false; - if(!bDontAddUndoHistory) this.oApp.exec("RECORD_UNDO_ACTION", ["SET CONTENTS"]); - }, - - $ON_SET_IR : function(sIR){ - if(!this.oActivePlugin || typeof this.oActivePlugin.setIR != "function") return - - this.oActivePlugin.setIR(sIR); - }, - - $AFTER_SET_IR : function(sIR, bDontAddUndoHistory){ - bDontAddUndoHistory = bDontAddUndoHistory || false; - if(!bDontAddUndoHistory) this.oApp.exec("RECORD_UNDO_ACTION", ["SET CONTENTS"]); - }, - - $ON_REGISTER_EDITING_AREA : function(oEditingAreaPlugin){ - this.oEditingMode[oEditingAreaPlugin.sMode] = oEditingAreaPlugin; - this.attachDocumentEvents(oEditingAreaPlugin.oEditingArea); - }, - - $ON_MSG_EDITING_AREA_RESIZE_STARTED : function(){ - this.oActivePlugin.elEditingArea.style.display = "none"; - - this.iStartingHeight = parseInt(this.elEditingAreaContainer.style.height); - }, - - $ON_RESIZE_EDITING_AREA: function(ipNewWidth, ipNewHeight){ - var iNewWidth = parseInt(ipNewWidth); - var iNewHeight = parseInt(ipNewHeight); - - if(iNewWidth < this.niMinWidth) iNewWidth = this.niMinWidth; - if(iNewHeight < this.nMinHeight) iNewHeight = this.nMinHeight; - - if(ipNewWidth) this.elEditingAreaContainer.style.width = iNewWidth + "px"; - if(ipNewHeight) this.elEditingAreaContainer.style.height = iNewHeight + "px"; - }, - - $ON_RESIZE_EDITING_AREA_BY : function(ipWidthChange, ipHeightChange){ - var iWidthChange = parseInt(ipWidthChange); - var iHeightChange = parseInt(ipHeightChange); - - var iWidth = this.elEditingAreaContainer.style.width?parseInt(this.elEditingAreaContainer.style.width)+iWidthChange:null; - var iHeight = this.elEditingAreaContainer.style.height?this.iStartingHeight+iHeightChange:null; - - this.oApp.exec("RESIZE_EDITING_AREA", [iWidth, iHeight]); - }, - - $ON_MSG_EDITING_AREA_RESIZE_ENDED : function(FnMouseDown, FnMouseMove, FnMouseUp){ - this.oActivePlugin.elEditingArea.style.display = "block"; - this._setEditingAreaDimension(); - }, - - _setEditingAreaDimension : function(){ - this.oActivePlugin.elEditingArea.style.height = this.elEditingAreaContainer.style.height; - this.oActivePlugin.elEditingArea.style.width = this.elEditingAreaContainer.style.width; - }, - - attachDocumentEvents : function(doc){ - this.oApp.registerBrowserEvent(doc, "click", "EVENT_EDITING_AREA_CLICK"); - this.oApp.registerBrowserEvent(doc, "mousedown", "EVENT_EDITING_AREA_MOUSEDOWN"); - this.oApp.registerBrowserEvent(doc, "mousemove", "EVENT_EDITING_AREA_MOUSEMOVE"); - this.oApp.registerBrowserEvent(doc, "mouseup", "EVENT_EDITING_AREA_MOUSEUP"); - this.oApp.registerBrowserEvent(doc, "keydown", "EVENT_EDITING_AREA_KEYDOWN"); - this.oApp.registerBrowserEvent(doc, "keypress", "EVENT_EDITING_AREA_KEYPRESS"); - this.oApp.registerBrowserEvent(doc, "keyup", "EVENT_EDITING_AREA_KEYUP"); - }, - - getIR : function(){ - return this.oActivePlugin.getIR(); - }, - - setIR : function(sIR, bDontAddUndo){ - this.oApp.exec("SET_IR", [sIR, bDontAddUndo]); - }, - - getEditingMode : function(){ - return this.oActivePlugin.sMode; - } -}); -//} - -//{ -/** - * @fileOverview This file contains Xpress plugin that takes care of the operations directly related to editing the HTML source code using Textarea element - * @name hp_XE_EditingArea_HTMLSrc.js - * @required XE_EditingAreaManager - */ -xe.XE_EditingArea_HTMLSrc = jQuery.Class({ - name : "XE_EditingArea_HTMLSrc", - - sMode : "HTMLSrc", - textarea : null, - - $init : function(textarea){ - this.textarea = jQuery.$(textarea); - this.elEditingArea = this.textarea; - }, - - $BEFORE_MSG_APP_READY : function(){ - this.oEditingArea = this.textarea; - this.oApp.exec("REGISTER_EDITING_AREA", [this]); - }, - - $ON_CHANGE_EDITING_MODE : function(sMode, bNoFocus){ - if(sMode == this.sMode){ - this.textarea.style.display = "block"; - }else{ - this.textarea.style.display = "none"; - } - }, - - $ON_PASTE_HTML : function(sHTML, oPSelection){ - if(this.oApp.getEditingMode() != this.sMode) return; - - var o = new TextRange(this.textarea); - o.paste(sHTML); - this.textarea.focus(); - }, - - getIR : function(){ - var sIR; - var sContent = this.textarea.value; - - if(this.oApp.applyConverter) - sIR = this.oApp.applyConverter(this.sMode+"_TO_IR", sContent); - else - sIR = sContent; - - return sIR; - }, - - setIR : function(sIR){ - var sContent; - - if(this.oApp.applyConverter) - sContent = this.oApp.applyConverter("IR_TO_"+this.sMode, sIR); - else - sContent = sIR; - - this.textarea.value = sContent; - }, - - focus : function(){ - this.textarea.focus(); - } -}); - -var TextRange = function(oEl) { - this._o = oEl; -}; - -/** - * Selection for textfield - * - * @author hooriza - */ -TextRange.prototype.getSelection = function() { - var obj = this._o; - var ret = [ -1, -1 ]; - - if (isNaN(this._o.selectionStart)) { - obj.focus(); - - // textarea support added by nagoon97 - var range = document.body.createTextRange(); - var rangeField = null; - - rangeField = document.selection.createRange().duplicate(); - range.moveToElementText(obj); - rangeField.collapse(true); - range.setEndPoint("EndToEnd", rangeField); - ret[0] = range.text.length; - - rangeField = document.selection.createRange().duplicate(); - range.moveToElementText(obj); - rangeField.collapse(false); - range.setEndPoint("EndToEnd", rangeField); - ret[1] = range.text.length; - - obj.blur(); - } else { - ret[0] = obj.selectionStart; - ret[1] = obj.selectionEnd; - } - - return ret; -}; - -TextRange.prototype.setSelection = function(start, end) { - - var obj = this._o; - if (typeof end == 'undefined') end = start; - - if (obj.setSelectionRange) { - - obj.setSelectionRange(start, end); - - } else if (obj.createTextRange) { - - var range = obj.createTextRange(); - - range.collapse(true); - range.moveStart("character", start); - range.moveEnd("character", end - start); - range.select(); - - obj.blur(); - } - -}; - -TextRange.prototype.copy = function() { - - var r = this.getSelection(); - return this._o.value.substring(r[0], r[1]); - -}; - -TextRange.prototype.paste = function(sStr) { - - var obj = this._o; - var sel = this.getSelection(); - - var value = obj.value; - - var pre = value.substr(0, sel[0]); - var post = value.substr(sel[1]); - - value = pre + sStr + post; - obj.value = value; - - var n = 0; - if ( typeof document.body.style.maxHeight == "undefined" ) { - var a = pre.match( /\n/gi ); - n = ( a != null ? a.length : 0 ); - } - this.setSelection(sel[0] + sStr.length - n ); - -}; - -TextRange.prototype.cut = function() { - var r = this.copy(); - this.paste(''); - - return r; -}; -//} -//{ -/** - * @fileOverview This file contains Xpress plugin that takes care of the operations directly related to WYSIWYG iframe - * @name hp_XE_EditingArea_WYSIWYG.js - */ -xe.XE_EditingArea_WYSIWYG = jQuery.Class({ - name : "XE_EditingArea_WYSIWYG", - status : xe.PLUGIN_STATUS["NOT_READY"], - - sMode : "WYSIWYG", - iframe : null, - doc : null, - - iLastUndoRecorded : 0, - iMinUndoInterval : 3000, - - _nIFrameReadyCount : 50, - - $init : function(iframe){ - this.iframe = jQuery.$(iframe); - - this.initIframe(); - - this.elEditingArea = iframe; - }, - - $BEFORE_MSG_APP_READY : function(){ - this.oEditingArea = this.doc; - this.oApp.exec("REGISTER_EDITING_AREA", [this]); - this.oApp.exec("ADD_APP_PROPERTY", ["getWYSIWYGWindow", jQuery.fnBind(this.getWindow, this)]); - this.oApp.exec("ADD_APP_PROPERTY", ["getWYSIWYGDocument", jQuery.fnBind(this.getDocument, this)]); - }, - - $ON_MSG_APP_READY : function(){ - // uncomment this line if you wish to use the IE-style cursor in FF - // this.getDocument().body.style.cursor = "text"; - - if(jQuery.browser.msie){ - jQuery(this.doc).bind('keydown', jQuery.fnBind( - function(weEvent){ - if(this.doc.selection.type.toLowerCase() == 'control' && weEvent.keyCode == 8) { - this.oApp.exec("EXECCOMMAND", ['delete', false, false]); - weEvent.preventDefault(); weEvent.stopPropagation(); - } - } - , this)); - jQuery(this.doc.body).bind('mousedown', jQuery.fnBind( - function(weEvent){ - this._oIERange = null; - this._bIERangeReset = true; - } - , this)); - jQuery(this.doc.body).bind('beforedeactivate', jQuery.fnBind( - function(weEvent){ - // without this, cursor won't make it inside a table. - // mousedown(_oIERange gets reset) -> beforedeactivate(gets fired for table) -> RESTORE_IE_SELECTION - if(this._bIERangeReset) return; - - var tmpRange = this.getDocument().selection.createRange(0); - // Control range does not have parentElement - if(tmpRange.parentElement && tmpRange.parentElement() && tmpRange.parentElement().tagName == "INPUT"){ - this._oIERange = this._oPrevIERange; - }else{ - this._oIERange = tmpRange; - } - } - , this)); - jQuery(this.doc.body).bind('mouseup', jQuery.fnBind( - function(weEvent){ - this._bIERangeReset = false; - } - , this)); - } - }, - - $ON_CHANGE_EDITING_MODE : function(sMode, bNoFocus){ - if(sMode == this.sMode){ - this.iframe.style.display = "block"; - - this.oApp.exec("REFRESH_WYSIWYG", []); - this.oApp.exec("SET_EDITING_WINDOW", [this.getWindow()]); - }else{ - this.iframe.style.display = "none"; - } - }, - - $AFTER_CHANGE_EDITING_MODE : function(sMode, bNoFocus){ - this._oIERange = null; - }, - - $ON_REFRESH_WYSIWYG : function(){ - if(!jQuery.browser.mozilla) return; - - this._disableWYSIWYG(); - this._enableWYSIWYG(); - }, - - $ON_ENABLE_WYSIWYG : function(){ - this._enableWYSIWYG(); - }, - - $ON_DISABLE_WYSIWYG : function(){ - this._disableWYSIWYG(); - }, - - $ON_EVENT_EDITING_AREA_KEYUP : function(oEvent){ - // 33, 34: page up/down, 35,36: end/home, 37,38,39,40: left, up, right, down - if(oEvent.keyCode == 229 || oEvent.keyCode == 13 || oEvent.altKey || oEvent.ctrlKey || (oEvent.keyCode >= 33 && oEvent.keyCode <= 40) || oEvent.keyCode == 16) return; - this._recordUndo(oEvent); - }, - - $ON_PASTE_HTML : function(sHTML, oPSelection){ - if(this.oApp.getEditingMode() != this.sMode) return; - - var oSelection = oPSelection || this.oApp.getSelection(); - oSelection.pasteHTML(sHTML); - - // every browser except for IE may modify the innerHTML when it is inserted - if(!jQuery.browser.msie){ - var sTmpBookmark = oSelection.placeStringBookmark(); - this.oApp.getWYSIWYGDocument().body.innerHTML = this.oApp.getWYSIWYGDocument().body.innerHTML; - oSelection.moveToBookmark(sTmpBookmark); - oSelection.collapseToEnd(); - oSelection.select(); - oSelection.removeStringBookmark(sTmpBookmark); - } - - this.oApp.exec("RECORD_UNDO_ACTION", ["INSERT HTML"]); - }, - - $AFTER_MSG_EDITING_AREA_RESIZE_ENDED : function(FnMouseDown, FnMouseMove, FnMouseUp){ - this.oApp.exec("REFRESH_WYSIWYG", []); - }, - - $ON_RESTORE_IE_SELECTION : function(){ - if(this._oIERange){ - this._oIERange.select(); - this._oPrevIERange = this._oIERange; - this._oIERange = null; - } - }, - - initIframe : function(){ - try { - this.doc = this.iframe.contentWindow.document; - if (this.doc == null || this.doc.location.href == 'about:blank') { - throw new Error('Access denied'); - } - - this._enableWYSIWYG(); - - this.status = xe.PLUGIN_STATUS["READY"]; - } catch(e) { - if(this._nIFrameReadyCount-- > 0){ - setTimeout(jQuery.fnBind(this.initIframe, this), 100); - }else{ - throw("iframe for WYSIWYG editing mode can't be initialized. Please check if the iframe document exists and is also accessable(cross-domain issues). "); - } - } - }, - - getIR : function(){ - var sContent = this.doc.body.innerHTML; - var sIR; - - if(this.oApp.applyConverter) - sIR = this.oApp.applyConverter(this.sMode+"_TO_IR", sContent); - else - sIR = sContent; - - return sIR; - }, - - setIR : function(sIR){ - var sContent; - if(this.oApp.applyConverter) - sContent = this.oApp.applyConverter("IR_TO_"+this.sMode, sIR); - else - sContent = sIR; - - this.doc.body.innerHTML = sContent; - - if(jQuery.browser.mozilla){ - if(this.doc.body.innerHTML == "") this.doc.body.innerHTML = "
"; - } - }, - - getWindow : function(){ - return this.iframe.contentWindow; - }, - - getDocument : function(){ - return this.iframe.contentWindow.document; - }, - - focus : function(){ - //this.getWindow().focus(); - //this.oApp.exec("RESTORE_IE_SELECTION", []); - }, - - _recordUndo : function(oKeyInfo){ - var curTime = new Date(); - if(curTime-this.iLastUndoRecorded < this.iMinUndoInterval) return; - this.oApp.exec("RECORD_UNDO_ACTION", ["KEYPRESS"]); - - this.iLastUndoRecorded = new Date(); - - this.prevKeyCode = oKeyInfo.keyCode; - }, - - _enableWYSIWYG : function(){ - if (jQuery.browser.msie){ - var fake = jQuery(''); - jQuery(document.body).prepend(fake); - fake.focus(); - - this.doc.body.contentEditable = true; - - setTimeout(function(){fake.remove()}, 100); - } else { - this.doc.designMode = "on"; - } - }, - - _disableWYSIWYG : function(){ - if (jQuery.browser.msie){ - this.doc.body.contentEditable = false; - } else { - this.doc.designMode = "off"; - } - } -}); -//} -//{ -/** - * @fileOverview This file contains Xpress plugin that takes care of the operations related to resizing the editing area vertically - * @name hp_XE_EditingAreaVerticalResizer.js - */ -xe.XE_EditingAreaVerticalResizer = jQuery.Class({ - name : "XE_EditingAreaVerticalResizer", - oResizeGrip : null, - - $init : function(oAppContainer){ - this._assignHTMLObjects(oAppContainer); - - this.$FnMouseDown = jQuery.fnBind(this._mousedown, this); - this.$FnMouseMove = jQuery.fnBind(this._mousemove, this); - this.$FnMouseUp = jQuery.fnBind(this._mouseup, this); - - jQuery(this.oResizeGrip).bind("mousedown", this.$FnMouseDown); - }, - - _assignHTMLObjects : function(oAppContainer){ - oAppContainer = jQuery.$(oAppContainer) || document; - - this.oResizeGrip = jQuery(".xpress_xeditor_editingArea_verticalResizer", oAppContainer).get(0); - }, - - _mousedown : function(oEvent){ - this.iStartHeight = oEvent.clientY; - - jQuery(document).bind("mousemove", this.$FnMouseMove); - jQuery(document).bind("mouseup", this.$FnMouseUp); - - this.oApp.exec("MSG_EDITING_AREA_RESIZE_STARTED", [this.$FnMouseDown, this.$FnMouseMove, this.$FnMouseUp]); - }, - - _mousemove : function(oEvent){ - var iHeightChange = oEvent.clientY - this.iStartHeight; - - this.oApp.exec("RESIZE_EDITING_AREA_BY", [0, iHeightChange]); - }, - - _mouseup : function(oEvent){ - jQuery(document).unbind("mousemove", this.$FnMouseMove); - jQuery(document).unbind("mouseup", this.$FnMouseUp); - - this.oApp.exec("MSG_EDITING_AREA_RESIZE_ENDED", [this.$FnMouseDown, this.$FnMouseMove, this.$FnMouseUp]); - } -}); -//} -//{ -/** - * @fileOverview This file contains Xpress plugin that takes care of the basic editor commands - * @name hp_XE_ExecCommand.js - */ -xe.XE_ExecCommand = jQuery.Class({ - name : "XE_ExecCommand", - oEditingArea : null, - - $init : function(oEditingArea){ - this.oEditingArea = oEditingArea; - }, - - $BEFORE_MSG_APP_READY : function(){ - // the right document will be available only when the src is completely loaded - if(this.oEditingArea && this.oEditingArea.tagName == "IFRAME") - this.oEditingArea = this.oEditingArea.contentWindow.document; - }, - - $ON_MSG_APP_READY : function(){ - this.oApp.exec("REGISTER_HOTKEY", ["ctrl+b", "EXECCOMMAND", ["bold", false, false]]); - this.oApp.exec("REGISTER_HOTKEY", ["ctrl+u", "EXECCOMMAND", ["underline", false, false]]); - this.oApp.exec("REGISTER_HOTKEY", ["ctrl+i", "EXECCOMMAND", ["italic", false, false]]); - this.oApp.exec("REGISTER_HOTKEY", ["ctrl+d", "EXECCOMMAND", ["strikethrough", false, false]]); - - this.oApp.exec("REGISTER_UI_EVENT", ["bold", "click", "EXECCOMMAND", ["bold", false, false]]); - this.oApp.exec("REGISTER_UI_EVENT", ["underline", "click", "EXECCOMMAND", ["underline", false, false]]); - this.oApp.exec("REGISTER_UI_EVENT", ["italic", "click", "EXECCOMMAND", ["italic", false, false]]); - this.oApp.exec("REGISTER_UI_EVENT", ["lineThrough", "click", "EXECCOMMAND", ["strikethrough", false, false]]); - this.oApp.exec("REGISTER_UI_EVENT", ["superscript", "click", "EXECCOMMAND", ["superscript", false, false]]); - this.oApp.exec("REGISTER_UI_EVENT", ["subscript", "click", "EXECCOMMAND", ["subscript", false, false]]); - this.oApp.exec("REGISTER_UI_EVENT", ["justifyleft", "click", "EXECCOMMAND", ["justifyleft", false, false]]); - this.oApp.exec("REGISTER_UI_EVENT", ["justifycenter", "click", "EXECCOMMAND", ["justifycenter", false, false]]); - this.oApp.exec("REGISTER_UI_EVENT", ["justifyright", "click", "EXECCOMMAND", ["justifyright", false, false]]); - this.oApp.exec("REGISTER_UI_EVENT", ["justifyfull", "click", "EXECCOMMAND", ["justifyfull", false, false]]); - this.oApp.exec("REGISTER_UI_EVENT", ["orderedlist", "click", "EXECCOMMAND", ["insertorderedlist", false, false]]); - this.oApp.exec("REGISTER_UI_EVENT", ["unorderedlist", "click", "EXECCOMMAND", ["insertunorderedlist", false, false]]); - this.oApp.exec("REGISTER_UI_EVENT", ["outdent", "click", "EXECCOMMAND", ["outdent", false, false]]); - this.oApp.exec("REGISTER_UI_EVENT", ["indent", "click", "EXECCOMMAND", ["indent", false, false]]); - }, - - $BEFORE_EXECCOMMAND : function(sCommand, bUserInterface, vValue){ - this._bOnlyCursorChanged = false; - - this.oApp.exec("FOCUS", []); - - if(sCommand.match(/^bold|underline|italic|strikethrough|superscript|subscript$/i)){ - var oSelection = this.oApp.getSelection(); - if(oSelection.collapsed) this._bOnlyCursorChanged = true; - } - - if(!this._bOnlyCursorChanged){ - this.oApp.exec("RECORD_UNDO_BEFORE_ACTION", [sCommand]); - } - }, - - $ON_EXECCOMMAND : function(sCommand, bUserInterface, vValue){ - bUserInterface = (bUserInterface == "" || bUserInterface)?bUserInterface:false; - vValue = (vValue == "" || vValue)?vValue:false; - - this.oEditingArea.execCommand(sCommand, bUserInterface, vValue); - }, - - $AFTER_EXECCOMMAND : function(sCommand, bUserInterface, vValue){ - if(!this._bOnlyCursorChanged){ - this.oApp.exec("RECORD_UNDO_AFTER_ACTION", [sCommand]); - } - - this.oApp.exec("CHECK_STYLE_CHANGE", []); - } -}); -//} - -//{ -/** - * @fileOverview This file contains Xpress plugin that takes care of the operations related to wrapping the sentence around with a

tag when enter key is pressed - * @name hp_XE_WYSIWYGEnterKey.js - */ -xe.XE_WYSIWYGEnterKey = jQuery.Class({ - name : "XE_WYSIWYGEnterKey", - // IE/Opera do not need this - unsupportedBrowser : ['ie', 'opera'], - oEditingArea : null, - - $init : function(oEditingArea){ - this.oEditingArea = oEditingArea; - }, - - $BEFORE_MSG_APP_READY : function(){ - // the right document will be available only when the src is completely loaded - if(this.oEditingArea && this.oEditingArea.tagName == "IFRAME") - this.oEditingArea = this.oEditingArea.contentWindow.document; - }, - - $ON_EVENT_EDITING_AREA_KEYDOWN : function(oEvent){ - if(this.oApp.getEditingMode() != "WYSIWYG") return; - - if(oEvent.shiftKey) return; - - if(oEvent.keyCode == 13){ - var oSelection = this.oApp.getSelection(); - var sBM = oSelection.placeStringBookmark(); - var oLineInfo = oSelection.getLineInfo(); - var oStart = oLineInfo.oStart; - var oEnd = oLineInfo.oEnd; - - //top.document.title = oStart.oNode.tagName+":"+oStart.oNode.nodeValue+", "+oEnd.oNode.tagName+":"+oEnd.oNode.nodeValue+"::"+oStart.bParentBreak+", "+oStart.oLineBreaker.tagName; - - // line broke by sibling - // or - // the parent line breaker is just a block container - if(!oStart.bParentBreak || oSelection.rxBlockContainer.test(oStart.oLineBreaker.tagName)){ - oEvent.stopPropagation(); - oEvent.preventDefault(); - - var oSWrapper = this.oEditingArea.createElement("P"); - oSelection.moveToBookmark(sBM); - oSelection.setStartBefore(oStart.oNode); - oSelection.surroundContents(oSWrapper); - - oSelection.collapseToEnd(); - - var oEWrapper = this.oEditingArea.createElement("P"); - oSelection.setEndAfter(oEnd.oNode); - oSelection.surroundContents(oEWrapper); - - oSelection.removeStringBookmark(sBM); - - if(oSWrapper.innerHTML == "") oSWrapper.innerHTML = "
"; - if(oEWrapper.innerHTML == "") oEWrapper.innerHTML = "
"; - - if(oEWrapper.nextSibling && oEWrapper.nextSibling.tagName == "BR") oEWrapper.parentNode.removeChild(oEWrapper.nextSibling); - - oSelection.selectNodeContents(oEWrapper); - oSelection.collapseToStart(); - oSelection.select(); - this.oApp.exec("CHECK_STYLE_CHANGE", []); - }else{ - oSelection.removeStringBookmark(sBM); - } - } - } -}); -//} - -//{ -/** - * @fileOverview This file contains Xpress plugin that takes care of the operations related to styling the font - * @name hp_XE_WYSIWYGStyler.js - * @required XE_EditingArea_WYSIWYG, XpressRangeManager - */ -xe.XE_WYSIWYGStyler = jQuery.Class({ - name : "XE_WYSIWYGStyler", - - $PRECONDITION : function(sFullCommand, aArgs){ - return (this.oApp.getEditingMode() == "WYSIWYG"); - }, - - $ON_SET_WYSIWYG_STYLE : function(oStyles){ - var oSelection = this.oApp.getSelection(); - - // style cursor - if(oSelection.collapsed){ - var oSpan = this.oApp.getWYSIWYGDocument().createElement("SPAN"); - oSelection.insertNode(oSpan); - oSpan.innerHTML = unescape("%uFEFF"); - - var sValue; - for(var sName in oStyles){ - sValue = oStyles[sName]; - - if(typeof sValue != "string") continue; - - oSpan.style[sName] = sValue; - } - - oSelection.selectNodeContents(oSpan); - oSelection.collapseToEnd(); - oSelection._window.focus(); - oSelection._window.document.body.focus(); - oSelection.select(); - - // FF3 will actually display %uFEFF when it is followed by a number AND certain font-family is used(like Gulim), so remove the chcaracter for FF3 - if(jQuery.browser.mozilla && jQuery.browser.nVersion == 3) - oSpan.innerHTML = ""; - - return; - } - - this.oApp.exec("RECORD_UNDO_BEFORE_ACTION", ["FONT STYLE"]); - - oSelection.styleRange(oStyles); - oSelection._window.focus(); - oSelection.select(); - - this.oApp.exec("RECORD_UNDO_AFTER_ACTION", ["FONT STYLE"]); - } -}); -//} - -//{ -/** - * @fileOverview This file contains Xpress plugin that takes care of the operations related to detecting the style change - * @name hp_XE_WYSIWYGStyleGetter.js - */ -xe.XE_WYSIWYGStyleGetter = jQuery.Class({ - name : "XE_WYSIWYGStyleGetter", - - hKeyUp : null, - - getStyleInterval : 200, - - oStyleMap : { - fontFamily : { - type : "Value", - css : "fontFamily" - }, - fontSize : { - type : "Value", - css : "fontSize" - }, - lineHeight : { - type : "Value", - css : "lineHeight", - converter : function(sValue, oStyle){ - if(!sValue.match(/px$/)) return sValue; - - return Math.ceil((parseInt(sValue)/parseInt(oStyle.fontSize))*10)/10; - } - }, - bold : { - command : "bold" - }, - underline : { - command : "underline" - }, - italic : { - command : "italic" - }, - lineThrough : { - command : "strikethrough" - }, - superscript : { - command : "superscript" - }, - subscript : { - command : "subscript" - }, - justifyleft : { - command : "justifyleft" - }, - justifycenter : { - command : "justifycenter" - }, - justifyright : { - command : "justifyright" - }, - justifyfull : { - command : "justifyfull" - }, - orderedlist : { - command : "insertorderedlist" - }, - unorderedlist : { - command : "insertunorderedlist" - } - }, - - $init : function(){ - this.oStyle = this._getBlankStyle(); - }, - - $PRECONDITION : function(){ - if(this.oApp.getEditingMode() != "WYSIWYG") return false; - - return true; - }, - - $ON_MSG_APP_READY : function(){ - this.oDocument = this.oApp.getWYSIWYGDocument(); - this.oApp.exec("ADD_APP_PROPERTY", ["getCurrentStyle", jQuery.fnBind(this.getCurrentStyle, this)]); - }, - - $ON_EVENT_EDITING_AREA_MOUSEUP : function(oEvnet){ - if(this.hKeyUp) clearTimeout(this.hKeyUp); - this.oApp.exec("CHECK_STYLE_CHANGE", []); - }, - - $ON_EVENT_EDITING_AREA_KEYUP : function(oEvent){ - /* - backspace 8 - page up 33 - page down 34 - end 35 - home 36 - left arrow 37 - up arrow 38 - right arrow 39 - down arrow 40 - insert 45 - delete 46 - */ - if(!(oEvent.keyCode == 8 || (oEvent.keyCode >= 33 && oEvent.keyCode <= 40) || oEvent.keyCode == 45 || oEvent.keyCode == 46)) return; - - if(this.hKeyUp) clearTimeout(this.hKeyUp); - - this.hKeyUp = setTimeout(jQuery.fnBind(this.oApp.exec, this.oApp, "CHECK_STYLE_CHANGE", []), this.getStyleInterval); - }, - - $ON_CHECK_STYLE_CHANGE : function(){ - this._getStyle(); - }, - - $ON_RESET_STYLE_STATUS : function(){ - var oBlankStyle = this._getBlankStyle(); - for(var sAttributeName in oBlankStyle) - this.oApp.exec("SET_STYLE_STATUS", [sAttributeName, oBlankStyle[sAttributeName]]); - }, - - getCurrentStyle : function(){ - return this.oStyle; - }, - - _check_style_change : function(){ - this.oApp.exec("CHECK_STYLE_CHANGE", []); - }, - - _getBlankStyle : function(){ - var oBlankStyle = {}; - for(var attributeName in this.oStyleMap){ - if(this.oStyleMap[attributeName].type == "Value") - oBlankStyle[attributeName] = ""; - else - oBlankStyle[attributeName] = 0; - } - - return oBlankStyle; - }, - - _getStyle : function(){ - var oSelection = this.oApp.getSelection(); - - var funcFilter = function(oNode){ - if (!oNode.childNodes || oNode.childNodes.length == 0) - return true; - else - return false; - } - - var aBottomNodes = oSelection.getNodes(false, funcFilter); - - var oStyle, oBaseStyle, oTmpStyle, attributeName; - if(aBottomNodes.length == 0){ - oStyle = this._getStyleOf(oSelection.commonAncestorContainer); - }else{ - oStyle = this._getStyleOf(aBottomNodes[0]); - } - - for(attributeName in oStyle){ - if(this.oStyleMap[attributeName].converter){ - oStyle[attributeName] = this.oStyleMap[attributeName].converter(oStyle[attributeName], oStyle); - } - - if(this.oStyle[attributeName] != oStyle[attributeName]) - this.oApp.exec("MSG_STYLE_CHANGED", [attributeName, oStyle[attributeName]]); - } - - this.oStyle = oStyle; - }, - - _getStyleOf : function(oNode){ - var oStyle = this._getBlankStyle(); - - // this must not happen - if(!oNode) return oStyle; - - if(oNode.nodeType == 3) oNode = oNode.parentNode; - - var welNode = jQuery(oNode); - var attribute, cssName; - for(var styleName in this.oStyle){ - attribute = this.oStyleMap[styleName]; - - if(attribute.type && attribute.type == "Value"){ - if(attribute.css){ - var sValue = welNode.css(attribute.css); - - if(styleName == "fontFamily"){ - sValue = sValue.split(/,/)[0]; - } - - oStyle[styleName] = sValue; - }else{ - if(attribute.command){ - try{ - oStyle[styleName] = this.oDocument.queryCommandState(attribute.command); - }catch(e){} - }else{ - // todo - } - } - }else{ - if(attribute.command){ - try{ - if(this.oDocument.queryCommandState(attribute.command)){ - oStyle[styleName] = 1; - }else{ - oStyle[styleName] = 0; - } - }catch(e){} - }else{ - // todo - } - } - } - return oStyle; - } -}); -//} -//{ -/** - * @fileOverview This file contains Xpress plugin that takes care of the operations related to changing the font size using Select element - * @name hp_XE_FontSizeWithSelectUI.js - */ -xe.XE_FontSizeWithSelectUI = jQuery.Class({ - name : "XE_FontSizeWithSelectUI", - - $init : function(elAppContainer){ - this._assignHTMLObjects(elAppContainer); - }, - - _assignHTMLObjects : function(elAppContainer){ - this.elFontSizeSelect = jQuery("SELECT.xpress_xeditor_ui_fontSize_select", elAppContainer).get(0); - }, - - $ON_MSG_APP_READY : function(){ - this.oApp.registerBrowserEvent(this.elFontSizeSelect, "change", "SET_FONTSIZE_FROM_SELECT_UI"); - this.elFontSizeSelect.selectedIndex = 0; - }, - - $ON_MSG_STYLE_CHANGED : function(sAttributeName, sAttributeValue){ - if(sAttributeName == "fontSize"){ - this.elFontSizeSelect.value = sAttributeValue; - if(this.elFontSizeSelect.selectedIndex < 0) this.elFontSizeSelect.selectedIndex = 0; - } - }, - - $ON_SET_FONTSIZE_FROM_SELECT_UI : function(){ - var sFontSize = this.elFontSizeSelect.value; - if(!sFontSize) return; - - this.oApp.exec("SET_WYSIWYG_STYLE", [{"fontSize":sFontSize}]); - this.oApp.exec("CHECK_STYLE_CHANGE", []); - } -}); -//} -//{ -/** - * @fileOverview This file contains Xpress plugin that takes care of the operations related to changing the font name using Select element - * @name hp_XE_FontNameWithSelectUI.js - */ -xe.XE_FontNameWithSelectUI = jQuery.Class({ - name : "XE_FontNameWithSelectUI", - - $init : function(elAppContainer){ - this._assignHTMLObjects(elAppContainer); - }, - - _assignHTMLObjects : function(elAppContainer){ - this.elFontNameSelect = jQuery("SELECT.xpress_xeditor_ui_fontName_select", elAppContainer).get(0); - }, - - $ON_MSG_APP_READY : function(){ - this.oApp.registerBrowserEvent(this.elFontNameSelect, "change", "SET_FONTNAME_FROM_SELECT_UI"); - this.elFontNameSelect.selectedIndex = 0; - }, - - $ON_MSG_STYLE_CHANGED : function(sAttributeName, sAttributeValue){ - if(sAttributeName == "fontFamily"){ - this.elFontNameSelect.value = sAttributeValue.toLowerCase(); - if(this.elFontNameSelect.selectedIndex < 0) this.elFontNameSelect.selectedIndex = 0; - } - }, - - $ON_SET_FONTNAME_FROM_SELECT_UI : function(){ - var sFontName = this.elFontNameSelect.value; - if(!sFontName) return; - - this.oApp.exec("SET_WYSIWYG_STYLE", [{"fontFamily":sFontName}]); - this.oApp.exec("CHECK_STYLE_CHANGE", []); - } -}); -//} -//{ -/** - * @fileOverview This file contains Xpress plugin that takes care of the operations related to setting/changing the lineheight - * @name hp_XE_LineHeight.js - */ -xe.XE_LineHeight = jQuery.Class({ - name : "XE_LineHeight", - - $init : function(oAppContainer){ - this._assignHTMLObjects(oAppContainer); - }, - - _assignHTMLObjects : function(oAppContainer){ - }, - - $ON_SET_LINEHEIGHT : function(nLineHeight){ - this.setLineHeight(nLineHeight); - }, - - getLineHeight : function(){ - var nodes = this._getSelectedNodes(false); - - var curWrapper, prevWrapper; - var iCurHeight, iHeight; - - if(nodes.length == 0) return -1; - - var iLength = nodes.length; - - if(iLength == 0){ - iHeight = -1; - }else{ - prevWrapper = this._getLineWrapper(nodes[0]); - iHeight = this._getWrapperLineheight(prevWrapper); - } - - var firstNode = this.oSelection.getStartNode(); - - if(iHeight > 0){ - for(var i=1; i=0; i--){ - if(aNodes[i].nodeType == 3 || aNodes[i].tagName == "BR"){ - var oP = oSelection._document.createElement("P"); - oInsertionPoint = aNodes[i].nextSibling; - while(i>=0 && aNodes[i] && (aNodes[i].nodeType == 3 || aNodes[i].tagName == "BR")){ - oP.insertBefore(aNodes[i--], oP.firstChild); - } - oFormattingNode.insertBefore(oP, oInsertionPoint); - i++; - } - } - - if(oFormattingNode && oFormattingNode.parentNode){ - var oP = oSelection._document.createElement("P"); - oP.innerHTML = unescape("
"); - oFormattingNode.parentNode.insertBefore(oP, oFormattingNode.nextSibling); - } - - this.oApp.exec("RECORD_UNDO_ACTION", ["Block Quote"]); - - return oFormattingNode; - }, - - _expandToTableStart : function(oSelection, oNode){ - var oC = oSelection.commonAncestorContainer; - var oResultNode = null; - - var bLastIteration = false; - while(oNode && !bLastIteration){ - if(oNode == oC) bLastIteration = true; - - if(/TBODY|TFOOT|THEAD|TR/i.test(oNode.tagName)){ - oResultNode = this._getTableRoot(oNode); - break; - } - oNode = oNode.parentNode; - } - - return oResultNode; - }, - - _getTableRoot : function(oNode){ - while(oNode && oNode.tagName != "TABLE") oNode = oNode.parentNode; - - return oNode; - } -}); -//} -//{ -/** - * @fileOverview This file contains Xpress plugin that takes care of the operations related to inserting special characters - * @name hp_XE_SCharacter.js - * @required XpressRangeManager - */ -xe.XE_SCharacter = jQuery.Class({ - name : "XE_SCharacter", - - $init : function(oAppContainer){ - this.bIE = jQuery.browser.msie; - - this._assignHTMLObjects(oAppContainer); - - this.charSet = []; - this.charSet[0] = unescape('FF5B FF5D 3014 3015 3008 3009 300A 300B 300C 300D 300E 300F 3010 3011 2018 2019 201C 201D 3001 3002 %B7 2025 2026 %A7 203B 2606 2605 25CB 25CF 25CE 25C7 25C6 25A1 25A0 25B3 25B2 25BD 25BC 25C1 25C0 25B7 25B6 2664 2660 2661 2665 2667 2663 2299 25C8 25A3 25D0 25D1 2592 25A4 25A5 25A8 25A7 25A6 25A9 %B1 %D7 %F7 2260 2264 2265 221E 2234 %B0 2032 2033 2220 22A5 2312 2202 2261 2252 226A 226B 221A 223D 221D 2235 222B 222C 2208 220B 2286 2287 2282 2283 222A 2229 2227 2228 FFE2 21D2 21D4 2200 2203 %B4 FF5E 02C7 02D8 02DD 02DA 02D9 %B8 02DB %A1 %BF 02D0 222E 2211 220F 266D 2669 266A 266C 327F 2192 2190 2191 2193 2194 2195 2197 2199 2196 2198 321C 2116 33C7 2122 33C2 33D8 2121 2668 260F 260E 261C 261E %B6 2020 2021 %AE %AA %BA 2642 2640').replace(/(\S{4})/g, function(a){return "%u"+a}).split(' '); - this.charSet[1] = unescape('%BD 2153 2154 %BC %BE 215B 215C 215D 215E %B9 %B2 %B3 2074 207F 2081 2082 2083 2084 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 FFE6 %24 FFE5 FFE1 20AC 2103 212B 2109 FFE0 %A4 2030 3395 3396 3397 2113 3398 33C4 33A3 33A4 33A5 33A6 3399 339A 339B 339C 339D 339E 339F 33A0 33A1 33A2 33CA 338D 338E 338F 33CF 3388 3389 33C8 33A7 33A8 33B0 33B1 33B2 33B3 33B4 33B5 33B6 33B7 33B8 33B9 3380 3381 3382 3383 3384 33BA 33BB 33BC 33BD 33BE 33BF 3390 3391 3392 3393 3394 2126 33C0 33C1 338A 338B 338C 33D6 33C5 33AD 33AE 33AF 33DB 33A9 33AA 33AB 33AC 33DD 33D0 33D3 33C3 33C9 33DC 33C6').replace(/(\S{4})/g, function(a){return "%u"+a}).split(' '); - this.charSet[2] = unescape('3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 326A 326B 326C 326D 326E 326F 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 327A 327B 24D0 24D1 24D2 24D3 24D4 24D5 24D6 24D7 24D8 24D9 24DA 24DB 24DC 24DD 24DE 24DF 24E0 24E1 24E2 24E3 24E4 24E5 24E6 24E7 24E8 24E9 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 246A 246B 246C 246D 246E 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 320A 320B 320C 320D 320E 320F 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 321A 321B 249C 249D 249E 249F 24A0 24A1 24A2 24A3 24A4 24A5 24A6 24A7 24A8 24A9 24AA 24AB 24AC 24AD 24AE 24AF 24B0 24B1 24B2 24B3 24B4 24B5 2474 2475 2476 2477 2478 2479 247A 247B 247C 247D 247E 247F 2480 2481 2482').replace(/(\S{4})/g, function(a){return "%u"+a}).split(' '); - this.charSet[3] = unescape('3131 3132 3133 3134 3135 3136 3137 3138 3139 313A 313B 313C 313D 313E 313F 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 314A 314B 314C 314D 314E 314F 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 315A 315B 315C 315D 315E 315F 3160 3161 3162 3163 3165 3166 3167 3168 3169 316A 316B 316C 316D 316E 316F 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 317A 317B 317C 317D 317E 317F 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 318A 318B 318C 318D 318E').replace(/(\S{4})/g, function(a){return "%u"+a}).split(' '); - this.charSet[4] = unescape('0391 0392 0393 0394 0395 0396 0397 0398 0399 039A 039B 039C 039D 039E 039F 03A0 03A1 03A3 03A4 03A5 03A6 03A7 03A8 03A9 03B1 03B2 03B3 03B4 03B5 03B6 03B7 03B8 03B9 03BA 03BB 03BC 03BD 03BE 03BF 03C0 03C1 03C3 03C4 03C5 03C6 03C7 03C8 03C9 %C6 %D0 0126 0132 013F 0141 %D8 0152 %DE 0166 014A %E6 0111 %F0 0127 I 0133 0138 0140 0142 0142 0153 %DF %FE 0167 014B 0149 0411 0413 0414 0401 0416 0417 0418 0419 041B 041F 0426 0427 0428 0429 042A 042B 042C 042D 042E 042F 0431 0432 0433 0434 0451 0436 0437 0438 0439 043B 043F 0444 0446 0447 0448 0449 044A 044B 044C 044D 044E 044F').replace(/(\S{4})/g, function(a){return "%u"+a}).split(' '); - this.charSet[5] = unescape('3041 3042 3043 3044 3045 3046 3047 3048 3049 304A 304B 304C 304D 304E 304F 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 305A 305B 305C 305D 305E 305F 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 306A 306B 306C 306D 306E 306F 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 307A 307B 307C 307D 307E 307F 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 308A 308B 308C 308D 308E 308F 3090 3091 3092 3093 30A1 30A2 30A3 30A4 30A5 30A6 30A7 30A8 30A9 30AA 30AB 30AC 30AD 30AE 30AF 30B0 30B1 30B2 30B3 30B4 30B5 30B6 30B7 30B8 30B9 30BA 30BB 30BC 30BD 30BE 30BF 30C0 30C1 30C2 30C3 30C4 30C5 30C6 30C7 30C8 30C9 30CA 30CB 30CC 30CD 30CE 30CF 30D0 30D1 30D2 30D3 30D4 30D5 30D6 30D7 30D8 30D9 30DA 30DB 30DC 30DD 30DE 30DF 30E0 30E1 30E2 30E3 30E4 30E5 30E6 30E7 30E8 30E9 30EA 30EB 30EC 30ED 30EE 30EF 30F0 30F1 30F2 30F3 30F4 30F5 30F6').replace(/(\S{4})/g, function(a){return "%u"+a}).split(' '); - }, - - _assignHTMLObjects : function(oAppContainer){ - oAppContainer = jQuery.$(oAppContainer) || document; - - this.elDropdownLayer = jQuery("DIV.xpress_xeditor_sCharacter_layer", oAppContainer).get(0); - - this.oTextField = jQuery("INPUT", this.elDropdownLayer).get(0); - this.oInsertButton = jQuery("+ BUTTON", this.oTextField).get(0); - this.aCloseButton = jQuery("BUTTON.close", this.elDropdownLayer).get(); - this.aSCharList = jQuery(".list", this.elDropdownLayer).get(); - var oLabelUL = jQuery(">UL", this.elDropdownLayer).get(0); - this.aLabelA = jQuery("A", oLabelUL).get(); - }, - - $ON_MSG_APP_READY : function(){ - var funcInsert = jQuery.fnBind(this.oApp.exec, this.oApp, "INSERT_SCHARACTERS", [this.oTextField.value]); - jQuery(this.oInsertButton).click(funcInsert, this); - - this.oApp.exec("SET_SCHARACTER_LIST", [this.charSet]); - - for(var i=0; i"); - }else{ - button = document.createElement("BUTTON"); - button.type = "button"; - } - span = document.createElement("SPAN"); - span.innerHTML = unescape(this.charSet[i][ii]); - button.appendChild(span); - - aLI[ii].appendChild(button); - this.aSCharList[i].appendChild(aLI[ii]); - } - - // enable this after Jindo framework is updated -// this.oApp.exec("ATTACH_HOVER_EVENTS", [jQuery(">LI>BUTTON", this.aSCharList[i])]).get(); - }, - - _stopBrowserEvent : function(obj, sEvent){ - jQuery(obj).bind(sEvent, function(e){e.stopPropagation();e.preventDefault();} ) - } -}); -//} -//{ -/** - * @fileOverview This file contains Xpress plugin that takes care of the operations related to Undo/Redo - * @name hp_XE_UndoRedo.js - * @required XE_EditingAreaManager, XpressRangeManager - */ -xe.XE_UndoRedo = jQuery.Class({ - name : "XE_UndoRedo", - actionHistory : null, - // this may also be called, lastAdded/lastRestored - oCurStateIdx : null, - iMinimumSizeChange : 10, - sBlankContentsForFF : "
", - - $init : function(){ - this.aUndoHistory = []; - this.oCurStateIdx = {nIdx: 0, nStep: 0}; - }, - - $PRECONDITION : function(sCmd){ - if(sCmd.match(/_DO_RECORD_UNDO_HISTORY_AT$/)) return true; - - try{ - if(this.oApp.getEditingMode() != "WYSIWYG") return false; - }catch(e){ - return false; - } - - return true; - }, - - $BEFORE_MSG_APP_READY : function(){ - this.oApp.exec("DO_RECORD_UNDO_HISTORY_AT", [this.oCurStateIdx, "", "", null]); - }, - - $ON_MSG_APP_READY : function(){ - this.bFF = jQuery.browser.mozilla; - - this.oApp.exec("ADD_APP_PROPERTY", ["getUndoHistory", jQuery.fnBind(this.getUndoHistory, this)]); - this.oApp.exec("ADD_APP_PROPERTY", ["getUndoStateIdx", jQuery.fnBind(this.getUndoStateIdx, this)]); - - this.oApp.exec("REGISTER_UI_EVENT", ["undo", "click", "UNDO"]); - this.oApp.exec("REGISTER_UI_EVENT", ["redo", "click", "REDO"]); - - this.oApp.exec("REGISTER_HOTKEY", ["ctrl+z", "UNDO"]); - this.oApp.exec("REGISTER_HOTKEY", ["ctrl+y", "REDO"]); - }, - - $ON_UNDO : function(){ - var oTmpStateIdx = {}; - this.oApp.exec("DO_RECORD_UNDO_HISTORY", ["KEYPRESS", false, false, 1]); - if(this.oCurStateIdx.nIdx == 0) return; - - if(this.oCurStateIdx.nStep > 0){ - this.oCurStateIdx.nStep--; - }else{ - var oTmpHistory = this.aUndoHistory[this.oCurStateIdx.nIdx]; - - this.oCurStateIdx.nIdx--; - - if(oTmpHistory.nTotalSteps>1){ - this.oCurStateIdx.nStep = 0; - }else{ - oTmpHistory = this.aUndoHistory[this.oCurStateIdx.nIdx]; - this.oCurStateIdx.nStep = oTmpHistory.nTotalSteps-1; - } - } - - this.oApp.exec("RESTORE_UNDO_HISTORY", [this.oCurStateIdx.nIdx, this.oCurStateIdx.nStep]); - - this.oApp.exec("CHECK_STYLE_CHANGE", []); - }, - - - $ON_REDO : function(){ - if(this.oCurStateIdx.nIdx >= this.aUndoHistory.length) return; - - var oCurHistory = this.aUndoHistory[this.oCurStateIdx.nIdx]; - if(this.oCurStateIdx.nIdx == this.aUndoHistory.length-1 && this.oCurStateIdx.nStep >= oCurHistory.nTotalSteps-1) return; - - if(this.oCurStateIdx.nStep < oCurHistory.nTotalSteps-1){ - this.oCurStateIdx.nStep++; - }else{ - this.oCurStateIdx.nIdx++; - oCurHistory = this.aUndoHistory[this.oCurStateIdx.nIdx]; - this.oCurStateIdx.nStep = oCurHistory.nTotalSteps-1; - } - - this.oApp.exec("RESTORE_UNDO_HISTORY", [this.oCurStateIdx.nIdx, this.oCurStateIdx.nStep]); - - this.oApp.exec("CHECK_STYLE_CHANGE", []); - }, - - $ON_RECORD_UNDO_ACTION : function(sAction){ - this.oApp.exec("DO_RECORD_UNDO_HISTORY", [sAction]); - }, - - $ON_RECORD_UNDO_BEFORE_ACTION : function(sAction){ - this.oApp.exec("DO_RECORD_UNDO_HISTORY", [sAction, true, true]); - }, - - $ON_RECORD_UNDO_AFTER_ACTION : function(sAction){ - this.oApp.exec("DO_RECORD_UNDO_HISTORY", [sAction, true, false]); - }, - - $ON_RESTORE_UNDO_HISTORY : function(nUndoIdx, nUndoStateStep){ - this.oCurStateIdx.nIdx = nUndoIdx; - this.oCurStateIdx.nStep = nUndoStateStep; - - var oCurHistory = this.aUndoHistory[this.oCurStateIdx.nIdx]; - var sContent = oCurHistory.sContent[this.oCurStateIdx.nStep]; - var oBookmark = oCurHistory.oBookmark[this.oCurStateIdx.nStep]; - - this.oApp.setIR(sContent, true); - - // setting the innerHTML may change the internal DOM structure, so save the value again. - var sCurContent = this.oApp.getIR(); - if(this.bFF && sCurContent == this.sBlankContentsForFF){ - sCurContent = ""; - } - oCurHistory.sContent[this.oCurStateIdx.nStep] = sCurContent; - - var oSelection = this.oApp.getEmptySelection(); - if(oSelection.selectionLoaded){ - if(oBookmark){ - oSelection.moveToXPathBookmark(oBookmark); - }else{ - oSelection = this.oApp.getEmptySelection(); - } - - oSelection.select(); - } - }, - - $ON_DO_RECORD_UNDO_HISTORY : function(sAction, bTwoStepAction, bBeforeAction, nForceAddUnlessEqual){ - bTwoStepAction = bTwoStepAction || false; - bBeforeAction = bBeforeAction || false; - nForceAddUnlessEqual = nForceAddUnlessEqual || 0; - - // if we're in the middle of some action history, remove everything after current idx if any "little" change is made - if(!(this.oCurStateIdx.nIdx == this.aUndoHistory.length-1)) nForceAddUnlessEqual = 1; - - var oCurHistory = this.aUndoHistory[this.oCurStateIdx.nIdx]; - - var sCurContent = this.oApp.getIR(); - var sHistoryContent = oCurHistory.sContent[this.oCurStateIdx.nStep]; - - if(this.bFF && sCurContent == this.sBlankContentsForFF){ - sCurContent = ""; - } - - // every TwoStepAction needs to be recorded - if(!bTwoStepAction){ - switch(nForceAddUnlessEqual){ - case 0: - if(Math.abs(sHistoryContent.length - sCurContent.length) .bx", this.oUILayer).get(); - - this.oFindInputSet = oTmp[0]; - this.oReplaceInputSet = oTmp[1]; - - this.oFindInput_Keyword = jQuery("INPUT", this.oFindInputSet).get(0); - - oTmp = jQuery("INPUT", this.oReplaceInputSet).get(); - this.oReplaceInput_Original = oTmp[0]; - this.oReplaceInput_Replacement = oTmp[1]; - - this.oFindNextButton = jQuery("BUTTON.find_next", this.oUILayer).get(0); - this.oCancelButton = jQuery("BUTTON.cancel", this.oUILayer).get(0); - - this.oReplaceButton = jQuery("BUTTON.replace", this.oUILayer).get(0); - this.oReplaceAllButton = jQuery("BUTTON.replace_all", this.oUILayer).get(0); - - this.aCloseButtons = jQuery("BUTTON.close", this.oUILayer).get(); - this.aCloseButtons[this.aCloseButtons.length] = this.oCancelButton; - }, - - $ON_MSG_APP_READY : function(){ - // the right document will be available only when the src is completely loaded - if(this.oEditingWindow && this.oEditingWindow.tagName == "IFRAME") - this.oEditingWindow = this.oEditingWindow.contentWindow; - - this.oFindReplace = new xe.FindReplace(this.oEditingWindow); - if(!this.oFindReplace.bBrowserSupported){ - this.oApp.exec("DISABLE_UI", ["find_replace"]); - return; - } - - for(var i=0; i" + sURL + ""; - this.oSelection.pasteHTML(str); - }else{ - var nSession = Math.ceil(Math.random()*10000); - var arg = ( sURL == "" ? ["unlink"] : ["createLink", false, this.sATagMarker+nSession+sURL] ); - this.oApp.exec("EXECCOMMAND", arg); - - this.oSelection.setFromSelection(); - - var oDoc = this.oApp.getWYSIWYGDocument(); - var aATags = oDoc.body.getElementsByTagName("A"); - var nLen = aATags.length; - var rxMarker = new RegExp(this.sRXATagMarker+nSession, "i"); - var elATag; - for(var i=0; i this.iMaxRows) iRows = this.iMaxRows; - - this.oRowInput.value = iRows; - this._showNewTable(); - }, - - $ON_ST_SET_COLUMN_NUM : function(iColumns, iColumnDiff){ - iColumns = iColumns || parseInt(this.oColumnInput.value); - iColumnDiff = iColumnDiff || 0; - - iColumns += iColumnDiff; - - if(iColumns < this.iMinColumns) iColumns = this.iMinColumns; - if(iColumns > this.iMaxColumns) iColumns = this.iMaxColumns; - - this.oColumnInput.value = iColumns; - this._showNewTable(); - }, - - $ON_ST_INSERT_TABLE : function(){ - var sTable = this._getTableString(); - - this.oApp.exec("PASTE_HTML", [sTable]); - - this.oApp.exec("ST_CLOSE", []); - }, - - $ON_ST_CLOSE : function(){ - this.oApp.exec("HIDE_ACTIVE_LAYER", []); - }, - - $ON_ST_SET_BORDER_WIDTH : function(iBorderWidth, iBorderWidthDiff){ - iBorderWidth = iBorderWidth || parseInt(this.oBorderWidthInput.value); - iBorderWidthDiff = iBorderWidthDiff || 0; - - iBorderWidth += iBorderWidthDiff; - - if(iBorderWidth < this.iMinBorderWidth) iBorderWidth = this.iMinBorderWidth; - if(iBorderWidth > this.iMaxBorderWidth) iBorderWidth = this.iMaxBorderWidth; - - this.oBorderWidthInput.value = iBorderWidth; - this._showNewTable(); - }, - - $ON_ST_INC_BORDER_WIDTH : function(){ - this.oApp.exec("ST_SET_BORDER_WIDTH", [null, 1]); - }, - - $ON_ST_DEC_BORDER_WIDTH : function(){ - this.oApp.exec("ST_SET_BORDER_WIDTH", [null, -1]); - }, - - $ON_ST_TOGGLE_BORDER_COLOR_LAYER : function(){ - if(this.welDropdownLayer.hasClass("p1")) - this.oApp.exec("ST_HIDE_BORDER_COLOR_LAYER", []); - else - this.oApp.exec("ST_SHOW_BORDER_COLOR_LAYER", []); - }, - - $ON_ST_SHOW_BORDER_COLOR_LAYER : function(){ - this.welDropdownLayer.addClass("p1"); - this.welDropdownLayer.removeClass("p2"); - - this.oApp.exec("SHOW_COLOR_PALETTE", ["ST_SET_BORDER_COLOR_FROM_PALETTE", this.elDropdownLayer]); - }, - - $ON_ST_HIDE_BORDER_COLOR_LAYER : function(){ - this.welDropdownLayer.removeClass("p1"); - - this.oApp.exec("HIDE_COLOR_PALETTE", []); - }, - - $ON_ST_TOGGLE_BGCOLOR_LAYER : function(){ - if(this.welDropdownLayer.hasClass("p2")) - this.oApp.exec("ST_HIDE_BGCOLOR_LAYER", []); - else - this.oApp.exec("ST_SHOW_BGCOLOR_LAYER", []); - }, - - $ON_ST_SHOW_BGCOLOR_LAYER : function(){ - this.welDropdownLayer.removeClass("p1"); - this.welDropdownLayer.addClass("p2"); - - this.oApp.exec("SHOW_COLOR_PALETTE", ["ST_SET_BGCOLOR_FROM_PALETTE", this.elDropdownLayer]); - }, - - $ON_ST_HIDE_BGCOLOR_LAYER : function(){ - this.welDropdownLayer.removeClass("p2"); - - this.oApp.exec("HIDE_COLOR_PALETTE", []); - }, - - $ON_ST_SET_BORDER_COLOR_FROM_PALETTE : function(sColorCode){ - this.oApp.exec("ST_SET_BORDER_COLOR", [sColorCode]); - this.oApp.exec("ST_HIDE_BORDER_COLOR_LAYER", []); - }, - - $ON_ST_SET_BORDER_COLOR : function(sColorCode){ - this.oBorderColorInput.value = sColorCode; - this.oButton_BorderColorPreview.style.backgroundColor = sColorCode; - - this._showNewTable(); - }, - - $ON_ST_SET_BGCOLOR_FROM_PALETTE : function(sColorCode){ - this.oApp.exec("ST_SET_BGCOLOR", [sColorCode]); - this.oApp.exec("ST_HIDE_BGCOLOR_LAYER", []); - }, - - $ON_ST_SET_BGCOLOR : function(sColorCode){ - this.oBGColorInput.value = sColorCode; - this.oButton_BGColorPreview.style.backgroundColor = sColorCode; - - this._showNewTable(); - }, - - _showNewTable : function(){ - var oTmp = document.createElement("DIV"); - oTmp.innerHTML = this._getTableString(); - var oNewTable = oTmp.firstChild; - this.oSampleTable.parentNode.insertBefore(oNewTable, this.oSampleTable); - this.oSampleTable.parentNode.removeChild(this.oSampleTable); - this.oSampleTable = oNewTable; - }, - - // need to do something about the table width as the same HTML code is being used to the actual table and the preview table - _getTableString : function(){ - var sBorderColorCode = this.oBorderColorInput.value; - var sBGColorCode = this.oBGColorInput.value; - var iBorderWidth = this.oBorderWidthInput.value; - var sTD = ""; - if(jQuery.browser.msie){ - sTD = "

"; - }else{ - if(jQuery.browser.firefox){ - sTD = ""; - }else{ - sTD = ""; - } - } - - var sTable = '


 

'; - var sRow = ''; - var iColumns = this.oColumnInput.value; - for(var i=0; i/ig, - regex_meanless_css2 = /(?:(?:margin|padding)\s*:\s*0(?:px)?|\-(?:moz|ms|webkit|opera)\-[\w-]+\s*:\s*.*?|[\w-]+\s*:\s*\-(?:moz|ms|webkit|opera)\-[\w-]+|(?:line-height|font-variant|font-stretch|font-size-adjust|font-size)\s*:\s*[a-z_-]+)\s*;?\s*|font-(?:weight|style)\s*:\s*normal;?/ig, - regex_class = /<(.*?)\s+class\s*=(?:\s*"(.*?)"|\s*'(.*?)'|([^\s>]+))(.*?)>/ig, - regex_class2 = /xe_selected_cell/g; - regex_handler = /<(.*?)\s+on[a-z]+\s*=(?:\s*".*?"|\s*'.*?'|[^\s>]+)(.*?)>/ig, - //regex_id = /<(.*?)\s+id\s*=(?:[^\s>]+|\s*".*?"|\s*'.*?')(.*?)>/ig, - //regex_script = //ig, - regex_font_color = /color\s*=(?:\s*"(.*?)"|\s*'(.*?)'|([^\s>]+))/i, - regex_font_face = /face\s*=(?:\s*"(.*?)"|\s*'(.*?)'|([^\s>]+))/i, - regex_font_size = /size\s*=(?:\s*"(\d+)"|\s*'(\d+)'|(\d+))/i, - regex_style = /style\s*=\s*(?:\s*"(.*?)"|\s*'(.*?)'|([^\s>]+))/i, - regex_font_weight = /font-weight\s*:\s*([a-z]+);?/i, - regex_font_style = /font-style\s*:\s*italic;?/i, - regex_font_decoration = /text-decoration\s*:\s*([a-z -]+);?/i, - regex_jquery = /jQuery\d+\s*=(\s*"\d+"|\d+)/ig, - regex_quote_attr = /([\w-]+\s*=(?:\s*"[^"]+"|\s*'[^']+'))|([\w-]+)=([^\s]+)/g; //" - -var - allow_tags = 'a,abbr,acronym,address,area,blockquote,br,caption,center,cite,code,col,colgroup,dd,del,dfn,div,dl,dt,em,embed,h1,h2,h3,h4,h5,h6,hr,img,ins,kbd,li,map,object,ol,p,param,pre,q,samp,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,tt,u,ul,var,iframe,object,param,style'.split(','), - lonely_tags = 'area,br,col,embed,hr,img,input,param'.split(','); - -var - replace_tags = { - 'b' : 'strong', - 'i' : 'em', - 's' : 'del', - 'strike' : 'del' - }; - -xe.XE_XHTMLFormatter = $.Class({ - name : "XE_XHTMLFormatter", - - $ON_MSG_APP_READY : function() { - this.oApp.addConverter("WYSIWYG_TO_IR", this.TO_IR); - this.oApp.addConverter("HTMLSrc_TO_IR", this.TO_IR); - this.oApp.addConverter("IR_TO_HTMLSrc", this.IR_TO); - this.oApp.addConverter("IR_TO_WYSIWYG", this.IR_TO); - }, - - TO_IR : function(sContent) { - var stack = []; - - // remove xeHandled attrs - sContent = sContent.replace(/xeHandled="YES"/ig,''); - - - // remove all useless styles - sContent = sContent.replace(regex_meanless_css1, function(m0,m1,m2,m3){ - m2 = m2.replace(regex_meanless_css2, ''); - - return '<'+m1+(m2?' style="'+m2+'"':'')+m3+'>'; - }); - - // remove all useless classes - sContent = sContent.replace(regex_class, function(m0,m1,m2,m3,m4,m5){ - var cls = jQuery.trim((m2 || m3 || m4 || "").replace(regex_class2, '')); - - return '<'+(m1||"")+(cls?' class="'+cls+'"':'')+(m5||"")+'>'; - }); - - // remove all event handler - sContent = sContent.replace(regex_handler, '<$1$2>'); - - // remove all id - //sContent = sContent.replace(regex_id, '<$1$2>'); - - // remove all scripts - //sContent = sContent.replace(regex_script, ''); - - if (jQuery.browser.msie) { - // remove jQuery attributes - sContent = sContent.replace(regex_jquery, ''); - - // quote all attrs - sContent = sContent.replace(/<(\w+) ([^>]+)>/g, function(m0,m1,m2){ - return '<'+m1+' '+ - m2.replace(regex_quote_attr, function(s0,s1,s2,s3){ - if (s1) return s1; - if(/^"/.test(s3)||/"$/.test(s3)) return s2+'='+s3; - return s2+'="'+s3+'"'; - }) + '>'; - }); - } - - // remove all useless tag and enclose tags - regex = /<(\/)?([:\w\/-]+)(.*?)>/ig; - sContent = sContent.replace(regex, function(m0,m1,m2,m3){ - var m3s = []; - var state = ''; - - m1 = m1 || ''; - m2 = m2.toLowerCase(); - m3 = $.trim(m3 || ''); - - if (!m1) { - if ($.inArray(m2,lonely_tags) >= 0) { - var len = m3.length; - if (m2 == 'br') m3 = ''; - if (!m3 || m3.substring(len-1,len) != '/') m3 += ' /'; - - return '<'+m2+' '+m3+'>'; - } - - if (replace_tags[m2]) { - stack.push({tag:m2, state:'deleted'}); - - m2 = replace_tags[m2]; - state = 'inserted'; - } else if (m2 == 'font') { - stack.push({tag:m2, state:'deleted'}); - - m2 = 'span'; - m3s = []; - if (regex_font_color.test(m3)) m3s.push('color:'+(RegExp.$1||RegExp.$2||RegExp.$3)+';'); - if (regex_font_face.test(m3)) m3s.push('font-family:'+(RegExp.$1||RegExp.$2||RegExp.$3)+';'); - - m3 = m3s.length?'style="'+m3s.join('')+'"':''; - state = 'inserted'; - } else if (m2 == 'center') { - stack.push({tag:m2, state:'deleted'}); - - m2 = 'div' - m3 = 'style="text-align:center"'; - - state = 'inserted'; - } else if (m2 == 'span') { - var style = ''; - - if (!m3) { - stack.push({tag:m3, state:'deleted'}); - return ''; - } - - if (regex_style.test(m3)) { - var tmpstack = []; - var tmptag = ''; - - style = RegExp.$1||RegExp.$2||RegExp.$3; - m3 = m3.replace(regex_style, ''); - - if (regex_font_weight.test(style)) { - if (RegExp.$1 == 'bold' || RegExp.$1 == 'bolder') { - style = style.replace(regex_font_weight, ''); - tmpstack.push({tag:'strong', state:'inserted'}); - tmptag += ''; - } - } - - if (regex_font_style.test(style)) { - style = style.replace(regex_font_style, ''); - tmpstack.push({tag:'em', state:'inserted'}); - tmptag += ''; - } - - if (regex_font_decoration.test(style)) { - var deco_css = ' '+RegExp.$1.toLowerCase()+' '; - - if (deco_css.indexOf('underline ') > 0) { - deco_css = deco_css.replace('underline ', ''); - tmpstack.push({tag:'u', state:'inserted'}); - tmptag += ''; - } - - if (deco_css.indexOf('line-through ') > 0) { - deco_css = deco_css.replace('line-through ', ''); - tmpstack.push({tag:'del', state:'inserted'}); - tmptag += ''; - } - - deco_css = $.trim(deco_css); - style = style.replace(regex_font_decoration, (deco_css?'text-decoration:'+deco_css+';':'')); - } - - style = $.trim(style); - - stack.push({tag:m2, state:(!m3&&!style?'deleted':'')}); - stack = stack.concat(tmpstack); - - return (!m3&&!style?'':'')+tmptag; - } - } else { - state = (jQuery.inArray(m2,allow_tags) < 0)?'deleted':''; - if (state == 'deleted') return ''; - } - - stack.push({tag:m2, state:state}); - } else { - var tags = [], t = ''; - - if (!stack.length) return ''; - - do { - t = stack.pop(); - if (t.state != 'inserted' && t.tag != m2) { - stack.push(t); - return tags.join(''); - } - if (t.state != 'deleted') tags.push(''); - } while(stack.length && t.tag != m2); - - return tags.join(''); - } - - return '<'+m1+m2+(m3?' '+m3:'')+'>'; - }); - if (stack.length) { - var t = ''; - - do { - t = stack.pop(); - if (t.state != 'deleted') sContent += ''; - } while(stack.length); - } - - return sContent; - }, - - IR_TO : function(sContent) { - return sContent; - } -}); - -// center, font, b, i, s, strike - -})(jQuery); -/** - * Support XE extensions - * @author gony - */ -xe.XE_Extension = jQuery.Class({ - name : "XE_Extension", - seq : '', - - $init : function(elAppContainer, editor_sequence) { - this.seq = editor_sequence; - this._assignHTMLObjects(elAppContainer); - }, - - _assignHTMLObjects : function(elAppContainer) { - this.elDropdownLayer = jQuery('DIV.xpress_xeditor_extension_layer', elAppContainer).get(0); - }, - - _removeAttrs : function(sContent) { - return sContent; - }, - - _addEvent : function() { - if (this.oApp.getEditingMode() != 'WYSIWYG') return; - - var doc = this.oApp.getWYSIWYGDocument(); - var seq = this.seq; - var fn = function(){ - var obj = jQuery(this); - var comp = obj.attr('editor_component'); - if (comp && jQuery.isFunction(openComponent)) { - editorPrevNode = obj.get(0); - openComponent(comp, seq); - } - }; - - jQuery('img,div[editor_component]', doc).each(function(){ - var obj = jQuery(this); - if(this.nodeName == 'IMG' && !obj.attr('editor_component')) obj.attr('editor_component','image_link') - if(!obj.attr('xeHandled')) { - obj.attr('xeHandled','YES'); - obj.dblclick(fn); - } - }); - }, - - $ON_MSG_APP_READY : function() { - this.oApp.exec('REGISTER_UI_EVENT', ['extension', 'click', 'TOGGLE_EXTENSION_LAYER']); - }, - - $ON_TOGGLE_EXTENSION_LAYER : function() { - this.oApp.exec('TOGGLE_TOOLBAR_ACTIVE_LAYER', [this.elDropdownLayer]); - }, - - $ON_CHANGE_EDITING_MODE : function(mode) { - var self = this; - setTimeout(function(){ self._addEvent(); }, 100); - }, - - $ON_PASTE_HTML : function() { - var self = this; - setTimeout(function(){ self._addEvent(); }, 100); - }, - - $ON_LOAD_IR_FIELD : function() { - var self = this; - setTimeout(function(){ self._addEvent(); }, 100); - }, - - $ON_SET_IR : function() { - var self = this; - setTimeout(function(){ self._addEvent(); }, 100); - } -}); -/** - * Auto saving - * @author gony - */ -xe.XE_AutoSave = jQuery.Class({ - name : "XE_AutoSave", - form : null, - textarea : null, - - $init : function(oIRTextarea, elAppContainer) { - this.form = oIRTextarea.form; - this.textarea = oIRTextarea; - - this._assignHTMLObjects(elAppContainer); - }, - - _assignHTMLObjects : function(elAppContainer) { - this.welMessageBox = jQuery('autosave_message'); - }, - - $ON_MSG_APP_READY : function() { - var elTitle = jQuery(this.form._saved_doc_title); - var elContent = jQuery(this.form._saved_doc_content); - var title = jQuery.trim(elTitle.val()); - var content = jQuery.trim(elContent.val()); - - if (title || content) { - if (confirm(this.form._saved_doc_message.value)) { - jQuery(this.form.title).val(title); - this.oApp.setIR(content); - } else { - editorRemoveSavedDoc(); - } - } - - editorEnableAutoSave(this.form, jQuery(this.form).attr("editor_sequence")); - - // register hotkey - this.oApp.exec('REGISTER_HOTKEY', ['ctrl+shift+s','AUTO_SAVE']); - }, - - $ON_AUTO_SAVE : function() { - _editorAutoSave(); - } -}); -/** - * Format Block plugin - * @author gony - */ -xe.XE_FormatWithSelectUI = jQuery.Class({ - name : "XE_FormatWithSelectUI", - - $init : function(elAppContainer){ - this._assignHTMLObjects(elAppContainer); - }, - - _assignHTMLObjects : function(elAppContainer){ - this.elFormatSelect = jQuery("SELECT.xpress_xeditor_ui_format_select", elAppContainer).get(0); - }, - - $ON_MSG_APP_READY : function(){ - this.oApp.registerBrowserEvent(this.elFormatSelect, "change", "SET_FORMAT_FROM_SELECT_UI"); - this.elFormatSelect.selectedIndex = 0; - }, - - $ON_MSG_STYLE_CHANGED : function(sAttributeName, sAttributeValue){ - var blockName = this.oApp.getWYSIWYGDocument().queryCommandValue("FormatBlock"); - - if (!blockName) return (this.elFormatSelect.selectedIndex = 0); - if (jQuery.browser.msie && /([0-9])/.test(blockName)) blockName = 'h'+(RegExp.$1); - - this.elFormatSelect.value = blockName.toLowerCase(); - if(this.elFormatSelect.selectedIndex < 0) this.elFormatSelect.selectedIndex = 0; - }, - - $ON_SET_FORMAT_FROM_SELECT_UI : function(){ - var sFormat = this.elFormatSelect.value; - if(!sFormat) return; - if(jQuery.browser.msie) sFormat = '<'+sFormat+'>'; - - this.oApp.exec("EXECCOMMAND", ["FormatBlock", false, sFormat]); - this.oApp.exec("CHECK_STYLE_CHANGE", []); - } -}); -/** - * Enhanced Table Fetures - * @author gony - */ - -// 표 편집 확장 기능 -xe.XE_Table = jQuery.Class({ - _startSel : null, - _endSel : null, - - $ON_MSG_APP_READY : function() { - this._doc = jQuery(this.oApp.getWYSIWYGDocument()); - - this.$FnMouseDown = jQuery.fnBind(this._mousedown, this); - this.$FnMouseUp = jQuery.fnBind(this._mouseup, this); - this.$FnMouseMove = jQuery.fnBind(this._mousemove, this); - - this._doc.mousedown(this.$FnMouseDown); - - // initialize - this._startSel = null; - this._endSel = null; - - // register buttons - this.oApp.exec('REGISTER_UI_EVENT', ['merge_cells', 'click', 'MERGE_CELLS']); - this.oApp.exec('REGISTER_UI_EVENT', ['split_col', 'click', 'CELL_SPLIT_BY_COL']); - this.oApp.exec('REGISTER_UI_EVENT', ['split_row', 'click', 'CELL_SPLIT_BY_ROW']); - - // register hotkeys - this.oApp.exec('REGISTER_HOTKEY', ['ctrl+alt+m', 'MERGE_CELLS']); - - // perform default ready action - this.$super.$ON_MSG_APP_READY(); - }, - - $ON_MERGE_CELLS : function() { - var html = ""; - var cell = jQuery('.xe_selected_cell', this.oApp.getWYSIWYGDocument()).filter('td,th'); - var self = this; - - // 선택된 셀이 없으면 종료 - if (!cell.length) return; - - // UNDO 지점 기록 - this.oApp.exec("RECORD_UNDO_ACTION", ["Cell:Merge"]); - - // 선택한 모든 셀의 데이터를 첫번째 셀로 복사 - cell.each(function(){ html += jQuery(this).html() }).eq(0).html(html); - - // 첫번째 셀 가로 확장 - var colspan = 0; - cell.eq(0).nextAll('td,th').andSelf().filter('.xe_selected_cell').each(function(idx){ - colspan += self._getSpan(this, 'col'); - }); - - // 마지막 셀까지 줄의 갯수 계산 - var rect = this._getRect(cell.eq(0)); - var start_tr = cell.eq(0).parent('tr'); - var end_tr = cell.eq(cell.length-1).parent('tr'); - var all_rows = cell.parents('table').eq(0).find('tr'); - var rowspan = all_rows.index(end_tr.get(0)) - all_rows.index(start_tr.get(0)) + this._getSpan(cell.eq(cell.length-1), 'row'); - - // 첫번째 셀 colspan, rowspan 속성 지정 - cell.eq(0).attr('colSpan', colspan).attr('rowSpan', rowspan); - - // 첫번째 셀을 제외한 다른 모든 셀 제거 - cell.slice(1).remove(); - }, - - $ON_CELL_SPLIT_BY_ROW : function(many) { - var cell = jQuery('.xe_selected_cell', this.oApp.getWYSIWYGDocument()).filter('td,th'); - var table = cell.parents('table').eq(0); - var self = this; - - // 선택된 셀이 없으면 종료 - if (!cell.length) return; - - // UNDO 지점 기록 - this.oApp.exec("RECORD_UNDO_ACTION", ["Cell:Split By Row"]); - - // 선택 영역의 상하 좌표 구함 - var _top = this._getRect(cell.eq(0)).top; - var _bottom = this._getRect(cell.eq(cell.length-1)).bottom; - - // 테이블의 모든 셀에서 선택영역에 해당하는 셀을 구한다(상하 기준). - (cell = table.find('td,th').filter(function(){ - var rect = self._getRect(jQuery(this)); - - return !(rect.bottom <= _top || rect.top >= _bottom); - })).filter('.xe_selected_cell').each(function(){ - var t = jQuery(this); - var row = t.parent('tr'); - var rowspan = self._getSpan(t, 'row'); - var rect = self._getRect(t); - var queue = []; - var clone = t.clone().html('
'); - var topspan = 1, botspan = 1; - - // rowspan > 1이면 현재 셀의 rowspan을 절반으로 분할한다. - if (rowspan > 1) { - - topspan = Math.ceil(rowspan/2); - botspan = rowspan - topspan; - - queue.push(function(){ - t.attr('rowSpan', topspan); - }); - - clone.attr('rowSpan', botspan); - } else { - // rowspan이 없으면 현재 셀과 영역이 겹치는 모든 셀에 rowspan을 추가 - cell.filter(function(){ - if (t.get(0) == this) return false; - - var tt = jQuery(this); - var rc = self._getRect(tt); - - // 범위를 넘은 부분은 제외 - if (rc.bottom <= rect.top || rc.top >= rect.bottom) return false; - - return true; - }).each(function(){ - var tt = jQuery(this); - var sp = self._getSpan(tt, 'row')+1; - - // rowspan 1 추가 - queue.push(function(){ - tt.attr('rowSpan', sp); - }); - }); - - // 새 줄을 추가한다. - if (jQuery.browser.msie) { - // Fix bug for IE - row.after(row.clone().empty().get(0).outerHTML); - } else { - row.after(row.clone().empty()); - } - } - - var rows = row.nextAll('tr'); - - // 현재 셀이 마지막 줄에 있다면 한 줄 추가 후 새로운 셀 추가 - if (!rows.length) { - row.after(row.clone().empty().append(clone)); - } else { - var next_sib = rows.eq(topspan - 1).children('td,th').filter(function(){ - return ( self._getRect(jQuery(this)).left > rect.left ); - }); - - if (jQuery.browser.msie) { - next_sib.length? - next_sib.eq(0).before(clone.get(0).outerHTML): - rows.eq(topspan-1).append(clone.get(0).outerHTML); - } else { - next_sib.length? - next_sib.slice(0,1).before(clone): - rows.slice(topspan-1,1).append(clone); - } - } - - // 함수를 바로 실행하면 좌표가 틀어지므로, 큐에 넣은 후 실행 - jQuery.each(queue, function(){ this(); }); - - }); - }, - - $ON_CELL_SPLIT_BY_COL : function(many) { - var cell = jQuery('.xe_selected_cell', this.oApp.getWYSIWYGDocument()).filter('td,th'); - var table = cell.parents('table').slice(0,1); - var self = this; - var ie_bug = [], tmpId = (new Date).getTime(), tmpStr = ''; - - // 선택된 셀이 없으면 종료 - if (!cell.length) return; - - // UNDO 지점 기록 - this.oApp.exec("RECORD_UNDO_ACTION", ["Cell:Split By Column"]); - - // 선택 영역의 좌우 좌표 구함 - var first_row = cell.eq(0).parent('tr'); - var _left = this._getRect(first_row.find('.xe_selected_cell:first')).left; - var _right = this._getRect(first_row.find('.xe_selected_cell:last')).right; - - // 테이블의 모든 셀에서 선택영역에 해당하는 셀을 구한다(좌우 기준). - (cell = table.find('td,th').filter(function(){ - var rect = self._getRect(jQuery(this)); - - return !(rect.right <= _left || rect.left >= _right); - })).filter('.xe_selected_cell').each(function(idx){ - var t = jQuery(this); - var colspan = self._getSpan(t, 'col'); - var clone = t.clone().html('
'); - - // colspan > 1 이면 colspan을 절반으로 분할한다. - if (colspan > 1) { - var leftspan = Math.ceil(colspan/2); - var rightspan = colspan - leftspan; - - t.attr('colSpan', leftspan); - clone.attr('colSpan', rightspan); - } else { - // colspan이 없으면 현재 셀과 영역이 겹치는 모든 셀에 colspan을 추가 - var rect = self._getRect(t); - - cell.filter(function(){ - if (t.get(0) == this) return false; - - var tt = jQuery(this); - var rc = self._getRect(tt); - - // 범위를 넘은 부분은 제외 - if (rc.right <= rect.left || rc.left >= rect.right) return false; - - return true; - }).each(function(){ - var tt = jQuery(this); - - // colspan 1 추가 - tt.attr('colSpan', self._getSpan(tt, 'col')+1); - }); - - clone.attr('colSpan', 1); - } - - if (jQuery.browser.msie) { - // Fix for IE bug - t.after(clone.get(0).outerHTML); - } else { - t.after(clone); - } - }); - }, - - $ON_CHECK_STYLE_CHANGE : function(){ - var ui = ['merge_cells', 'split_col', 'split_row']; - var app = this.oApp; - var command = (this._startSel && this._startSel.is('.xe_selected_cell'))?'ENABLE_UI':'DISABLE_UI'; - - jQuery.each(ui, function(){ app.exec(command, [this]); }); - }, - - _mousedown : function(event) { - var cur = jQuery(event.target); - var sel = cur.parents().andSelf().filter('td,th,table'); - var app = this.oApp; - var self = this; - - // 모든 선택영역 해제 - jQuery('td.xe_selected_cell', this.oApp.getWYSIWYGDocument()).removeClass('xe_selected_cell'); - - this._startSel = null; - this._endSel = null; - - if (!sel.length || !this._isLeftClicked(event.button)) return; - - function delayed(){ - sel = app.getSelection().cloneRange(); - sel.collapseToStart(); - sel = jQuery(sel.startContainer).parents().andSelf().filter('td,th').eq(0); - - if (!sel.length) return self._removeAllListener()||true; - - // 좌표를 구한다 - self._getRect(self._startSel = sel); - - // 이벤트 바인딩 - self._doc.bind('mousemove', self.$FnMouseMove); - self._doc.bind('mouseup', self.$FnMouseUp); - } - - // mousedown이 일어난 후에 선택 영역이 설정되므로 실행을 지연시킨다. - setTimeout(delayed, 0); - }, - - _mouseup : function(event) { - // 선택된 셀 확인 - this._removeAllListener(); - - // 시작셀과 종료셀 제거 - this._startSel = this._endSel = null; - }, - - _mousemove : function(event) { - var cur = jQuery(event.target); - var cell = cur.parents().andSelf().filter('td,th').eq(0); - var self = this; - - // 마우스 왼쪽 버튼이 눌리지 않았으면 종료 - if (!cell.length || !this._isLeftClicked(event.button)) return; - if (!this._endSel && cell.get(0) == this._startSel.get(0)) return; - if (this._endSel && cell.get(0) == this._endSel.get(0)) return; - - // 종료셀 && 종료셀의 좌표 - this._getRect(this._endSel = cell); - - // 선택 범위를 구한다 - var _top = Math.min(this._startSel.rect.top, this._endSel.rect.top); - var _left = Math.min(this._startSel.rect.left, this._endSel.rect.left); - var _bottom = Math.max(this._startSel.rect.bottom, this._endSel.rect.bottom); - var _right = Math.max(this._startSel.rect.right, this._endSel.rect.right); - - var table = cell.parents('table'); - var cells = table.find('td,th').removeClass('xe_selected_cell'); - var i = 0; - - // 복잡한 모양의 테이블을 위한 반복 처리 - var selected = jQuery(); - do { - // 선택한 셀로 최대 영역 재계산 - selected.each(function(){ - var rect = self._getRect(jQuery(this)); - - // 영역 재계산 - if (rect.right > _right) _right = rect.right; - if (rect.left < _left) _left = rect.left; - if (rect.top < _top) _top = rect.top; - if (rect.bottom > _bottom) _bottom = rect.bottom; - }); - - // 좌표 범위 안에 있는 선택할 셀을 추린다. - cells = cells.filter(':not(.xe_selected_cell)'); - selected = cells.filter(function(){ - var rect = self._getRect(jQuery(this)); - - if (rect.right <= _left || rect.left >= _right || rect.bottom <= _top || rect.top >= _bottom) return false; - - return true; - }).addClass('xe_selected_cell'); - } while(selected.length); - - // 브라우저의 기본 선택영역 해제 : FF 제외 - 기본 기능이 충분히 좋아서 + 이 부분을 실행하면 오류가 발생해서 - if (!jQuery.browser.mozilla) { - function delayed() { - var sel = self.oApp.getSelection(); - - if (!self._startSel) return; - if (!self._startSel.get(0).firstChild) self._startSel.text(" "); - - sel.selectNode(self._startSel.get(0).firstChild); - sel.collapseToStart(); - sel.select(); - } - - setTimeout(delayed, 0); - } - - return false; - }, - - _removeAllListener : function() { - // 이벤트 해제 - this._doc.unbind("mousemove", this.$FnMouseMove); - this._doc.unbind("mouseup", this.$FnMouseUp); - }, - - _isLeftClicked : function(value) { - return jQuery.browser.msie?!!(value & 1):(value == 0); - }, - - _getRect : function(obj) { - var el = obj.get(0); - - obj.rect = {}; - obj.rect.top = el.offsetTop; - obj.rect.left = el.offsetLeft; - obj.rect.bottom = obj.rect.top + el.offsetHeight; - obj.rect.right = obj.rect.left + el.offsetWidth; - - return obj.rect; - }, - - _getSpan : function(obj, type) { - var span = parseInt(jQuery(obj).attr(type+'span')); - - return isNaN(span)?1:span; - } -}).extend(xe.XE_Table); +// extends jQuery object +(function($){ + +$.extend({ + Class : function(def) { + function c(){ + if (typeof this.$super != 'undefined') this.$super.$this = this; + if ($.isFunction(this.$init)) this.$init.apply(this, arguments); + } + c.prototype = def; + c.constructor = c; + c.extend = Class_extend; + + return c; + }, + $ : function(id) { + if(typeof id == 'string') { + if (id.substring(0,1) == '<') return $(id).get(0); + return $('#'+id).get(0); + } else { + return id; + } + }, + fnBind : function(fn, th/* , args... */) { + var args = $.makeArray(arguments); + args.shift(); args.shift(); + + return function() { + var a = args.concat($.makeArray(arguments)); + + return fn.apply(th, a); + }; + } +}); + +$.browser.nVersion = parseFloat($.browser.version); + +function Class_extend(superDef) { + var Super = superDef.prototype; + + this.prototype.$super = {}; + + function bind(fn) { + return function() { + return fn.apply(this.$this, arguments); + }; + } + + for(var x in Super) { + if (!Super.propertyIsEnumerable(x)) continue; + + if (typeof this.prototype[x] == 'undefined') this.prototype[x] = Super[x]; + this.prototype.$super[x] = $.isFunction(Super[x])?bind(Super[x]):Super[x]; + } + + return this; +} + +})(jQuery); + +if (typeof window.xe == 'undefined') window.xe = {}; + +//{ + /** + * @fileOverview This file contains Xpress framework core + * @name XpressCore.js + */ +xe.XpressCore = jQuery.Class({ + name : "XpressCore", + + $init : function(htOptions){ + htOptions = !htOptions?{}:jQuery.Class({}).extend({ + oDebugger : null + }).extend(htOptions); + if(htOptions.oDebugger){ + this.oDebugger = htOptions.oDebugger; + this.oDebugger.oApp = this; + } + + // To prevent processing a Xpress command before all the plugins are registered and ready, + // Queue up all the commands here until the application's status is changed to READY + this.commandQueue = []; + + this.oCommandMap = {}; + this.oDisabledCommand = {}; + this.aPlugins = []; + + this.appStatus = xe.APP_STATUS["NOT_READY"]; + + // Register the core as a plugin so it can receive messages + this.registerPlugin(this); + }, + + exec : function(msg, args, oEvent){ + // If the application is not yet ready just queue the command + if(this.appStatus == xe.APP_STATUS["NOT_READY"]){ + this.commandQueue[this.commandQueue.length] = {'msg':msg, 'args':args, 'event':oEvent}; + return true; + } + + this.exec = this._exec; + this.exec(msg, args, oEvent); + }, + + delayedExec : function(msg, args, nDelay, oEvent){ + var fExec = jQuery.fnBind(this.exec, this, msg, args, oEvent); + setTimeout(fExec, nDelay); + }, + + _exec : function(msg, args, oEvent){return (this._exec = this.oDebugger?this._execWithDebugger:this._execWithoutDebugger).call(this, msg, args, oEvent);}, + _execWithDebugger : function(msg, args, oEvent){this.oDebugger.log_MessageStart(msg, args);var bResult = this._doExec(msg, args, oEvent);this.oDebugger.log_MessageEnd(msg, args);return bResult; }, + _execWithoutDebugger : function(msg, args, oEvent){return this._doExec(msg, args, oEvent);}, + _doExec : function(msg, args, oEvent){ + var bContinue = false; + + if(!this.oDisabledCommand[msg]){ + var allArgs = []; + if(args && args.length){ + var iLen = args.length; + for(var i=0; i= 0 && xe.DOMFix.parentNode(aAllNodes[iChildIdx]) == aAllNodes[iCurIdx]){ + iChildIdx = this._recurConstructClonedTree(aAllNodes, iChildIdx, aAllNodes[iCurIdx], oCurNodeCloneWithChildren, oClonedStartContainer, oClonedEndContainer); + } + + // this may trigger an error message in IE when an erroneous script is inserted + oClonedParentNode.insertBefore(oCurNodeCloneWithChildren, oClonedParentNode.firstChild); + + return iChildIdx; + }; + + aNodes[aNodes.length] = xe.DOMFix.parentNode(aNodes[aNodes.length-1]); + _recurConstructClonedTree(aNodes, aNodes.length-1, aNodes[aNodes.length-1], oClonedParentNode); + + return {oStartContainer: oClonedStartContainer, oEndContainer: oClonedEndContainer}; + }, + + cloneRange : function(){ + return this._copyRange(new xe.W3CDOMRange(this._document)); + }, + + _copyRange : function(oClonedRange){ + oClonedRange.collapsed = this.collapsed; + oClonedRange.commonAncestorContainer = this.commonAncestorContainer; + oClonedRange.endContainer = this.endContainer; + oClonedRange.endOffset = this.endOffset; + oClonedRange.startContainer = this.startContainer; + oClonedRange.startOffset = this.startOffset; + oClonedRange._document = this._document; + + return oClonedRange; + }, + + collapse : function(toStart){ + if(toStart){ + this.endContainer = this.startContainer; + this.endOffset = this.startOffset; + }else{ + this.startContainer = this.endContainer; + this.startOffset = this.endOffset; + } + + this._updateRangeInfo(); + }, + + compareBoundaryPoints : function(how, sourceRange){ + switch(how){ + case xe.W3CDOMRange.START_TO_START: + return this._compareEndPoint(this.startContainer, this.startOffset, sourceRange.startContainer, sourceRange.startOffset); + case xe.W3CDOMRange.START_TO_END: + return this._compareEndPoint(this.endContainer, this.endOffset, sourceRange.startContainer, sourceRange.startOffset); + case xe.W3CDOMRange.END_TO_END: + return this._compareEndPoint(this.endContainer, this.endOffset, sourceRange.endContainer, sourceRange.endOffset); + case xe.W3CDOMRange.END_TO_START: + return this._compareEndPoint(this.startContainer, this.startOffset, sourceRange.endContainer, sourceRange.endOffset); + } + }, + + _findBody : function(oNode){ + if(!oNode) return null; + while(oNode){ + if(oNode.tagName == "BODY") return oNode; + oNode = xe.DOMFix.parentNode(oNode); + } + return null; + }, + + _compareEndPoint : function(oContainerA, iOffsetA, oContainerB, iOffsetB){ + var iIdxA, iIdxB; + + if(!oContainerA || this._findBody(oContainerA) != this._document.body){ + oContainerA = this._document.body; + iOffsetA = 0; + } + + if(!oContainerB || this._findBody(oContainerB) != this._document.body){ + oContainerB = this._document.body; + iOffsetB = 0; + } + + var compareIdx = function(iIdxA, iIdxB){ + // iIdxX == -1 when the node is the commonAncestorNode + // if iIdxA == -1 + // -> [[...]]... + // if iIdxB == -1 + // -> ...[[...]] + if(iIdxB == -1) iIdxB = iIdxA+1; + if(iIdxA < iIdxB) return -1; + if(iIdxA == iIdxB) return 0; + return 1; + }; + + var oCommonAncestor = this._getCommonAncestorContainer(oContainerA, oContainerB); + + // ================================================================================================================================================ + // Move up both containers so that both containers are direct child nodes of the common ancestor node. From there, just compare the offset + // Add 0.5 for each contaienrs that has "moved up" since the actual node is wrapped by 1 or more parent nodes and therefore its position is somewhere between idx & idx+1 + // NODE1

NODE2

NODE3
+ // The position of NODE2 in COMMON_ANCESTOR is somewhere between after NODE1(idx1) and before NODE3(idx2), so we let that be 1.5 + + // container node A in common ancestor container + var oNodeA = oContainerA; + if(oNodeA != oCommonAncestor){ + while((oTmpNode = xe.DOMFix.parentNode(oNodeA)) != oCommonAncestor){oNodeA = oTmpNode;} + + iIdxA = this._getPosIdx(oNodeA)+0.5; + }else iIdxA = iOffsetA; + + // container node B in common ancestor container + var oNodeB = oContainerB; + if(oNodeB != oCommonAncestor){ + while((oTmpNode = xe.DOMFix.parentNode(oNodeB)) != oCommonAncestor){oNodeB = oTmpNode;} + + iIdxB = this._getPosIdx(oNodeB)+0.5; + }else iIdxB = iOffsetB; + + return compareIdx(iIdxA, iIdxB); + }, + + _getCommonAncestorContainer : function(oNode1, oNode2){ + var oComparingNode = oNode2; + + while(oNode1){ + while(oComparingNode){ + if(oNode1 == oComparingNode) return oNode1; + oComparingNode = xe.DOMFix.parentNode(oComparingNode); + } + oComparingNode = oNode2; + oNode1 = xe.DOMFix.parentNode(oNode1); + } + + return this._document.body; + }, + + deleteContents : function(){ + if(this.collapsed) return; + + this._splitTextEndNodesOfTheRange(); + + var aNodes = this._getNodesInRange(); + + if(aNodes.length < 1) return; + + var oPrevNode = aNodes[0].previousSibling; + while(oPrevNode && this._isBlankTextNode(oPrevNode)) oPrevNode = oPrevNode.previousSibling; + + var oNewStartContainer, iNewOffset; + if(!oPrevNode){ + oNewStartContainer = xe.DOMFix.parentNode(aNodes[0]); + iNewOffset = 0; + } + + for(var i=0; i oNode.nodeValue.length) iOffset = oNode.nodeValue.length; + }else{ + if(iOffset > xe.DOMFix.childNodes(oNode).length) iOffset = xe.DOMFix.childNodes(oNode).length; + } + + return iOffset; + }, + + + setEnd : function(refNode, offset){ + offset = this._endsNodeValidation(refNode, offset); + + this.endContainer = refNode; + this.endOffset = offset; + if(!this.startContainer || this._compareEndPoint(this.startContainer, this.startOffset, this.endContainer, this.endOffset) != -1) this.collapse(false); + + this._updateRangeInfo(); + }, + + setEndAfter : function(refNode){ + if(!refNode) throw new Error("INVALID_NODE_TYPE_ERR in setEndAfter"); + + if(refNode.tagName == "BODY"){ + this.setEnd(refNode, xe.DOMFix.childNodes(refNode).length); + return; + } + this.setEnd(xe.DOMFix.parentNode(refNode), this._getPosIdx(refNode)+1); + }, + + setEndBefore : function(refNode){ + if(!refNode) throw new Error("INVALID_NODE_TYPE_ERR in setEndBefore"); + + if(refNode.tagName == "BODY"){ + this.setEnd(refNode, 0); + return; + } + + this.setEnd(xe.DOMFix.parentNode(refNode), this._getPosIdx(refNode)); + }, + + setStart : function(refNode, offset){ + offset = this._endsNodeValidation(refNode, offset); + + this.startContainer = refNode; + this.startOffset = offset; + + if(!this.endContainer || this._compareEndPoint(this.startContainer, this.startOffset, this.endContainer, this.endOffset) != -1) this.collapse(true); + this._updateRangeInfo(); + }, + + setStartAfter : function(refNode){ + if(!refNode) throw new Error("INVALID_NODE_TYPE_ERR in setStartAfter"); + + if(refNode.tagName == "BODY"){ + this.setStart(refNode, xe.DOMFix.childNodes(refNode).length); + return; + } + + this.setStart(xe.DOMFix.parentNode(refNode), this._getPosIdx(refNode)+1); + }, + + setStartBefore : function(refNode){ + if(!refNode) throw new Error("INVALID_NODE_TYPE_ERR in setStartBefore"); + + if(refNode.tagName == "BODY"){ + this.setStart(refNode, 0); + return; + } + this.setStart(xe.DOMFix.parentNode(refNode), this._getPosIdx(refNode)); + }, + + surroundContents : function(newParent){ + newParent.appendChild(this.extractContents()); + this.insertNode(newParent); + this.selectNode(newParent); + }, + + toString : function(){ + var oTmpContainer = this._document.createElement("DIV"); + oTmpContainer.appendChild(this.cloneContents()); + + return oTmpContainer.textContent || oTmpContainer.innerText || ""; + }, + + _isBlankTextNode : function(oNode){ + if(oNode.nodeType == 3 && oNode.nodeValue == "") return true; + return false; + }, + + _getPosIdx : function(refNode){ + var idx = 0; + for(var node = refNode.previousSibling; node; node = node.previousSibling) idx++; + + return idx; + }, + + _updateRangeInfo : function(){ + if(!this.startContainer){ + this.init(this._document); + return; + } + + this.collapsed = this._isCollapsed(this.startContainer, this.startOffset, this.endContainer, this.endOffset); + + this.commonAncestorContainer = this._getCommonAncestorContainer(this.startContainer, this.endContainer); + }, + + _isCollapsed : function(oStartContainer, iStartOffset, oEndContainer, iEndOffset){ + var bCollapsed = false; + + if(oStartContainer == oEndContainer && iStartOffset == iEndOffset){ + bCollapsed = true; + }else{ + var oActualStartNode = this._getActualStartNode(oStartContainer, iStartOffset); + var oActualEndNode = this._getActualEndNode(oEndContainer, iEndOffset); + + // Take the parent nodes on the same level for easier comparison when they're next to each other + // eg) From + // + // + // + // + // + // + // + // + // + // + // + // + // , it's easier to compare the position of B and D rather than C and F because they are siblings + // + // If the range were collapsed, oActualEndNode will precede oActualStartNode by doing this + oActualStartNode = this._getNextNode(this._getPrevNode(oActualStartNode)); + oActualEndNode = this._getPrevNode(this._getNextNode(oActualEndNode)); + + if(oActualStartNode && oActualEndNode && oActualEndNode.tagName != "BODY" && + (this._getNextNode(oActualEndNode) == oActualStartNode || (oActualEndNode == oActualStartNode && this._isBlankTextNode(oActualEndNode))) + ) + bCollapsed = true; + } + + return bCollapsed; + }, + + _splitTextEndNodesOfTheRange : function(){ + var oEndPoints = this._splitTextEndNodes({oStartContainer: this.startContainer, iStartOffset: this.startOffset, + oEndContainer: this.endContainer, iEndOffset: this.endOffset}); + + this.startContainer = oEndPoints.oStartContainer; + this.startOffset = oEndPoints.iStartOffset; + + this.endContainer = oEndPoints.oEndContainer; + this.endOffset = oEndPoints.iEndOffset; + }, + + _splitTextEndNodes : function(oEndPoints){ + oEndPoints = this._splitStartTextNode(oEndPoints); + oEndPoints = this._splitEndTextNode(oEndPoints); + + return oEndPoints; + }, + + _splitStartTextNode : function(oEndPoints){ + var oStartContainer = oEndPoints.oStartContainer; + var iStartOffset = oEndPoints.iStartOffset; + + var oEndContainer = oEndPoints.oEndContainer; + var iEndOffset = oEndPoints.iEndOffset; + + if(!oStartContainer) return oEndPoints; + if(oStartContainer.nodeType != 3) return oEndPoints; + if(iStartOffset == 0) return oEndPoints; + + if(oStartContainer.nodeValue.length <= iStartOffset) return oEndPoints; + + var oLastPart = oStartContainer.splitText(iStartOffset); + + if(oStartContainer == oEndContainer){ + iEndOffset -= iStartOffset; + oEndContainer = oLastPart; + } + oStartContainer = oLastPart; + iStartOffset = 0; + + return {oStartContainer: oStartContainer, iStartOffset: iStartOffset, oEndContainer: oEndContainer, iEndOffset: iEndOffset}; + }, + + _splitEndTextNode : function(oEndPoints){ + var oStartContainer = oEndPoints.oStartContainer; + var iStartOffset = oEndPoints.iStartOffset; + + var oEndContainer = oEndPoints.oEndContainer; + var iEndOffset = oEndPoints.iEndOffset; + + if(!oEndContainer) return oEndPoints; + if(oEndContainer.nodeType != 3) return oEndPoints; + + if(iEndOffset >= oEndContainer.nodeValue.length) return oEndPoints; + if(iEndOffset == 0) return oEndPoints; + + oEndContainer.splitText(iEndOffset); + + return {oStartContainer: oStartContainer, iStartOffset: iStartOffset, oEndContainer: oEndContainer, iEndOffset: iEndOffset}; + }, + + _getNodesInRange : function(){ + if(this.collapsed) return []; + + var oStartNode = this._getActualStartNode(this.startContainer, this.startOffset); + var oEndNode = this._getActualEndNode(this.endContainer, this.endOffset); + + return this._getNodesBetween(oStartNode, oEndNode); + }, + + _getActualStartNode : function(oStartContainer, iStartOffset){ + var oStartNode = oStartContainer;; + + if(oStartContainer.nodeType == 3){ + if(iStartOffset >= oStartContainer.nodeValue.length){ + oStartNode = this._getNextNode(oStartContainer); + if(oStartNode.tagName == "BODY") oStartNode = null; + }else{ + oStartNode = oStartContainer; + } + }else{ + if(iStartOffset < xe.DOMFix.childNodes(oStartContainer).length){ + oStartNode = xe.DOMFix.childNodes(oStartContainer)[iStartOffset]; + }else{ + oStartNode = this._getNextNode(oStartContainer); + if(oStartNode.tagName == "BODY") oStartNode = null; + } + } + + return oStartNode; + }, + + _getActualEndNode : function(oEndContainer, iEndOffset){ + var oEndNode = oEndContainer; + + if(iEndOffset == 0){ + oEndNode = this._getPrevNode(oEndContainer); + if(oEndNode.tagName == "BODY") oEndNode = null; + }else if(oEndContainer.nodeType == 3){ + oEndNode = oEndContainer; + }else{ + oEndNode = xe.DOMFix.childNodes(oEndContainer)[iEndOffset-1]; + } + + return oEndNode; + }, + + _getNextNode : function(oNode){ + if(!oNode || oNode.tagName == "BODY") return this._document.body; + + if(oNode.nextSibling) return oNode.nextSibling; + + return this._getNextNode(xe.DOMFix.parentNode(oNode)); + }, + + _getPrevNode : function(oNode){ + if(!oNode || oNode.tagName == "BODY") return this._document.body; + + if(oNode.previousSibling) return oNode.previousSibling; + + return this._getPrevNode(xe.DOMFix.parentNode(oNode)); + }, + + // includes partially selected + // for
, _getNodesBetween(b, c) will yield to b, "a" and c + _getNodesBetween : function(oStartNode, oEndNode){ + var aNodesBetween = []; + + if(!oStartNode || !oEndNode) return aNodesBetween; + + this._recurGetNextNodesUntil(oStartNode, oEndNode, aNodesBetween); + return aNodesBetween; + }, + + _recurGetNextNodesUntil : function(oNode, oEndNode, aNodesBetween){ + if(!oNode) return false; + + if(!this._recurGetChildNodesUntil(oNode, oEndNode, aNodesBetween)) return false; + + var oNextToChk = oNode.nextSibling; + + while(!oNextToChk){ + if(!xe.DOMFix.parentNode(oNode)) return false; + oNode = xe.DOMFix.parentNode(oNode); + + aNodesBetween[aNodesBetween.length] = oNode; + + if(oNode == oEndNode) return false; + + oNextToChk = oNode.nextSibling; + } + + return this._recurGetNextNodesUntil(oNextToChk, oEndNode, aNodesBetween); + }, + + _recurGetChildNodesUntil : function(oNode, oEndNode, aNodesBetween){ + if(!oNode) return false; + + var bEndFound = false; + var oCurNode = oNode; + if(oCurNode.firstChild){ + oCurNode = oCurNode.firstChild; + while(oCurNode){ + if(!this._recurGetChildNodesUntil(oCurNode, oEndNode, aNodesBetween)){ + bEndFound = true; + break; + } + oCurNode = oCurNode.nextSibling; + } + } + + aNodesBetween[aNodesBetween.length] = oNode; + + if(bEndFound) return false; + if(oNode == oEndNode) return false; + + return true; + } +}); + +xe.W3CDOMRange.START_TO_START = 0; +xe.W3CDOMRange.START_TO_END = 1; +xe.W3CDOMRange.END_TO_END = 2; +xe.W3CDOMRange.END_TO_START = 3; + + +/** + * @fileOverview This file contains a cross-browser function that implements all of the W3C's DOM Range specification and some more + * @name XpressRange.js + */ +xe.XpressRange = jQuery.Class({ + setWindow : function(win){ + this._window = win; + this._document = win.document; + }, + + $init : function(win){ + this.HUSKY_BOOMARK_START_ID_PREFIX = "xpress_bookmark_start_"; + this.HUSKY_BOOMARK_END_ID_PREFIX = "xpress_bookmark_end_"; + + this.sBlockElement = "P|DIV|LI|H[1-6]|PRE"; + this.sBlockContainer = "BODY|TABLE|TH|TR|TD|UL|OL|BLOCKQUOTE|FORM"; + + this.rxBlockElement = new RegExp("^("+this.sBlockElement+")$"); + this.rxBlockContainer = new RegExp("^("+this.sBlockContainer+")$") + this.rxLineBreaker = new RegExp("^("+this.sBlockElement+"|"+this.sBlockContainer+")$") + + this.setWindow(win); + + this.oSimpleSelection = new xe.SimpleSelection(this._window); + this.selectionLoaded = this.oSimpleSelection.selectionLoaded; + + this.$super.$init(this._document); + }, + + select : function(){ + this.oSimpleSelection.selectRange(this); + }, + + setFromSelection : function(iNum){ + this.setRange(this.oSimpleSelection.getRangeAt(iNum)); + }, + + setRange : function(oW3CRange){ + this.setStart(oW3CRange.startContainer, oW3CRange.startOffset); + this.setEnd(oW3CRange.endContainer, oW3CRange.endOffset); + }, + + setEndNodes : function(oSNode, oENode){ + this.setEndAfter(oENode); + this.setStartBefore(oSNode); + }, + + splitTextAtBothEnds : function(){ + this._splitTextEndNodesOfTheRange(); + }, + + getStartNode : function(){ + if(this.collapsed){ + if(this.startContainer.nodeType == 3){ + if(this.startOffset == 0) return null; + if(this.startContainer.nodeValue.length <= this.startOffset) return null; + return this.startContainer; + } + return null; + } + + if(this.startContainer.nodeType == 3){ + if(this.startOffset >= this.startContainer.nodeValue.length) return this._getNextNode(this.startContainer); + return this.startContainer; + }else{ + if(this.startOffset >= xe.DOMFix.childNodes(this.startContainer).length) return this._getNextNode(this.startContainer); + return xe.DOMFix.childNodes(this.startContainer)[this.startOffset]; + } + }, + + getEndNode : function(){ + if(this.collapsed) return this.getStartNode(); + + if(this.endContainer.nodeType == 3){ + if(this.endOffset == 0) return this._getPrevNode(this.endContainer); + return this.endContainer; + }else{ + if(this.endOffset == 0) return this._getPrevNode(this.endContainer); + return xe.DOMFix.childNodes(this.endContainer)[this.endOffset-1]; + } + }, + + getNodeAroundRange : function(bBefore, bStrict){ + if(this.collapsed && this.startContainer && this.startContainer.nodeType == 3) return this.startContainer; + if(!this.collapsed || (this.startContainer && this.startContainer.nodeType == 3)) return this.getStartNode(); + + var oBeforeRange, oAfterRange, oResult; + + if(this.startOffset >= xe.DOMFix.childNodes(this.startContainer).length) + oAfterRange = this._getNextNode(this.startContainer); + else + oAfterRange = xe.DOMFix.childNodes(this.startContainer)[this.startOffset]; + + if(this.endOffset == 0) + oBeforeRange = this._getPrevNode(this.endContainer); + else + oBeforeRange = xe.DOMFix.childNodes(this.endContainer)[this.endOffset-1]; + + if(bBefore){ + oResult = oBeforeRange; + if(!oResult && !bStrict) oResult = oAfterRange; + }else{ + oResult = oAfterRange; + if(!oResult && !bStrict) oResult = oBeforeRange; + } + + return oResult; + }, + + _getXPath : function(elNode){ + var sXPath = ""; + + while(elNode && elNode.nodeType == 1){ + sXPath = "/" + elNode.tagName+"["+this._getPosIdx4XPath(elNode)+"]" + sXPath; + elNode = xe.DOMFix.parentNode(elNode); + } + + return sXPath; + }, + + _getPosIdx4XPath : function(refNode){ + var idx = 0; + for(var node = refNode.previousSibling; node; node = node.previousSibling) + if(node.tagName == refNode.tagName) idx++; + + return idx; + }, + + // this was written specifically for XPath Bookmark and it may not perform correctly for general purposes + _evaluateXPath : function(sXPath, oDoc){ + sXPath = sXPath.substring(1, sXPath.length-1); + var aXPath = sXPath.split(/\//); + var elNode = oDoc.body; + + for(var i=2; i -1 && elContainer){ + var aChildNodes = xe.DOMFix.childNodes(elContainer); + var elNode = null; + + var nIdx = nTextNodeIdx; + var nOffsetLeft = nOffset; + + while((elNode = aChildNodes[nIdx]) && elNode.nodeType == 3 && elNode.nodeValue.length < nOffsetLeft){ + nOffsetLeft -= elNode.nodeValue.length; + nIdx++; + } + + elContainer = xe.DOMFix.childNodes(elContainer)[nIdx]; + nOffset = nOffsetLeft; + } + + if(!elContainer){ + elContainer = this._document.body; + nOffset = 0; + } + return {elContainer: elContainer, nOffset: nOffset}; + }, + + // this was written specifically for XPath Bookmark and it may not perform correctly for general purposes + getXPathBookmark : function(){ + var nTextNodeIdx1 = -1; + var htEndPt1 = {elContainer: this.startContainer, nOffset: this.startOffset}; + var elNode1 = this.startContainer; + if(elNode1.nodeType == 3){ + htEndPt1 = this._getFixedStartTextNode(); + nTextNodeIdx1 = this._getPosIdx(htEndPt1.elContainer); + elNode1 = xe.DOMFix.parentNode(elNode1); + } + var sXPathNode1 = this._getXPath(elNode1); + var oBookmark1 = {sXPath:sXPathNode1, nTextNodeIdx:nTextNodeIdx1, nOffset: htEndPt1.nOffset}; + + var nTextNodeIdx2 = -1; + var htEndPt2 = {elContainer: this.endContainer, nOffset: this.endOffset}; + var elNode2 = this.endContainer; + if(elNode2.nodeType == 3){ + htEndPt2 = this._getFixedEndTextNode(); + nTextNodeIdx2 = this._getPosIdx(htEndPt2.elContainer); + elNode2 = xe.DOMFix.parentNode(elNode2); + } + var sXPathNode2 = this._getXPath(elNode2); + var oBookmark2 = {sXPath:sXPathNode2, nTextNodeIdx:nTextNodeIdx2, nOffset: htEndPt2.nOffset}; + + return [oBookmark1, oBookmark2]; + }, + + moveToXPathBookmark : function(aBookmark){ + if(!aBookmark) return; + + var oBookmarkInfo1 = this._evaluateXPathBookmark(aBookmark[0]); + var oBookmarkInfo2 = this._evaluateXPathBookmark(aBookmark[1]); + + if(!oBookmarkInfo1["elContainer"] || !oBookmarkInfo2["elContainer"]) return; + + this.startContainer = oBookmarkInfo1["elContainer"]; + this.startOffset = oBookmarkInfo1["nOffset"]; + + this.endContainer = oBookmarkInfo2["elContainer"]; + this.endOffset = oBookmarkInfo2["nOffset"]; + }, + + _getFixedTextContainer : function(elNode, nOffset){ + while(elNode && elNode.nodeType == 3 && elNode.previousSibling && elNode.previousSibling.nodeType == 3){ + nOffset += elNode.previousSibling.nodeValue.length; + elNode = elNode.previousSibling; + } + + return {elContainer:elNode, nOffset:nOffset}; + }, + + _getFixedStartTextNode : function(){ + return this._getFixedTextContainer(this.startContainer, this.startOffset); + }, + + _getFixedEndTextNode : function(){ + return this._getFixedTextContainer(this.endContainer, this.endOffset); + }, + + placeStringBookmark : function(){ + var sTmpId = (new Date()).getTime(); + + var oInsertionPoint = this.cloneRange(); + oInsertionPoint.collapseToEnd(); + var oEndMarker = this._document.createElement("A"); + oEndMarker.id = this.HUSKY_BOOMARK_END_ID_PREFIX+sTmpId; + oInsertionPoint.insertNode(oEndMarker); + + var oInsertionPoint = this.cloneRange(); + oInsertionPoint.collapseToStart(); + var oStartMarker = this._document.createElement("A"); + oStartMarker.id = this.HUSKY_BOOMARK_START_ID_PREFIX+sTmpId; + oInsertionPoint.insertNode(oStartMarker); + + this.moveToBookmark(sTmpId); + + return sTmpId; + }, + + cloneRange : function(){ + return this._copyRange(new xe.XpressRange(this._window)); + }, + + moveToBookmark : function(vBookmark){ + if(typeof(vBookmark) != "object") + this.moveToStringBookmark(vBookmark); + else + this.moveToXPathBookmark(vBookmark); + }, + + moveToStringBookmark : function(sBookmarkID){ + var oStartMarker = this._document.getElementById(this.HUSKY_BOOMARK_START_ID_PREFIX+sBookmarkID); + var oEndMarker = this._document.getElementById(this.HUSKY_BOOMARK_END_ID_PREFIX+sBookmarkID); + + if(!oStartMarker || !oEndMarker) return; + + this.setEndBefore(oEndMarker); + this.setStartAfter(oStartMarker); + }, + + removeStringBookmark : function(sBookmarkID){ + var oStartMarker = this._document.getElementById(this.HUSKY_BOOMARK_START_ID_PREFIX+sBookmarkID); + var oEndMarker = this._document.getElementById(this.HUSKY_BOOMARK_END_ID_PREFIX+sBookmarkID); + + if(oStartMarker) xe.DOMFix.parentNode(oStartMarker).removeChild(oStartMarker); + if(oEndMarker) xe.DOMFix.parentNode(oEndMarker).removeChild(oEndMarker); + }, + + collapseToStart : function(){ + this.collapse(true); + }, + + collapseToEnd : function(){ + this.collapse(false); + }, + + createAndInsertNode : function(sTagName){ + tmpNode = this._document.createElement(tagName); + this.insertNode(tmpNode) + return tmpNode + }, + + getNodes : function(bSplitTextEndNodes, fnFilter){ + if(bSplitTextEndNodes) this._splitTextEndNodesOfTheRange(); + + var aAllNodes = this._getNodesInRange(); + var aFilteredNodes = []; + + if(!fnFilter) return aAllNodes; + + for(var i=0; i= 0) return true; + + if(bIncludePartlyIncluded){ + if(startToEnd == 1) return false; + if(endToStart == -1) return false; + return true; + } + + return false; + }, + + isNodeInRange : function(oNode, bIncludePartlySelected, bContentOnly){ + var oTmpRange = new xe.XpressRange(this._window); + + if(bContentOnly && oNode.firstChild){ + oTmpRange.setStartBefore(oNode.firstChild); + oTmpRange.setEndAfter(oNode.lastChild); + }else{ + oTmpRange.selectNode(oNode); + } + + return isRangeInRange(oTmpRange, bIncludePartlySelected); + }, + + pasteHTML : function(sHTML){ + if(sHTML == ""){ + this.deleteContents(); + return; + } + + var oTmpDiv = this._document.createElement("DIV"); + oTmpDiv.innerHTML = sHTML; + + var oFirstNode = oTmpDiv.firstChild; + var oLastNode = oTmpDiv.lastChild; + + var clone = this.cloneRange(); + var sBM = clone.placeStringBookmark(); + + while(oTmpDiv.lastChild) this.insertNode(oTmpDiv.lastChild); + + this.setEndNodes(oFirstNode, oLastNode); + + // delete the content later as deleting it first may mass up the insertion point + // eg)

[A]BCD

---paste O---> O

BCD

+ clone.moveToBookmark(sBM); + clone.deleteContents(); + clone.removeStringBookmark(sBM); + }, + + toString : function(){ + this.toString = xe.W3CDOMRange.prototype.toString; + return this.toString(); + }, + + toHTMLString : function(){ + var oTmpContainer = this._document.createElement("DIV"); + oTmpContainer.appendChild(this.cloneContents()); + + return oTmpContainer.innerHTML; + }, + + findAncestorByTagName : function(sTagName){ + var oNode = this.commonAncestorContainer; + while(oNode && oNode.tagName != sTagName) oNode = xe.DOMFix.parentNode(oNode); + + return oNode; + }, + + selectNodeContents : function(oNode){ + if(!oNode) return; + + var oFirstNode = oNode.firstChild?oNode.firstChild:oNode; + var oLastNode = oNode.lastChild?oNode.lastChild:oNode; + + if(oFirstNode.nodeType == 3) + this.setStart(oFirstNode, 0); + else + this.setStartBefore(oFirstNode); + + if(oLastNode.nodeType == 3) + this.setEnd(oLastNode, oLastNode.nodeValue.length); + else + this.setEndAfter(oLastNode); + }, + + styleRange : function(oStyle, oAttribute, sNewSpanMarker){ + var aStyleParents = this._getStyleParentNodes(sNewSpanMarker); + if(aStyleParents.length < 1) return; + + var sName, sValue; + + for(var i=0; i= 0)){ + oSNode = this.getNodeAroundRange(false, true); + oENode = this.getNodeAroundRange(false, true); + oStart = this._getLineStartInfo(oSNode); + oEnd = this._getLineEndInfo(oENode); + } + + return {oStart: oStart, oEnd: oEnd}; + } +}).extend(xe.W3CDOMRange); + +/** + * @fileOverview This file contains cross-browser selection function + * @name SimpleSelection.js + */ +xe.SimpleSelection = function(win){ + this.init = function(win){ + this._window = win || window; + this._document = this._window.document; + }; + + this.init(win); + + if(jQuery.browser.msie) + xe.SimpleSelectionImpl_IE.apply(this); + else + xe.SimpleSelectionImpl_FF.apply(this); + + this.selectRange = function(oRng){ + this.selectNone(); + this.addRange(oRng); + }; + + this.selectionLoaded = true; + if(!this._oSelection) this.selectionLoaded = false; +}; + +xe.SimpleSelectionImpl_FF = function(){ + this._oSelection = this._window.getSelection(); + + this.getRangeAt = function(iNum){ + iNum = iNum || 0; + + try{ + var oFFRange = this._oSelection.getRangeAt(iNum); + }catch(e){return new xe.W3CDOMRange(this._document);} + + return this._FFRange2W3CRange(oFFRange); + }; + + this.addRange = function(oW3CRange){ + var oFFRange = this._W3CRange2FFRange(oW3CRange); + this._oSelection.addRange(oFFRange); + }; + + this.selectNone = function(){ + this._oSelection.removeAllRanges(); + }; + + this._FFRange2W3CRange = function(oFFRange){ + var oW3CRange = new xe.W3CDOMRange(this._document); + oW3CRange.setStart(oFFRange.startContainer, oFFRange.startOffset); + oW3CRange.setEnd(oFFRange.endContainer, oFFRange.endOffset); + return oW3CRange; + }; + + this._W3CRange2FFRange = function(oW3CRange){ + var oFFRange = this._document.createRange(); + oFFRange.setStart(oW3CRange.startContainer, oW3CRange.startOffset); + oFFRange.setEnd(oW3CRange.endContainer, oW3CRange.endOffset); + + return oFFRange; + }; +}; + +xe.SimpleSelectionImpl_IE = function(){ + this._oSelection = this._document.selection; + + this.getRangeAt = function(iNum){ + iNum = iNum || 0; + + if(this._oSelection.type == "Control"){ + var oW3CRange = new xe.W3CDOMRange(this._document); + + var oSelectedNode = this._oSelection.createRange().item(iNum); + + // if the selction occurs in a different document, ignore + if(!oSelectedNode || oSelectedNode.ownerDocument != this._document) return oW3CRange; + + oW3CRange.selectNode(oSelectedNode); + + return oW3CRange; + }else{ + var oSelectedNode = this._oSelection.createRangeCollection().item(iNum).parentElement(); + + // if the selction occurs in a different document, ignore + if(!oSelectedNode || oSelectedNode.ownerDocument != this._document){ + var oW3CRange = new xe.W3CDOMRange(this._document); + return oW3CRange; + } + return this._IERange2W3CRange(this._oSelection.createRangeCollection().item(iNum)); + } + }; + + this.addRange = function(oW3CRange){ + var oIERange = this._W3CRange2IERange(oW3CRange); + oIERange.select(); + }; + + this.selectNone = function(){ + this._oSelection.empty(); + }; + + this._W3CRange2IERange = function(oW3CRange){ + var oStartIERange = this._getIERangeAt(oW3CRange.startContainer, oW3CRange.startOffset); + var oEndIERange = this._getIERangeAt(oW3CRange.endContainer, oW3CRange.endOffset); + oStartIERange.setEndPoint("EndToEnd", oEndIERange); + + return oStartIERange; + }; + + this._getIERangeAt = function(oW3CContainer, iW3COffset){ + var oIERange = this._document.body.createTextRange(); + + var oEndPointInfoForIERange = this._getSelectableNodeAndOffsetForIE(oW3CContainer, iW3COffset); + + var oSelectableNode = oEndPointInfoForIERange.oSelectableNodeForIE; + var iIEOffset = oEndPointInfoForIERange.iOffsetForIE; + + oIERange.moveToElementText(oSelectableNode); + oIERange.collapse(oEndPointInfoForIERange.bCollapseToStart); + oIERange.moveStart("character", iIEOffset); + + return oIERange; + }; + + this._getSelectableNodeAndOffsetForIE = function(oW3CContainer, iW3COffset){ + var oIERange = this._document.body.createTextRange(); + + var oNonTextNode = null; + var aChildNodes = null; + var iNumOfLeftNodesToCount = 0; + + if(oW3CContainer.nodeType == 3){ + oNonTextNode = xe.DOMFix.parentNode(oW3CContainer); + aChildNodes = xe.DOMFix.childNodes(oNonTextNode); + iNumOfLeftNodesToCount = aChildNodes.length; + }else{ + oNonTextNode = oW3CContainer; + aChildNodes = xe.DOMFix.childNodes(oNonTextNode); + iNumOfLeftNodesToCount = iW3COffset; + } + + var oNodeTester = null; + + var iResultOffset = 0; + + var bCollapseToStart = true; + + for(var i=0; i=0) break; + + oPrevNonTextNode = aChildNodes[i]; + } + + var pointRangeIdx = i; + + if(pointRangeIdx != 0 && aChildNodes[pointRangeIdx-1].nodeType == 3){ + var oRgTextStart = this._document.body.createTextRange(); + var oCurTextNode = null; + if(oPrevNonTextNode){ + oRgTextStart.moveToElementText(oPrevNonTextNode); + oRgTextStart.collapse(false); + oCurTextNode = oPrevNonTextNode.nextSibling; + }else{ + oRgTextStart.moveToElementText(oContainer); + oRgTextStart.collapse(true); + oCurTextNode = oContainer.firstChild; + } + + var oRgTextsUpToThePoint = oRgOrigPoint.duplicate(); + oRgTextsUpToThePoint.setEndPoint("StartToStart", oRgTextStart); + + var textCount = oRgTextsUpToThePoint.text.length + + while(textCount > oCurTextNode.nodeValue.length && oCurTextNode.nextSibling){ + textCount -= oCurTextNode.nodeValue.length; + oCurTextNode = oCurTextNode.nextSibling; + } + + // this will enforce IE to re-reference oCurTextNode + var oTmp = oCurTextNode.nodeValue; + + if(bStartPt && oCurTextNode.nextSibling && oCurTextNode.nextSibling.nodeType == 3 && textCount == oCurTextNode.nodeValue.length){ + textCount -= oCurTextNode.nodeValue.length; + oCurTextNode = oCurTextNode.nextSibling; + } + + oContainer = oCurTextNode; + offset = textCount; + }else{ + oContainer = oRgOrigPoint.parentElement(); + offset = pointRangeIdx; + } + + return {"oContainer" : oContainer, "iOffset" : offset}; + }; +} + +xe.DOMFix = new (jQuery.Class({ + $init : function(){ + if(jQuery.browser.msie || jQuery.browser.opera){ + this.childNodes = this._childNodes_Fix; + this.parentNode = this._parentNode_Fix; + }else{ + this.childNodes = this._childNodes_Native; + this.parentNode = this._parentNode_Native; + } + }, + + _parentNode_Native : function(elNode){ + return elNode.parentNode; + }, + + _parentNode_Fix : function(elNode){ + if(!elNode) return elNode; + + while(elNode.previousSibling){elNode = elNode.previousSibling;} + + return elNode.parentNode; + }, + + _childNodes_Native : function(elNode){ + return elNode.childNodes; + }, + + _childNodes_Fix : function(elNode){ + var aResult = null; + var nCount = 0; + + if(elNode){ + var aResult = []; + elNode = elNode.firstChild; + while(elNode){ + aResult[nCount++] = elNode; + elNode=elNode.nextSibling; + } + } + + return aResult; + } +}))(); +/** + * @fileOverview This file contains a function that takes care of various operations related to find and replace + * @name N_FindReplace.js + */ +xe.FindReplace = jQuery.Class({ + sKeyword : "", + window : null, + document : null, + bBrowserSupported : false, + + // true if End Of Contents is reached during last execution of find + bEOC : false, + + $init : function(win){ + this.window = win; + this.document = this.window.document; + + if(this.document.domain != this.document.location.hostname){ + if(jQuery.browser.mozilla && jQuery.browser.nVersion < 3){ + this.bBrowserSupported = false; + this.find = function(){return 3}; + return; + } + } + + this.bBrowserSupported = true; + }, + + // 0: found + // 1: not found + // 2: keyword required + // 3: browser not supported + find : function(sKeyword, bCaseMatch, bBackwards, bWholeWord){ + var bSearchResult, bFreshSearch; + + this.window.focus(); + + if(!sKeyword) return 2; + + // try find starting from current cursor position + this.bEOC = false; + bSearchResult = this.findNext(sKeyword, bCaseMatch, bBackwards, bWholeWord); + if(bSearchResult) return 0; + + // end of the contents could have been reached so search again from the beginning + this.bEOC = true; + bSearchResult = this.findNew(sKeyword, bCaseMatch, bBackwards, bWholeWord); + + if(bSearchResult) return 0; + + return 1; + }, + + findNew : function (sKeyword, bCaseMatch, bBackwards, bWholeWord){ + this.findReset(); + return this.findNext(sKeyword, bCaseMatch, bBackwards, bWholeWord); + }, + + findNext : function(sKeyword, bCaseMatch, bBackwards, bWholeWord){ + var bSearchResult; + bCaseMatch = bCaseMatch || false; + bWholeWord = bWholeWord || false; + bBackwards = bBackwards || false; + + if(this.window.find){ + var bWrapAround = false; + return this.window.find(sKeyword, bCaseMatch, bBackwards, bWrapAround, bWholeWord); + } + + // IE solution + if(this.document.body.createTextRange){ + var iOption = 0; + if(bBackwards) iOption += 1; + if(bWholeWord) iOption += 2; + if(bCaseMatch) iOption += 4; + + this.window.focus(); + this._range = this.document.selection.createRangeCollection().item(0); + this._range.collapse(false); + bSearchResult = this._range.findText(sKeyword, 1, iOption); + + this._range.select(); + return bSearchResult; + } + + return false; + }, + + findReset : function() { + if (this.window.find){ + this.window.getSelection().removeAllRanges(); + return; + } + + // IE solution + if(this.document.body.createTextRange){ + this._range = this.document.body.createTextRange(); + this._range.collapse(true); + this._range.select(); + } + }, + + // 0: replaced & next word found + // 1: replaced & next word not found + // 2: not replaced & next word found + // 3: not replaced & next word not found + // 4: sOriginalWord required + replace : function(sOriginalWord, Replacement, bCaseMatch, bBackwards, bWholeWord){ + if(!sOriginalWord) return 4; + + var oSelection = new xe.XpressRange(this.window); + oSelection.setFromSelection(); + + bCaseMatch = bCaseMatch || false; + var bMatch, selectedText = oSelection.toString(); + if(bCaseMatch) + bMatch = (selectedText == sOriginalWord); + else + bMatch = (selectedText.toLowerCase() == sOriginalWord.toLowerCase()); + + if(!bMatch) + return this.find(sOriginalWord, bCaseMatch, bBackwards, bWholeWord)+2; + + if(typeof Replacement == "function"){ + // the returned oSelection must contain the replacement + oSelection = Replacement(oSelection); + }else{ + oSelection.pasteHTML(Replacement); + } + + // force it to find the NEXT occurance of sOriginalWord + oSelection.select(); + + return this.find(sOriginalWord, bCaseMatch, bBackwards, bWholeWord); + }, + + // returns number of replaced words + // -1 : if original word is not given + replaceAll : function(sOriginalWord, Replacement, bCaseMatch, bWholeWord){ + if(!sOriginalWord) return -1; + + var bBackwards = false; + + var iReplaceResult; + var iResult = 0; + var win = this.window; + var oSelection = new xe.XpressRange(this.window); + oSelection.setFromSelection(); + var sBookmark = oSelection.placeStringBookmark(); + + this.bEOC = false; + while(!this.bEOC){ + iReplaceResult = this.replace(sOriginalWord, Replacement, bCaseMatch, bBackwards, bWholeWord); + if(iReplaceResult == 0 || iReplaceResult == 1) iResult++; + } + + var startingPointReached = function(){ + var oCurSelection = new xe.XpressRange(win); + oCurSelection.setFromSelection(); + + oSelection.moveToBookmark(sBookmark); + var pos = oSelection.compareBoundaryPoints(xe.W3CDOMRange.START_TO_END, oCurSelection); + + if(pos == 1) return false; + return true; + } + + iReplaceResult = 0; + this.bEOC = false; + while(!startingPointReached() && iReplaceResult == 0 && !this.bEOC){ + iReplaceResult = this.replace(sOriginalWord, Replacement, bCaseMatch, bBackwards, bWholeWord); + if(iReplaceResult == 0 || iReplaceResult == 1) iResult++; + } + + oSelection.moveToBookmark(sBookmark); + oSelection.select(); + oSelection.removeStringBookmark(sBookmark); + + return iResult; + } +}); + +/** + * @fileOverview This file contains a function that takes care of the draggable layers + * @name N_DraggableLayer.js + */ +xe.DraggableLayer = jQuery.Class({ + $init : function(oLayer, oOptions){ + this.oOptions = jQuery.extend({ + bModal : "false", + oHandle : oLayer, + iMinX : -999999, + iMinY : -999999, + iMaxX : 999999, + iMaxY : 999999 + }, oOptions); + + this.oHandle = this.oOptions.oHandle; + + oLayer.style.display = "block"; + oLayer.style.position = "absolute"; + oLayer.style.zIndex = "9999"; + + this.aBasePosition = this.getBaseOffset(oLayer); + + // "number-ize" the position and set it as inline style. (the position could've been set as "auto" or set by css, not inline style) + oLayer.style.top = (this.toInt(jQuery(oLayer).offset().top) - this.aBasePosition.top)+"px"; + oLayer.style.left = (this.toInt(jQuery(oLayer).offset().left) - this.aBasePosition.left)+"px"; + + this.$FnMouseDown = jQuery.fnBind(this._mousedown, this, oLayer); + this.$FnMouseMove = jQuery.fnBind(this._mousemove, this, oLayer); + this.$FnMouseUp = jQuery.fnBind(this._mouseup, this, oLayer); + + jQuery(this.oHandle).bind("mousedown", this.$FnMouseDown); + }, + + _mousedown : function(oLayer, oEvent){ + if(oEvent.target.tagName == "INPUT") return; + + this.MouseOffsetY = (oEvent.pageY-this.toInt(oLayer.style.top)-this.aBasePosition['top']); + this.MouseOffsetX = (oEvent.pageX-this.toInt(oLayer.style.left)-this.aBasePosition['left']); + + jQuery(oLayer).bind("mousemove", this.$FnMouseMove); + jQuery(oLayer).bind("mouseup", this.$FnMouseUp); + }, + + _mousemove : function(oLayer, oEvent){ + var iTop = (oEvent.pageY-this.MouseOffsetY-this.aBasePosition['top']); + var iLeft = (oEvent.pageX-this.MouseOffsetX-this.aBasePosition['left']); + + if(iTopthis.oOptions.iMaxY) iTop = this.oOptions.iMaxY; + + if(iLeftthis.oOptions.iMaxX) iLeft = this.oOptions.iMaxX; + + oLayer.style.top = iTop + "px"; + oLayer.style.left = iLeft + "px"; + }, + + _mouseup : function(oLayer, oEvent){ + jQuery(oLayer).unbind("mousemove", this.$FnMouseMove); + jQuery(oLayer).unbind("mouseup", this.$FnMouseUp); + }, + + toInt : function(num){ + var result = parseInt(num); + return result || 0; + }, + + findNonStatic : function(oEl){ + if(!oEl) return null; + if(oEl.tagName == "BODY") return oEl; + + if(jQuery(oEl).css("position").match(/absolute|relative/i)) return oEl; + + return this.findNonStatic(oEl.offsetParent); + }, + + getBaseOffset : function(oEl){ + var oBase = this.findNonStatic(oEl.offsetParent); + var tmp = jQuery(oBase).offset(); + + return {top: tmp.top, left: tmp.left}; + } +}); +//{ +/** + * @fileOverview This file contains Xpress plugin that takes care of the messages related to core operations + * @name hp_CorePlugin.js + */ +xe.CorePlugin = jQuery.Class({ + name : "CorePlugin", + + $init : function(funcOnReady){ + this.funcOnReady = funcOnReady; + }, + + $AFTER_MSG_APP_READY : function(){ + this.oApp.exec("EXEC_ON_READY_FUNCTION", []); + }, + + $ON_ADD_APP_PROPERTY : function(sPropertyName, oProperty){ + this.oApp[sPropertyName] = oProperty; + }, + + $ON_REGISTER_BROWSER_EVENT : function(obj, sEvent, sCMD, aParams, nDelay){ + this.oApp.registerBrowserEvent(obj, sEvent, sCMD, aParams, nDelay); + }, + + $ON_DISABLE_COMMAND : function(sCommand){ + this.oApp.disableCommand(sCommand, true); + }, + + $ON_ENABLE_COMMAND : function(sCommand){ + this.oApp.disableCommand(sCommand, false); + }, + + $ON_EXEC_ON_READY_FUNCTION : function(){ + if(typeof this.funcOnReady == "function") this.funcOnReady(); + } +}); +//} +//{ +/** + * @fileOverview This file contains Xpress plugin that helps various operations. + * @name hp_Utils.js + */ + xe.Utils = jQuery.Class({ + name : "Utils", + + $init : function(){ + if(jQuery.browser.msie && jQuery.browser.nVersion == 6){ + try{ + document.execCommand('BackgroundImageCache', false, true); + }catch(e){} + } + }, + + $ON_ATTACH_HOVER_EVENTS : function(aElms, sHoverClass){ + sHoverClass = sHoverClass || "hover"; + + if(!aElms) return; + + jQuery(aElms).hover( + function(){jQuery(this).addClass(sHoverClass)}, + function(){jQuery(this).removeClass(sHoverClass)} + ); + } +}); +//} + +//{ +/** + * @fileOverview This file contains Xpress plugin that bridges the XpressRange function + * @name hp_XpressRangeManager.js + */ +xe.XpressRangeManager = jQuery.Class({ + name : "XpressRangeManager", + + oWindow : null, + + $init : function(win){ + this.oWindow = win || window; + }, + + $BEFORE_MSG_APP_READY : function(){ + if(this.oWindow && this.oWindow.tagName == "IFRAME") + this.oWindow = this.oWindow.contentWindow; + + this.oApp.exec("ADD_APP_PROPERTY", ["getSelection", jQuery.fnBind(this.getSelection, this)]); + this.oApp.exec("ADD_APP_PROPERTY", ["getEmptySelection", jQuery.fnBind(this.getEmptySelection, this)]); + }, + + $ON_SET_EDITING_WINDOW : function(oWindow){ + this.oWindow = oWindow; + }, + + getEmptySelection : function(){ + var oXpressRange = new xe.XpressRange(this.oWindow); + return oXpressRange; + }, + + getSelection : function(){ + this.oApp.exec("RESTORE_IE_SELECTION", []); + + var oXpressRange = this.getEmptySelection(); + + // this may throw an exception if the selected is area is not yet shown + try{ + oXpressRange.setFromSelection(); + }catch(e){} + + return oXpressRange; + } +}); +//} +xe.Hotkey = jQuery.Class({ + name : "Hotkey", + + storage : {}, + keyhash : {}, + + $init : function(){ + this.storage = {}; + + this.keyhash = { + backspace : 8, + tab : 9, + enter : 13, + shift : 16, + ctrl : 17, + alt : 18, + meta : 224, + esc : 27, + space : 32, + pageup : 33, + pagedown : 34, + end : 35, + home : 36, + left : 37, + up : 38, + right : 39, + down : 40, + del : 46, + comma : 188,//(,) + period : 190,//(.) + slash : 191,//(/) + hyphen : 109, + equal : 61 + }; + + if (jQuery.browser.msie || jQuery.browser.safari) { + this.keyhash.hyphen = 189; // (-) + this.keyhash.equal = 187; // (=) + this.keyhash.meta = 91; // meta + } + + + }, + + $ON_MSG_APP_READY : function(){ + jQuery(this.oApp.getWYSIWYGDocument() || document).keydown(jQuery.fnBind(this.keydown, this)); + }, + + $ON_REGISTER_HOTKEY : function(sHotkey, sCMD, sArgs){ + if(!sArgs) sArgs = []; + var func = jQuery.fnBind(this.oApp.exec, this.oApp, sCMD, sArgs); + + sHotkey = this.normalize(sHotkey); + if (!sHotkey) return false; + + this.add(sHotkey, func); + }, + + add : function(sHotkey, func) { + if (typeof this.storage[sHotkey] == 'undefined') { + this.storage[sHotkey] = [func]; + } else { + this.storage[sHotkey].push(func); + } + }, + + keydown : function(event) { + var key = [], kh = this.keyhash; + + if (jQuery.inArray(event.keyCode, [kh.shift, kh.ctrl, kh.alt, kh.meta]) >= 0) return; + + if (event.shiftKey) key.push('shift'); + if (event.altKey) key.push('alt'); + if (event.ctrlKey) key.push('ctrl'); + if (event.metaKey) key.push('meta'); + if (!key.length) return; + if (key.length == 1 && event.metaKey) key = ['ctrl', 'meta']; + + key.push(event.keyCode); + + key = key.join('+'); + + if (!this.storage[key]) return; + + jQuery.each(this.storage[key], function(){ this(); }); + + return false; + }, + + normalize : function(sHotkey) { + var shift, ctrl, alt, meta, key, keys = (sHotkey||"").toLowerCase().split('+'); + + shift = ctrl = alt = meta = key = false; + + jQuery.each(keys, function(){ + var s = ""+this; + switch(s) { + case 'shift': shift = true; + case 'alt' : alt = true; + case 'ctrl' : ctrl = true; + case 'meta' : meta = true; + default: + key = s; + } + }); + + if (!key) return ''; + + keys = []; + if (shift) keys.push('shift'); + if (alt) keys.push('alt'); + if (ctrl) keys.push('ctrl'); + if (meta || (ctrl && !shift && !alt)) keys.push('meta'); + + keys.push(this.keyhash[key] || key.toUpperCase().charCodeAt(0)); + + return keys.join('+'); + } +}); + +//{ +/** + * @fileOverview This file contains Xpress plugin that takes care of the draggable layers + * @name hp_DialogLayerManager.js + */ +xe.DialogLayerManager = jQuery.Class({ + name : "DialogLayerManager", + aMadeDraggable : null, + aOpenedLayers : null, + + $init : function(){ + this.aMadeDraggable = []; + this.aOpenedLayers = []; + }, + + $ON_SHOW_DIALOG_LAYER : function(oLayer, bModal){ + oLayer = jQuery.$(oLayer); + bModal = jQuery.$(bModal) || false; + if(!oLayer) return; + + if(jQuery.inArray(oLayer, this.aOpenedLayers)) return; + + this.oApp.exec("POSITION_DIALOG_LAYER", [oLayer]); + + this.aOpenedLayers[this.aOpenedLayers.length] = oLayer; + + if(!jQuery.inArray(oLayer, this.aMadeDraggable)){ + new xe.DraggableLayer(oLayer, {bModal: bModal, iMinY: 0}); + this.aMadeDraggable[this.aMadeDraggable.length] = oLayer; + }else{ + oLayer.style.display = "block"; + } + }, + + $ON_HIDE_LAST_DIALOG_LAYER : function(){ + this.oApp.exec("HIDE_DIALOG_LAYER", [this.aOpenedLayers[this.aOpenedLayers.length-1]]); + }, + + $ON_HIDE_ALL_DIALOG_LAYER : function(){ + for(var i=this.aOpenedLayers.length-1; i>=0; i--) + this.oApp.exec("HIDE_DIALOG_LAYER", [this.aOpenedLayers[i]]); + }, + + $ON_HIDE_DIALOG_LAYER : function(oLayer){ + oLayer = jQuery.$(oLayer); + + if(oLayer) oLayer.style.display = "none"; + this.aOpenedLayers = jQuery.grep(this.aOpenedLayers, function(a){return a!=oLayer}); + }, + + $ON_SET_DIALOG_LAYER_POSITION : function(oLayer, iTop, iLeft){ + oLayer.style.top = iTop; + oLayer.style.left = iLeft; + } +}); +//} +//{ +/** + * @fileOverview This file contains Xpress plugin that takes care of the layers that should disappear when the focus is lost + * @name hp_ActiveLayerManager.js + */ +xe.ActiveLayerManager = jQuery.Class({ + name : "ActiveLayerManager", + oCurrentLayer : null, + + $ON_TOGGLE_ACTIVE_LAYER : function(oLayer, sOnOpenCmd, aOnOpenParam, sOnCloseCmd, aOnCloseParam){ + if(oLayer == this.oCurrentLayer){ + this.oApp.exec("HIDE_ACTIVE_LAYER", []); + }else{ + this.oApp.exec("SHOW_ACTIVE_LAYER", [oLayer, sOnCloseCmd, aOnCloseParam]); + if(sOnOpenCmd) this.oApp.exec(sOnOpenCmd, aOnOpenParam); + } + }, + + $ON_SHOW_ACTIVE_LAYER : function(oLayer, sOnCloseCmd, aOnCloseParam){ + oLayer = jQuery.$(oLayer); + this.sOnCloseCmd = sOnCloseCmd; + this.aOnCloseParam = aOnCloseParam; + + var oPrevLayer = this.oCurrentLayer; + + if(oLayer == oPrevLayer) return; + + this.oApp.exec("HIDE_ACTIVE_LAYER", []); + + oLayer.style.display = "block"; + this.oCurrentLayer = oLayer; + }, + + $ON_HIDE_ACTIVE_LAYER : function(){ + var oLayer = this.oCurrentLayer; + if(!oLayer) return; + oLayer.style.display = "none"; + this.oCurrentLayer = null; + + if(this.sOnCloseCmd) + this.oApp.exec(this.sOnCloseCmd, this.aOnCloseParam); + }, + + // for backward compatibility only. + // use HIDE_ACTIVE_LAYER instead! + $ON_HIDE_CURRENT_ACTIVE_LAYER : function(){ + this.oApp.exec("HIDE_ACTIVE_LAYER", []); + }, + + $ON_EVENT_EDITING_AREA_KEYDOWN : function(){ + this.oApp.exec("HIDE_ACTIVE_LAYER", []); + }, + + $ON_EVENT_EDITING_AREA_MOUSEDOWN : function(){ + this.oApp.exec("HIDE_ACTIVE_LAYER", []); + } +}); +//} +//{ +/** + * @fileOverview This file contains Xpress plugin that takes care of the operations related to string conversion. Ususally used to convert the IR value. + * @name hp_StringConverterManager.js + */ +xe.StringConverterManager = jQuery.Class({ + name : "StringConverterManager", + + oConverters : null, + + $init : function(){ + this.oConverters = {}; + }, + + $BEFORE_MSG_APP_READY : function(){ + this.oApp.exec("ADD_APP_PROPERTY", ["applyConverter", jQuery.fnBind(this.applyConverter, this)]); + this.oApp.exec("ADD_APP_PROPERTY", ["addConverter", jQuery.fnBind(this.addConverter, this)]); + }, + + applyConverter : function(sRuleName, sContent){ + var aConverters = this.oConverters[sRuleName]; + if(!aConverters) return sContent; + + for(var i=0; i*:first-child", aAllLi[i]).get(0); + } + } + }, + + $ON_MSG_APP_READY : function(){ + this.oApp.registerBrowserEvent(this.toolbarArea, "mouseover", "EVENT_TOOLBAR_MOUSEOVER", []); + this.oApp.registerBrowserEvent(this.toolbarArea, "mouseout", "EVENT_TOOLBAR_MOUSEOUT", []); + + this.oApp.exec("ADD_APP_PROPERTY", ["getToolbarButtonByUIName", jQuery.fnBind(this.getToolbarButtonByUIName, this)]); + }, + + $ON_EVENT_TOOLBAR_MOUSEOVER : function(weEvent){ + if(weEvent.target.tagName == "BUTTON") jQuery(weEvent.target).addClass("hover").parent("span").addClass("hover"); + }, + + $ON_EVENT_TOOLBAR_MOUSEOUT : function(weEvent){ + if(weEvent.target.tagName == "BUTTON") jQuery(weEvent.target).removeClass("hover").parent("span").removeClass("hover"); + }, + + $ON_TOGGLE_TOOLBAR_ACTIVE_LAYER : function(oLayer, oBtn, sOpenCmd, aOpenArgs, sCloseCmd, aCloseArgs){ + this.oApp.exec("TOGGLE_ACTIVE_LAYER", [oLayer, "MSG_TOOLBAR_LAYER_SHOWN", [oLayer, oBtn, sOpenCmd, aOpenArgs], sCloseCmd, aCloseArgs]); + }, + + $ON_MSG_TOOLBAR_LAYER_SHOWN : function(oLayer, oBtn, aOpenCmd, aOpenArgs){ + this.oApp.exec("POSITION_TOOLBAR_LAYER", [oLayer, oBtn]); + if(aOpenCmd) this.oApp.exec(aOpenCmd, aOpenArgs); + }, + + $ON_SHOW_TOOLBAR_ACTIVE_LAYER : function(oLayer, sCmd, aArgs, oBtn){ + this.oApp.exec("SHOW_ACTIVE_LAYER", [oLayer, sCmd, aArgs]); + this.oApp.exec("POSITION_TOOLBAR_LAYER", [oLayer, oBtn]); + }, + + $ON_ENABLE_UI : function(sUIName){ + var elUI = this.htUIList[sUIName]; + if(!elUI) return; + jQuery(elUI).removeClass("off"); + elUI.disabled = false; + + // enable related commands + var sCmd = ""; + if(this.aUICmdMap[sUIName]){ + for(var i=0; i nToolbarLeft) oLayer.style.left = (nToolbarLeft-nLayerLeft-5)+"px"; + }, + + getToolbarButtonByUIName : function(sUIName){ + return this.htUIList[sUIName]; + } +}); +//} +//{ +/** + * @fileOverview This file contains Xpress plugin that manages multiple number editing area plugins and the IR value + * @name hp_XE_EditingAreaManager.js + */ +xe.XE_EditingAreaManager = jQuery.Class({ + name : "XE_EditingAreaManager", + + // Currently active plugin instance(XE_EditingArea_???) + oActivePlugin : null, + + // Intermediate Representation of the content being edited. + // This should be a textarea element. + oIRField : null, + + bIsDirty : false, + + $init : function(sInitialMode, oIRField, oDimension, fOnBeforeUnload, oAppContainer){ + this.sInitialMode = sInitialMode; + this.oIRField = jQuery.$(oIRField); + this._assignHTMLObjects(oAppContainer); + this.fOnBeforeUnload = fOnBeforeUnload; + + this.oEditingMode = {}; + + this.elEditingAreaContainer.style.height = parseInt(oDimension.nHeight || this.elEditingAreaContainer.offsetHeight)+"px"; + + this.nMinHeight = oDimension.nMinHeight || 10; + this.niMinWidth = oDimension.nMinWidth || 10; + }, + + _assignHTMLObjects : function(oAppContainer){ + oAppContainer = jQuery.$(oAppContainer) || document; + this.elEditingAreaContainer = jQuery("DIV.xpress_xeditor_editing_area_container", oAppContainer).get(0); + this.elEditingAreaSkipUI = jQuery("A.skip", oAppContainer).get(0); + }, + + $BEFORE_MSG_APP_READY : function(msg){ + this.oApp.exec("ADD_APP_PROPERTY", ["elEditingAreaContainer", this.elEditingAreaContainer]); + this.oApp.exec("ADD_APP_PROPERTY", ["getIR", jQuery.fnBind(this.getIR, this)]); + this.oApp.exec("ADD_APP_PROPERTY", ["setIR", this.setIR]); + this.oApp.exec("ADD_APP_PROPERTY", ["getEditingMode", jQuery.fnBind(this.getEditingMode, this)]); + }, + + $ON_MSG_APP_READY : function(){ + this.oApp.exec("CHANGE_EDITING_MODE", [this.sInitialMode, true]); + this.oApp.exec("LOAD_IR_FIELD", [false]); + + this.oApp.registerBrowserEvent(this.elEditingAreaSkipUI, "focus", "MSG_EDITING_AREA_SIZE_CHANGED", [], 50); + this.oApp.registerBrowserEvent(this.elEditingAreaSkipUI, "blur", "MSG_EDITING_AREA_SIZE_CHANGED", [], 50); + + var fOnBeforeUnload = this.fOnBeforeUnload||function(){if(this.getIR() != this.oIRField.value || this.bIsDirty) return this.oApp.$MSG("XE_EditingAreaManager.onExit")}; + jQuery(window).bind("beforeunload", jQuery.fnBind(fOnBeforeUnload, this)); + }, + + $AFTER_MSG_APP_READY : function(){ + this.oApp.exec("UPDATE_IR_FIELD", []); + }, + + $ON_LOAD_IR_FIELD : function(bDontAddUndo){ + this.oApp.setIR(this.oIRField.value, bDontAddUndo); + }, + + $ON_UPDATE_IR_FIELD : function(){ + this.oIRField.value = this.oApp.getIR(); + }, + + $BEFORE_CHANGE_EDITING_MODE : function(sMode){ + this._oPrevActivePlugin = this.oActivePlugin; + this.oActivePlugin = this.oEditingMode[sMode]; + }, + + $AFTER_CHANGE_EDITING_MODE : function(sMode, bNoFocus){ + if(this._oPrevActivePlugin){ + var sIR = this._oPrevActivePlugin.getIR(); + this.oApp.exec("SET_IR", [sIR]); + + this.oApp.exec("ENABLE_UI", [this._oPrevActivePlugin.sMode]); + + this._setEditingAreaDimension(); + } + this.oApp.exec("DISABLE_UI", [this.oActivePlugin.sMode]); + + if(!bNoFocus){ + this.oApp.exec("FOCUS", []); + } + }, + + $ON_SET_IS_DIRTY : function(bIsDirty){ + this.bIsDirty = bIsDirty; + }, + + $ON_FOCUS : function(){ + if(!this.oActivePlugin || typeof this.oActivePlugin.setIR != "function") return + + this.oActivePlugin.focus(); + }, + + $BEFORE_SET_IR : function(sIR, bDontAddUndoHistory){ + bDontAddUndoHistory = bDontAddUndoHistory || false; + if(!bDontAddUndoHistory) this.oApp.exec("RECORD_UNDO_ACTION", ["SET CONTENTS"]); + }, + + $ON_SET_IR : function(sIR){ + if(!this.oActivePlugin || typeof this.oActivePlugin.setIR != "function") return + + this.oActivePlugin.setIR(sIR); + }, + + $AFTER_SET_IR : function(sIR, bDontAddUndoHistory){ + bDontAddUndoHistory = bDontAddUndoHistory || false; + if(!bDontAddUndoHistory) this.oApp.exec("RECORD_UNDO_ACTION", ["SET CONTENTS"]); + }, + + $ON_REGISTER_EDITING_AREA : function(oEditingAreaPlugin){ + this.oEditingMode[oEditingAreaPlugin.sMode] = oEditingAreaPlugin; + this.attachDocumentEvents(oEditingAreaPlugin.oEditingArea); + }, + + $ON_MSG_EDITING_AREA_RESIZE_STARTED : function(){ + this.oActivePlugin.elEditingArea.style.display = "none"; + + this.iStartingHeight = parseInt(this.elEditingAreaContainer.style.height); + }, + + $ON_RESIZE_EDITING_AREA: function(ipNewWidth, ipNewHeight){ + var iNewWidth = parseInt(ipNewWidth); + var iNewHeight = parseInt(ipNewHeight); + + if(iNewWidth < this.niMinWidth) iNewWidth = this.niMinWidth; + if(iNewHeight < this.nMinHeight) iNewHeight = this.nMinHeight; + + if(ipNewWidth) this.elEditingAreaContainer.style.width = iNewWidth + "px"; + if(ipNewHeight) this.elEditingAreaContainer.style.height = iNewHeight + "px"; + }, + + $ON_RESIZE_EDITING_AREA_BY : function(ipWidthChange, ipHeightChange){ + var iWidthChange = parseInt(ipWidthChange); + var iHeightChange = parseInt(ipHeightChange); + + var iWidth = this.elEditingAreaContainer.style.width?parseInt(this.elEditingAreaContainer.style.width)+iWidthChange:null; + var iHeight = this.elEditingAreaContainer.style.height?this.iStartingHeight+iHeightChange:null; + + this.oApp.exec("RESIZE_EDITING_AREA", [iWidth, iHeight]); + }, + + $ON_MSG_EDITING_AREA_RESIZE_ENDED : function(FnMouseDown, FnMouseMove, FnMouseUp){ + this.oActivePlugin.elEditingArea.style.display = "block"; + this._setEditingAreaDimension(); + }, + + _setEditingAreaDimension : function(){ + this.oActivePlugin.elEditingArea.style.height = this.elEditingAreaContainer.style.height; + this.oActivePlugin.elEditingArea.style.width = this.elEditingAreaContainer.style.width; + }, + + attachDocumentEvents : function(doc){ + this.oApp.registerBrowserEvent(doc, "click", "EVENT_EDITING_AREA_CLICK"); + this.oApp.registerBrowserEvent(doc, "mousedown", "EVENT_EDITING_AREA_MOUSEDOWN"); + this.oApp.registerBrowserEvent(doc, "mousemove", "EVENT_EDITING_AREA_MOUSEMOVE"); + this.oApp.registerBrowserEvent(doc, "mouseup", "EVENT_EDITING_AREA_MOUSEUP"); + this.oApp.registerBrowserEvent(doc, "keydown", "EVENT_EDITING_AREA_KEYDOWN"); + this.oApp.registerBrowserEvent(doc, "keypress", "EVENT_EDITING_AREA_KEYPRESS"); + this.oApp.registerBrowserEvent(doc, "keyup", "EVENT_EDITING_AREA_KEYUP"); + }, + + getIR : function(){ + return this.oActivePlugin.getIR(); + }, + + setIR : function(sIR, bDontAddUndo){ + this.oApp.exec("SET_IR", [sIR, bDontAddUndo]); + }, + + getEditingMode : function(){ + return this.oActivePlugin.sMode; + } +}); +//} + +//{ +/** + * @fileOverview This file contains Xpress plugin that takes care of the operations directly related to editing the HTML source code using Textarea element + * @name hp_XE_EditingArea_HTMLSrc.js + * @required XE_EditingAreaManager + */ +xe.XE_EditingArea_HTMLSrc = jQuery.Class({ + name : "XE_EditingArea_HTMLSrc", + + sMode : "HTMLSrc", + textarea : null, + + $init : function(textarea){ + this.textarea = jQuery.$(textarea); + this.elEditingArea = this.textarea; + }, + + $BEFORE_MSG_APP_READY : function(){ + this.oEditingArea = this.textarea; + this.oApp.exec("REGISTER_EDITING_AREA", [this]); + }, + + $ON_CHANGE_EDITING_MODE : function(sMode, bNoFocus){ + if(sMode == this.sMode){ + this.textarea.style.display = "block"; + }else{ + this.textarea.style.display = "none"; + } + }, + + $ON_PASTE_HTML : function(sHTML, oPSelection){ + if(this.oApp.getEditingMode() != this.sMode) return; + + var o = new TextRange(this.textarea); + o.paste(sHTML); + this.textarea.focus(); + }, + + getIR : function(){ + var sIR; + var sContent = this.textarea.value; + + if(this.oApp.applyConverter) + sIR = this.oApp.applyConverter(this.sMode+"_TO_IR", sContent); + else + sIR = sContent; + + return sIR; + }, + + setIR : function(sIR){ + var sContent; + + if(this.oApp.applyConverter) + sContent = this.oApp.applyConverter("IR_TO_"+this.sMode, sIR); + else + sContent = sIR; + + this.textarea.value = sContent; + }, + + focus : function(){ + this.textarea.focus(); + } +}); + +var TextRange = function(oEl) { + this._o = oEl; +}; + +/** + * Selection for textfield + * + * @author hooriza + */ +TextRange.prototype.getSelection = function() { + var obj = this._o; + var ret = [ -1, -1 ]; + + if (isNaN(this._o.selectionStart)) { + obj.focus(); + + // textarea support added by nagoon97 + var range = document.body.createTextRange(); + var rangeField = null; + + rangeField = document.selection.createRange().duplicate(); + range.moveToElementText(obj); + rangeField.collapse(true); + range.setEndPoint("EndToEnd", rangeField); + ret[0] = range.text.length; + + rangeField = document.selection.createRange().duplicate(); + range.moveToElementText(obj); + rangeField.collapse(false); + range.setEndPoint("EndToEnd", rangeField); + ret[1] = range.text.length; + + obj.blur(); + } else { + ret[0] = obj.selectionStart; + ret[1] = obj.selectionEnd; + } + + return ret; +}; + +TextRange.prototype.setSelection = function(start, end) { + + var obj = this._o; + if (typeof end == 'undefined') end = start; + + if (obj.setSelectionRange) { + + obj.setSelectionRange(start, end); + + } else if (obj.createTextRange) { + + var range = obj.createTextRange(); + + range.collapse(true); + range.moveStart("character", start); + range.moveEnd("character", end - start); + range.select(); + + obj.blur(); + } + +}; + +TextRange.prototype.copy = function() { + + var r = this.getSelection(); + return this._o.value.substring(r[0], r[1]); + +}; + +TextRange.prototype.paste = function(sStr) { + + var obj = this._o; + var sel = this.getSelection(); + + var value = obj.value; + + var pre = value.substr(0, sel[0]); + var post = value.substr(sel[1]); + + value = pre + sStr + post; + obj.value = value; + + var n = 0; + if ( typeof document.body.style.maxHeight == "undefined" ) { + var a = pre.match( /\n/gi ); + n = ( a != null ? a.length : 0 ); + } + this.setSelection(sel[0] + sStr.length - n ); + +}; + +TextRange.prototype.cut = function() { + var r = this.copy(); + this.paste(''); + + return r; +}; +//} +//{ +/** + * @fileOverview This file contains Xpress plugin that takes care of the operations directly related to WYSIWYG iframe + * @name hp_XE_EditingArea_WYSIWYG.js + */ +xe.XE_EditingArea_WYSIWYG = jQuery.Class({ + name : "XE_EditingArea_WYSIWYG", + status : xe.PLUGIN_STATUS["NOT_READY"], + + sMode : "WYSIWYG", + iframe : null, + doc : null, + + iLastUndoRecorded : 0, + iMinUndoInterval : 3000, + + _nIFrameReadyCount : 50, + + $init : function(iframe){ + this.iframe = jQuery.$(iframe); + + this.initIframe(); + + this.elEditingArea = iframe; + }, + + $BEFORE_MSG_APP_READY : function(){ + this.oEditingArea = this.doc; + this.oApp.exec("REGISTER_EDITING_AREA", [this]); + this.oApp.exec("ADD_APP_PROPERTY", ["getWYSIWYGWindow", jQuery.fnBind(this.getWindow, this)]); + this.oApp.exec("ADD_APP_PROPERTY", ["getWYSIWYGDocument", jQuery.fnBind(this.getDocument, this)]); + }, + + $ON_MSG_APP_READY : function(){ + // uncomment this line if you wish to use the IE-style cursor in FF + // this.getDocument().body.style.cursor = "text"; + + if(jQuery.browser.msie){ + jQuery(this.doc).bind('keydown', jQuery.fnBind( + function(weEvent){ + if(this.doc.selection.type.toLowerCase() == 'control' && weEvent.keyCode == 8) { + this.oApp.exec("EXECCOMMAND", ['delete', false, false]); + weEvent.preventDefault(); weEvent.stopPropagation(); + } + } + , this)); + jQuery(this.doc.body).bind('mousedown', jQuery.fnBind( + function(weEvent){ + this._oIERange = null; + this._bIERangeReset = true; + } + , this)); + jQuery(this.doc.body).bind('beforedeactivate', jQuery.fnBind( + function(weEvent){ + // without this, cursor won't make it inside a table. + // mousedown(_oIERange gets reset) -> beforedeactivate(gets fired for table) -> RESTORE_IE_SELECTION + if(this._bIERangeReset) return; + + var tmpRange = this.getDocument().selection.createRange(0); + // Control range does not have parentElement + if(tmpRange.parentElement && tmpRange.parentElement() && tmpRange.parentElement().tagName == "INPUT"){ + this._oIERange = this._oPrevIERange; + }else{ + this._oIERange = tmpRange; + } + } + , this)); + jQuery(this.doc.body).bind('mouseup', jQuery.fnBind( + function(weEvent){ + this._bIERangeReset = false; + } + , this)); + } + }, + + $ON_CHANGE_EDITING_MODE : function(sMode, bNoFocus){ + if(sMode == this.sMode){ + this.iframe.style.display = "block"; + + this.oApp.exec("REFRESH_WYSIWYG", []); + this.oApp.exec("SET_EDITING_WINDOW", [this.getWindow()]); + }else{ + this.iframe.style.display = "none"; + } + }, + + $AFTER_CHANGE_EDITING_MODE : function(sMode, bNoFocus){ + this._oIERange = null; + }, + + $ON_REFRESH_WYSIWYG : function(){ + if(!jQuery.browser.mozilla) return; + + this._disableWYSIWYG(); + this._enableWYSIWYG(); + }, + + $ON_ENABLE_WYSIWYG : function(){ + this._enableWYSIWYG(); + }, + + $ON_DISABLE_WYSIWYG : function(){ + this._disableWYSIWYG(); + }, + + $ON_EVENT_EDITING_AREA_KEYDOWN : function(oEvent) { + // ctrl-left/right add/remove indent + if(!oEvent.ctrlKey) return; + + switch(oEvent.keyCode) { + // outdent + case 37 : + this.oApp.exec("EXECCOMMAND", ["outdent", false, false]); + break; + // indent + case 39 : + this.oApp.exec("EXECCOMMAND", ["indent", false, false]); + break; + // h1 ~ h6, normal + case 49 : + case 50 : + case 51 : + case 52 : + case 53 : + case 54 : + this.oApp.exec("EXECCOMMAND", ["FormatBlock", false, '']); + break; + default : + return; + } + oEvent.preventDefault(); oEvent.stopPropagation(); + + }, + + $ON_EVENT_EDITING_AREA_KEYUP : function(oEvent){ + // 33, 34: page up/down, 35,36: end/home, 37,38,39,40: left, up, right, down + if(oEvent.keyCode == 229 || oEvent.keyCode == 13 || oEvent.altKey || oEvent.ctrlKey || (oEvent.keyCode >= 33 && oEvent.keyCode <= 40) || oEvent.keyCode == 16) return; + this._recordUndo(oEvent); + }, + + $ON_PASTE_HTML : function(sHTML, oPSelection){ + if(this.oApp.getEditingMode() != this.sMode) return; + + var oSelection = oPSelection || this.oApp.getSelection(); + oSelection.pasteHTML(sHTML); + + // every browser except for IE may modify the innerHTML when it is inserted + if(!jQuery.browser.msie){ + var sTmpBookmark = oSelection.placeStringBookmark(); + this.oApp.getWYSIWYGDocument().body.innerHTML = this.oApp.getWYSIWYGDocument().body.innerHTML; + oSelection.moveToBookmark(sTmpBookmark); + oSelection.collapseToEnd(); + oSelection.select(); + oSelection.removeStringBookmark(sTmpBookmark); + } + + this.oApp.exec("RECORD_UNDO_ACTION", ["INSERT HTML"]); + }, + + $AFTER_MSG_EDITING_AREA_RESIZE_ENDED : function(FnMouseDown, FnMouseMove, FnMouseUp){ + this.oApp.exec("REFRESH_WYSIWYG", []); + }, + + $ON_RESTORE_IE_SELECTION : function(){ + if(this._oIERange){ + this._oIERange.select(); + this._oPrevIERange = this._oIERange; + this._oIERange = null; + } + }, + + initIframe : function(){ + try { + this.doc = this.iframe.contentWindow.document; + if (this.doc == null || this.doc.location.href == 'about:blank') { + throw new Error('Access denied'); + } + + this._enableWYSIWYG(); + + this.status = xe.PLUGIN_STATUS["READY"]; + } catch(e) { + if(this._nIFrameReadyCount-- > 0){ + setTimeout(jQuery.fnBind(this.initIframe, this), 100); + }else{ + throw("iframe for WYSIWYG editing mode can't be initialized. Please check if the iframe document exists and is also accessable(cross-domain issues). "); + } + } + }, + + getIR : function(){ + var sContent = this.doc.body.innerHTML; + var sIR; + + if(this.oApp.applyConverter) + sIR = this.oApp.applyConverter(this.sMode+"_TO_IR", sContent); + else + sIR = sContent; + + return sIR; + }, + + setIR : function(sIR){ + var sContent; + if(this.oApp.applyConverter) + sContent = this.oApp.applyConverter("IR_TO_"+this.sMode, sIR); + else + sContent = sIR; + + this.doc.body.innerHTML = sContent; + + if(jQuery.browser.mozilla){ + if(this.doc.body.innerHTML == "") this.doc.body.innerHTML = "
"; + } + }, + + getWindow : function(){ + return this.iframe.contentWindow; + }, + + getDocument : function(){ + return this.iframe.contentWindow.document; + }, + + focus : function(){ + //this.getWindow().focus(); + //this.oApp.exec("RESTORE_IE_SELECTION", []); + }, + + _recordUndo : function(oKeyInfo){ + var curTime = new Date(); + if(curTime-this.iLastUndoRecorded < this.iMinUndoInterval) return; + this.oApp.exec("RECORD_UNDO_ACTION", ["KEYPRESS"]); + + this.iLastUndoRecorded = new Date(); + + this.prevKeyCode = oKeyInfo.keyCode; + }, + + _enableWYSIWYG : function(){ + if (jQuery.browser.msie){ + this.doc.body.disabled = true; + this.doc.body.contentEditable = true; + this.doc.body.removeAttribute('disabled'); + } else { + this.doc.designMode = "on"; + } + }, + + _disableWYSIWYG : function(){ + if (jQuery.browser.msie){ + this.doc.body.contentEditable = false; + } else { + this.doc.designMode = "off"; + } + } +}); +//} +//{ +/** + * @fileOverview This file contains Xpress plugin that takes care of the operations related to resizing the editing area vertically + * @name hp_XE_EditingAreaVerticalResizer.js + */ +xe.XE_EditingAreaVerticalResizer = jQuery.Class({ + name : "XE_EditingAreaVerticalResizer", + oResizeGrip : null, + + $init : function(oAppContainer){ + this._assignHTMLObjects(oAppContainer); + + this.$FnMouseDown = jQuery.fnBind(this._mousedown, this); + this.$FnMouseMove = jQuery.fnBind(this._mousemove, this); + this.$FnMouseUp = jQuery.fnBind(this._mouseup, this); + + jQuery(this.oResizeGrip).bind("mousedown", this.$FnMouseDown); + }, + + _assignHTMLObjects : function(oAppContainer){ + oAppContainer = jQuery.$(oAppContainer) || document; + + this.oResizeGrip = jQuery(".xpress_xeditor_editingArea_verticalResizer", oAppContainer).get(0); + }, + + _mousedown : function(oEvent){ + this.iStartHeight = oEvent.clientY; + + jQuery(document).bind("mousemove", this.$FnMouseMove); + jQuery(document).bind("mouseup", this.$FnMouseUp); + + this.oApp.exec("MSG_EDITING_AREA_RESIZE_STARTED", [this.$FnMouseDown, this.$FnMouseMove, this.$FnMouseUp]); + }, + + _mousemove : function(oEvent){ + var iHeightChange = oEvent.clientY - this.iStartHeight; + + this.oApp.exec("RESIZE_EDITING_AREA_BY", [0, iHeightChange]); + }, + + _mouseup : function(oEvent){ + jQuery(document).unbind("mousemove", this.$FnMouseMove); + jQuery(document).unbind("mouseup", this.$FnMouseUp); + + this.oApp.exec("MSG_EDITING_AREA_RESIZE_ENDED", [this.$FnMouseDown, this.$FnMouseMove, this.$FnMouseUp]); + } +}); +//} +//{ +/** + * @fileOverview This file contains Xpress plugin that takes care of the basic editor commands + * @name hp_XE_ExecCommand.js + */ +xe.XE_ExecCommand = jQuery.Class({ + name : "XE_ExecCommand", + oEditingArea : null, + + $init : function(oEditingArea){ + this.oEditingArea = oEditingArea; + }, + + $BEFORE_MSG_APP_READY : function(){ + // the right document will be available only when the src is completely loaded + if(this.oEditingArea && this.oEditingArea.tagName == "IFRAME") + this.oEditingArea = this.oEditingArea.contentWindow.document; + }, + + $ON_MSG_APP_READY : function(){ + this.oApp.exec("REGISTER_HOTKEY", ["ctrl+b", "EXECCOMMAND", ["bold", false, false]]); + this.oApp.exec("REGISTER_HOTKEY", ["ctrl+u", "EXECCOMMAND", ["underline", false, false]]); + this.oApp.exec("REGISTER_HOTKEY", ["ctrl+i", "EXECCOMMAND", ["italic", false, false]]); + this.oApp.exec("REGISTER_HOTKEY", ["ctrl+d", "EXECCOMMAND", ["strikethrough", false, false]]); + + this.oApp.exec("REGISTER_UI_EVENT", ["bold", "click", "EXECCOMMAND", ["bold", false, false]]); + this.oApp.exec("REGISTER_UI_EVENT", ["underline", "click", "EXECCOMMAND", ["underline", false, false]]); + this.oApp.exec("REGISTER_UI_EVENT", ["italic", "click", "EXECCOMMAND", ["italic", false, false]]); + this.oApp.exec("REGISTER_UI_EVENT", ["lineThrough", "click", "EXECCOMMAND", ["strikethrough", false, false]]); + this.oApp.exec("REGISTER_UI_EVENT", ["superscript", "click", "EXECCOMMAND", ["superscript", false, false]]); + this.oApp.exec("REGISTER_UI_EVENT", ["subscript", "click", "EXECCOMMAND", ["subscript", false, false]]); + this.oApp.exec("REGISTER_UI_EVENT", ["justifyleft", "click", "EXECCOMMAND", ["justifyleft", false, false]]); + this.oApp.exec("REGISTER_UI_EVENT", ["justifycenter", "click", "EXECCOMMAND", ["justifycenter", false, false]]); + this.oApp.exec("REGISTER_UI_EVENT", ["justifyright", "click", "EXECCOMMAND", ["justifyright", false, false]]); + this.oApp.exec("REGISTER_UI_EVENT", ["justifyfull", "click", "EXECCOMMAND", ["justifyfull", false, false]]); + this.oApp.exec("REGISTER_UI_EVENT", ["orderedlist", "click", "EXECCOMMAND", ["insertorderedlist", false, false]]); + this.oApp.exec("REGISTER_UI_EVENT", ["unorderedlist", "click", "EXECCOMMAND", ["insertunorderedlist", false, false]]); + this.oApp.exec("REGISTER_UI_EVENT", ["outdent", "click", "EXECCOMMAND", ["outdent", false, false]]); + this.oApp.exec("REGISTER_UI_EVENT", ["indent", "click", "EXECCOMMAND", ["indent", false, false]]); + }, + + $BEFORE_EXECCOMMAND : function(sCommand, bUserInterface, vValue){ + this._bOnlyCursorChanged = false; + + this.oApp.exec("FOCUS", []); + + if(sCommand.match(/^bold|underline|italic|strikethrough|superscript|subscript$/i)){ + var oSelection = this.oApp.getSelection(); + if(oSelection.collapsed) this._bOnlyCursorChanged = true; + } + + if(!this._bOnlyCursorChanged){ + this.oApp.exec("RECORD_UNDO_BEFORE_ACTION", [sCommand]); + } + }, + + $ON_EXECCOMMAND : function(sCommand, bUserInterface, vValue){ + bUserInterface = (bUserInterface == "" || bUserInterface)?bUserInterface:false; + vValue = (vValue == "" || vValue)?vValue:false; + + this.oEditingArea.execCommand(sCommand, bUserInterface, vValue); + }, + + $AFTER_EXECCOMMAND : function(sCommand, bUserInterface, vValue){ + if(!this._bOnlyCursorChanged){ + this.oApp.exec("RECORD_UNDO_AFTER_ACTION", [sCommand]); + } + + this.oApp.exec("CHECK_STYLE_CHANGE", []); + } +}); +//} + +//{ +/** + * @fileOverview This file contains Xpress plugin that takes care of the operations related to wrapping the sentence around with a

tag when enter key is pressed + * @name hp_XE_WYSIWYGEnterKey.js + */ +xe.XE_WYSIWYGEnterKey = jQuery.Class({ + name : "XE_WYSIWYGEnterKey", + // IE/Opera do not need this + unsupportedBrowser : ['ie', 'opera'], + oEditingArea : null, + + $init : function(oEditingArea){ + this.oEditingArea = oEditingArea; + }, + + $BEFORE_MSG_APP_READY : function(){ + // the right document will be available only when the src is completely loaded + if(this.oEditingArea && this.oEditingArea.tagName == "IFRAME") + this.oEditingArea = this.oEditingArea.contentWindow.document; + }, + + $ON_EVENT_EDITING_AREA_KEYDOWN : function(oEvent){ + if(this.oApp.getEditingMode() != "WYSIWYG") return; + + if(oEvent.shiftKey) return; + + if(oEvent.keyCode == 13){ + var oSelection = this.oApp.getSelection(); + var sBM = oSelection.placeStringBookmark(); + var oLineInfo = oSelection.getLineInfo(); + var oStart = oLineInfo.oStart; + var oEnd = oLineInfo.oEnd; + + //top.document.title = oStart.oNode.tagName+":"+oStart.oNode.nodeValue+", "+oEnd.oNode.tagName+":"+oEnd.oNode.nodeValue+"::"+oStart.bParentBreak+", "+oStart.oLineBreaker.tagName; + + // line broke by sibling + // or + // the parent line breaker is just a block container + if(!oStart.bParentBreak || oSelection.rxBlockContainer.test(oStart.oLineBreaker.tagName)){ + oEvent.stopPropagation(); + oEvent.preventDefault(); + + var oSWrapper = this.oEditingArea.createElement("P"); + oSelection.moveToBookmark(sBM); + oSelection.setStartBefore(oStart.oNode); + oSelection.surroundContents(oSWrapper); + + oSelection.collapseToEnd(); + + var oEWrapper = this.oEditingArea.createElement("P"); + oSelection.setEndAfter(oEnd.oNode); + oSelection.surroundContents(oEWrapper); + + oSelection.removeStringBookmark(sBM); + + if(oSWrapper.innerHTML == "") oSWrapper.innerHTML = "
"; + if(oEWrapper.innerHTML == "") oEWrapper.innerHTML = "
"; + + if(oEWrapper.nextSibling && oEWrapper.nextSibling.tagName == "BR") oEWrapper.parentNode.removeChild(oEWrapper.nextSibling); + + oSelection.selectNodeContents(oEWrapper); + oSelection.collapseToStart(); + oSelection.select(); + this.oApp.exec("CHECK_STYLE_CHANGE", []); + }else{ + oSelection.removeStringBookmark(sBM); + } + } + } +}); +//} + +//{ +/** + * @fileOverview This file contains Xpress plugin that takes care of the operations related to styling the font + * @name hp_XE_WYSIWYGStyler.js + * @required XE_EditingArea_WYSIWYG, XpressRangeManager + */ +xe.XE_WYSIWYGStyler = jQuery.Class({ + name : "XE_WYSIWYGStyler", + + $PRECONDITION : function(sFullCommand, aArgs){ + return (this.oApp.getEditingMode() == "WYSIWYG"); + }, + + $ON_SET_WYSIWYG_STYLE : function(oStyles){ + var oSelection = this.oApp.getSelection(); + + // style cursor + if(oSelection.collapsed){ + var oSpan = this.oApp.getWYSIWYGDocument().createElement("SPAN"); + oSelection.insertNode(oSpan); + oSpan.innerHTML = unescape("%uFEFF"); + + var sValue; + for(var sName in oStyles){ + sValue = oStyles[sName]; + + if(typeof sValue != "string") continue; + + oSpan.style[sName] = sValue; + } + + oSelection.selectNodeContents(oSpan); + oSelection.collapseToEnd(); + oSelection._window.focus(); + oSelection._window.document.body.focus(); + oSelection.select(); + + // FF3 will actually display %uFEFF when it is followed by a number AND certain font-family is used(like Gulim), so remove the chcaracter for FF3 + if(jQuery.browser.mozilla && jQuery.browser.nVersion == 3) + oSpan.innerHTML = ""; + + return; + } + + this.oApp.exec("RECORD_UNDO_BEFORE_ACTION", ["FONT STYLE"]); + + oSelection.styleRange(oStyles); + oSelection._window.focus(); + oSelection.select(); + + this.oApp.exec("RECORD_UNDO_AFTER_ACTION", ["FONT STYLE"]); + } +}); +//} + +//{ +/** + * @fileOverview This file contains Xpress plugin that takes care of the operations related to detecting the style change + * @name hp_XE_WYSIWYGStyleGetter.js + */ +xe.XE_WYSIWYGStyleGetter = jQuery.Class({ + name : "XE_WYSIWYGStyleGetter", + + hKeyUp : null, + + getStyleInterval : 200, + + oStyleMap : { + fontFamily : { + type : "Value", + css : "fontFamily" + }, + fontSize : { + type : "Value", + css : "fontSize" + }, + lineHeight : { + type : "Value", + css : "lineHeight", + converter : function(sValue, oStyle){ + if(!sValue.match(/px$/)) return sValue; + + return Math.ceil((parseInt(sValue)/parseInt(oStyle.fontSize))*10)/10; + } + }, + bold : { + command : "bold" + }, + underline : { + command : "underline" + }, + italic : { + command : "italic" + }, + lineThrough : { + command : "strikethrough" + }, + superscript : { + command : "superscript" + }, + subscript : { + command : "subscript" + }, + justifyleft : { + command : "justifyleft" + }, + justifycenter : { + command : "justifycenter" + }, + justifyright : { + command : "justifyright" + }, + justifyfull : { + command : "justifyfull" + }, + orderedlist : { + command : "insertorderedlist" + }, + unorderedlist : { + command : "insertunorderedlist" + } + }, + + $init : function(){ + this.oStyle = this._getBlankStyle(); + }, + + $PRECONDITION : function(){ + if(this.oApp.getEditingMode() != "WYSIWYG") return false; + + return true; + }, + + $ON_MSG_APP_READY : function(){ + this.oDocument = this.oApp.getWYSIWYGDocument(); + this.oApp.exec("ADD_APP_PROPERTY", ["getCurrentStyle", jQuery.fnBind(this.getCurrentStyle, this)]); + }, + + $ON_EVENT_EDITING_AREA_MOUSEUP : function(oEvnet){ + if(this.hKeyUp) clearTimeout(this.hKeyUp); + this.oApp.exec("CHECK_STYLE_CHANGE", []); + }, + + $ON_EVENT_EDITING_AREA_KEYUP : function(oEvent){ + /* + backspace 8 + page up 33 + page down 34 + end 35 + home 36 + left arrow 37 + up arrow 38 + right arrow 39 + down arrow 40 + insert 45 + delete 46 + */ + if(!(oEvent.keyCode == 8 || (oEvent.keyCode >= 33 && oEvent.keyCode <= 40) || oEvent.keyCode == 45 || oEvent.keyCode == 46)) return; + + if(this.hKeyUp) clearTimeout(this.hKeyUp); + + this.hKeyUp = setTimeout(jQuery.fnBind(this.oApp.exec, this.oApp, "CHECK_STYLE_CHANGE", []), this.getStyleInterval); + }, + + $ON_CHECK_STYLE_CHANGE : function(){ + this._getStyle(); + }, + + $ON_RESET_STYLE_STATUS : function(){ + var oBlankStyle = this._getBlankStyle(); + for(var sAttributeName in oBlankStyle) + this.oApp.exec("SET_STYLE_STATUS", [sAttributeName, oBlankStyle[sAttributeName]]); + }, + + getCurrentStyle : function(){ + return this.oStyle; + }, + + _check_style_change : function(){ + this.oApp.exec("CHECK_STYLE_CHANGE", []); + }, + + _getBlankStyle : function(){ + var oBlankStyle = {}; + for(var attributeName in this.oStyleMap){ + if(this.oStyleMap[attributeName].type == "Value") + oBlankStyle[attributeName] = ""; + else + oBlankStyle[attributeName] = 0; + } + + return oBlankStyle; + }, + + _getStyle : function(){ + var oSelection = this.oApp.getSelection(); + + var funcFilter = function(oNode){ + if (!oNode.childNodes || oNode.childNodes.length == 0) + return true; + else + return false; + } + + var aBottomNodes = oSelection.getNodes(false, funcFilter); + + var oStyle, oBaseStyle, oTmpStyle, attributeName; + if(aBottomNodes.length == 0){ + oStyle = this._getStyleOf(oSelection.commonAncestorContainer); + }else{ + oStyle = this._getStyleOf(aBottomNodes[0]); + } + + for(attributeName in oStyle){ + if(this.oStyleMap[attributeName].converter){ + oStyle[attributeName] = this.oStyleMap[attributeName].converter(oStyle[attributeName], oStyle); + } + + if(this.oStyle[attributeName] != oStyle[attributeName]) + this.oApp.exec("MSG_STYLE_CHANGED", [attributeName, oStyle[attributeName]]); + } + + this.oStyle = oStyle; + }, + + _getStyleOf : function(oNode){ + var oStyle = this._getBlankStyle(); + + // this must not happen + if(!oNode) return oStyle; + + if(oNode.nodeType == 3) oNode = oNode.parentNode; + + var welNode = jQuery(oNode); + var attribute, cssName; + for(var styleName in this.oStyle){ + attribute = this.oStyleMap[styleName]; + + if(attribute.type && attribute.type == "Value"){ + if(attribute.css){ + var sValue = welNode.css(attribute.css); + + if(styleName == "fontFamily"){ + sValue = sValue.split(/,/)[0]; + } + + oStyle[styleName] = sValue; + }else{ + if(attribute.command){ + try{ + oStyle[styleName] = this.oDocument.queryCommandState(attribute.command); + }catch(e){} + }else{ + // todo + } + } + }else{ + if(attribute.command){ + try{ + if(this.oDocument.queryCommandState(attribute.command)){ + oStyle[styleName] = 1; + }else{ + oStyle[styleName] = 0; + } + }catch(e){} + }else{ + // todo + } + } + } + return oStyle; + } +}); +//} +//{ +/** + * @fileOverview This file contains Xpress plugin that takes care of the operations related to changing the font size using Select element + * @name hp_XE_FontSizeWithSelectUI.js + */ +xe.XE_FontSizeWithSelectUI = jQuery.Class({ + name : "XE_FontSizeWithSelectUI", + + $init : function(elAppContainer){ + this._assignHTMLObjects(elAppContainer); + }, + + _assignHTMLObjects : function(elAppContainer){ + this.elFontSizeSelect = jQuery("SELECT.xpress_xeditor_ui_fontSize_select", elAppContainer).get(0); + }, + + $ON_MSG_APP_READY : function(){ + this.oApp.registerBrowserEvent(this.elFontSizeSelect, "change", "SET_FONTSIZE_FROM_SELECT_UI"); + this.elFontSizeSelect.selectedIndex = 0; + }, + + $ON_MSG_STYLE_CHANGED : function(sAttributeName, sAttributeValue){ + if(sAttributeName == "fontSize"){ + this.elFontSizeSelect.value = sAttributeValue; + if(this.elFontSizeSelect.selectedIndex < 0) this.elFontSizeSelect.selectedIndex = 0; + } + }, + + $ON_SET_FONTSIZE_FROM_SELECT_UI : function(){ + var sFontSize = this.elFontSizeSelect.value; + if(!sFontSize) return; + + this.oApp.exec("SET_WYSIWYG_STYLE", [{"fontSize":sFontSize}]); + this.oApp.exec("CHECK_STYLE_CHANGE", []); + } +}); +//} +//{ +/** + * @fileOverview This file contains Xpress plugin that takes care of the operations related to changing the font name using Select element + * @name hp_XE_FontNameWithSelectUI.js + */ +xe.XE_FontNameWithSelectUI = jQuery.Class({ + name : "XE_FontNameWithSelectUI", + + $init : function(elAppContainer){ + this._assignHTMLObjects(elAppContainer); + }, + + _assignHTMLObjects : function(elAppContainer){ + this.elFontNameSelect = jQuery("SELECT.xpress_xeditor_ui_fontName_select", elAppContainer).get(0); + }, + + $ON_MSG_APP_READY : function(){ + this.oApp.registerBrowserEvent(this.elFontNameSelect, "change", "SET_FONTNAME_FROM_SELECT_UI"); + this.elFontNameSelect.selectedIndex = 0; + }, + + $ON_MSG_STYLE_CHANGED : function(sAttributeName, sAttributeValue){ + if(sAttributeName == "fontFamily"){ + this.elFontNameSelect.value = sAttributeValue.toLowerCase(); + if(this.elFontNameSelect.selectedIndex < 0) this.elFontNameSelect.selectedIndex = 0; + } + }, + + $ON_SET_FONTNAME_FROM_SELECT_UI : function(){ + var sFontName = this.elFontNameSelect.value; + if(!sFontName) return; + + this.oApp.exec("SET_WYSIWYG_STYLE", [{"fontFamily":sFontName}]); + this.oApp.exec("CHECK_STYLE_CHANGE", []); + } +}); +//} +//{ +/** + * @fileOverview This file contains Xpress plugin that takes care of the operations related to setting/changing the lineheight + * @name hp_XE_LineHeight.js + */ +xe.XE_LineHeight = jQuery.Class({ + name : "XE_LineHeight", + + $init : function(oAppContainer){ + this._assignHTMLObjects(oAppContainer); + }, + + _assignHTMLObjects : function(oAppContainer){ + }, + + $ON_SET_LINEHEIGHT : function(nLineHeight){ + this.setLineHeight(nLineHeight); + }, + + getLineHeight : function(){ + var nodes = this._getSelectedNodes(false); + + var curWrapper, prevWrapper; + var iCurHeight, iHeight; + + if(nodes.length == 0) return -1; + + var iLength = nodes.length; + + if(iLength == 0){ + iHeight = -1; + }else{ + prevWrapper = this._getLineWrapper(nodes[0]); + iHeight = this._getWrapperLineheight(prevWrapper); + } + + var firstNode = this.oSelection.getStartNode(); + + if(iHeight > 0){ + for(var i=1; i=0; i--){ + if(aNodes[i].nodeType == 3 || aNodes[i].tagName == "BR"){ + var oP = oSelection._document.createElement("P"); + oInsertionPoint = aNodes[i].nextSibling; + while(i>=0 && aNodes[i] && (aNodes[i].nodeType == 3 || aNodes[i].tagName == "BR")){ + oP.insertBefore(aNodes[i--], oP.firstChild); + } + oFormattingNode.insertBefore(oP, oInsertionPoint); + i++; + } + } + + if(oFormattingNode && oFormattingNode.parentNode){ + var oP = oSelection._document.createElement("P"); + oP.innerHTML = unescape("
"); + oFormattingNode.parentNode.insertBefore(oP, oFormattingNode.nextSibling); + } + + this.oApp.exec("RECORD_UNDO_ACTION", ["Block Quote"]); + + return oFormattingNode; + }, + + _expandToTableStart : function(oSelection, oNode){ + var oC = oSelection.commonAncestorContainer; + var oResultNode = null; + + var bLastIteration = false; + while(oNode && !bLastIteration){ + if(oNode == oC) bLastIteration = true; + + if(/TBODY|TFOOT|THEAD|TR/i.test(oNode.tagName)){ + oResultNode = this._getTableRoot(oNode); + break; + } + oNode = oNode.parentNode; + } + + return oResultNode; + }, + + _getTableRoot : function(oNode){ + while(oNode && oNode.tagName != "TABLE") oNode = oNode.parentNode; + + return oNode; + } +}); +//} +//{ +/** + * @fileOverview This file contains Xpress plugin that takes care of the operations related to inserting special characters + * @name hp_XE_SCharacter.js + * @required XpressRangeManager + */ +xe.XE_SCharacter = jQuery.Class({ + name : "XE_SCharacter", + + $init : function(oAppContainer){ + this.bIE = jQuery.browser.msie; + + this._assignHTMLObjects(oAppContainer); + + this.charSet = []; + this.charSet[0] = unescape('FF5B FF5D 3014 3015 3008 3009 300A 300B 300C 300D 300E 300F 3010 3011 2018 2019 201C 201D 3001 3002 %B7 2025 2026 %A7 203B 2606 2605 25CB 25CF 25CE 25C7 25C6 25A1 25A0 25B3 25B2 25BD 25BC 25C1 25C0 25B7 25B6 2664 2660 2661 2665 2667 2663 2299 25C8 25A3 25D0 25D1 2592 25A4 25A5 25A8 25A7 25A6 25A9 %B1 %D7 %F7 2260 2264 2265 221E 2234 %B0 2032 2033 2220 22A5 2312 2202 2261 2252 226A 226B 221A 223D 221D 2235 222B 222C 2208 220B 2286 2287 2282 2283 222A 2229 2227 2228 FFE2 21D2 21D4 2200 2203 %B4 FF5E 02C7 02D8 02DD 02DA 02D9 %B8 02DB %A1 %BF 02D0 222E 2211 220F 266D 2669 266A 266C 327F 2192 2190 2191 2193 2194 2195 2197 2199 2196 2198 321C 2116 33C7 2122 33C2 33D8 2121 2668 260F 260E 261C 261E %B6 2020 2021 %AE %AA %BA 2642 2640').replace(/(\S{4})/g, function(a){return "%u"+a}).split(' '); + this.charSet[1] = unescape('%BD 2153 2154 %BC %BE 215B 215C 215D 215E %B9 %B2 %B3 2074 207F 2081 2082 2083 2084 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 FFE6 %24 FFE5 FFE1 20AC 2103 212B 2109 FFE0 %A4 2030 3395 3396 3397 2113 3398 33C4 33A3 33A4 33A5 33A6 3399 339A 339B 339C 339D 339E 339F 33A0 33A1 33A2 33CA 338D 338E 338F 33CF 3388 3389 33C8 33A7 33A8 33B0 33B1 33B2 33B3 33B4 33B5 33B6 33B7 33B8 33B9 3380 3381 3382 3383 3384 33BA 33BB 33BC 33BD 33BE 33BF 3390 3391 3392 3393 3394 2126 33C0 33C1 338A 338B 338C 33D6 33C5 33AD 33AE 33AF 33DB 33A9 33AA 33AB 33AC 33DD 33D0 33D3 33C3 33C9 33DC 33C6').replace(/(\S{4})/g, function(a){return "%u"+a}).split(' '); + this.charSet[2] = unescape('3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 326A 326B 326C 326D 326E 326F 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 327A 327B 24D0 24D1 24D2 24D3 24D4 24D5 24D6 24D7 24D8 24D9 24DA 24DB 24DC 24DD 24DE 24DF 24E0 24E1 24E2 24E3 24E4 24E5 24E6 24E7 24E8 24E9 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 246A 246B 246C 246D 246E 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 320A 320B 320C 320D 320E 320F 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 321A 321B 249C 249D 249E 249F 24A0 24A1 24A2 24A3 24A4 24A5 24A6 24A7 24A8 24A9 24AA 24AB 24AC 24AD 24AE 24AF 24B0 24B1 24B2 24B3 24B4 24B5 2474 2475 2476 2477 2478 2479 247A 247B 247C 247D 247E 247F 2480 2481 2482').replace(/(\S{4})/g, function(a){return "%u"+a}).split(' '); + this.charSet[3] = unescape('3131 3132 3133 3134 3135 3136 3137 3138 3139 313A 313B 313C 313D 313E 313F 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 314A 314B 314C 314D 314E 314F 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 315A 315B 315C 315D 315E 315F 3160 3161 3162 3163 3165 3166 3167 3168 3169 316A 316B 316C 316D 316E 316F 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 317A 317B 317C 317D 317E 317F 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 318A 318B 318C 318D 318E').replace(/(\S{4})/g, function(a){return "%u"+a}).split(' '); + this.charSet[4] = unescape('0391 0392 0393 0394 0395 0396 0397 0398 0399 039A 039B 039C 039D 039E 039F 03A0 03A1 03A3 03A4 03A5 03A6 03A7 03A8 03A9 03B1 03B2 03B3 03B4 03B5 03B6 03B7 03B8 03B9 03BA 03BB 03BC 03BD 03BE 03BF 03C0 03C1 03C3 03C4 03C5 03C6 03C7 03C8 03C9 %C6 %D0 0126 0132 013F 0141 %D8 0152 %DE 0166 014A %E6 0111 %F0 0127 I 0133 0138 0140 0142 0142 0153 %DF %FE 0167 014B 0149 0411 0413 0414 0401 0416 0417 0418 0419 041B 041F 0426 0427 0428 0429 042A 042B 042C 042D 042E 042F 0431 0432 0433 0434 0451 0436 0437 0438 0439 043B 043F 0444 0446 0447 0448 0449 044A 044B 044C 044D 044E 044F').replace(/(\S{4})/g, function(a){return "%u"+a}).split(' '); + this.charSet[5] = unescape('3041 3042 3043 3044 3045 3046 3047 3048 3049 304A 304B 304C 304D 304E 304F 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 305A 305B 305C 305D 305E 305F 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 306A 306B 306C 306D 306E 306F 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 307A 307B 307C 307D 307E 307F 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 308A 308B 308C 308D 308E 308F 3090 3091 3092 3093 30A1 30A2 30A3 30A4 30A5 30A6 30A7 30A8 30A9 30AA 30AB 30AC 30AD 30AE 30AF 30B0 30B1 30B2 30B3 30B4 30B5 30B6 30B7 30B8 30B9 30BA 30BB 30BC 30BD 30BE 30BF 30C0 30C1 30C2 30C3 30C4 30C5 30C6 30C7 30C8 30C9 30CA 30CB 30CC 30CD 30CE 30CF 30D0 30D1 30D2 30D3 30D4 30D5 30D6 30D7 30D8 30D9 30DA 30DB 30DC 30DD 30DE 30DF 30E0 30E1 30E2 30E3 30E4 30E5 30E6 30E7 30E8 30E9 30EA 30EB 30EC 30ED 30EE 30EF 30F0 30F1 30F2 30F3 30F4 30F5 30F6').replace(/(\S{4})/g, function(a){return "%u"+a}).split(' '); + }, + + _assignHTMLObjects : function(oAppContainer){ + oAppContainer = jQuery.$(oAppContainer) || document; + + this.elDropdownLayer = jQuery("DIV.xpress_xeditor_sCharacter_layer", oAppContainer).get(0); + + this.oTextField = jQuery("INPUT", this.elDropdownLayer).get(0); + this.oInsertButton = jQuery("+ BUTTON", this.oTextField).get(0); + this.aCloseButton = jQuery("BUTTON.close", this.elDropdownLayer).get(); + this.aSCharList = jQuery(".list", this.elDropdownLayer).get(); + var oLabelUL = jQuery(">UL", this.elDropdownLayer).get(0); + this.aLabelA = jQuery("A", oLabelUL).get(); + }, + + $ON_MSG_APP_READY : function(){ + var funcInsert = jQuery.fnBind(this.oApp.exec, this.oApp, "INSERT_SCHARACTERS", [this.oTextField.value]); + jQuery(this.oInsertButton).click(funcInsert, this); + + this.oApp.exec("SET_SCHARACTER_LIST", [this.charSet]); + + for(var i=0; i"); + }else{ + button = document.createElement("BUTTON"); + button.type = "button"; + } + span = document.createElement("SPAN"); + span.innerHTML = unescape(this.charSet[i][ii]); + button.appendChild(span); + + aLI[ii].appendChild(button); + this.aSCharList[i].appendChild(aLI[ii]); + } + + // enable this after Jindo framework is updated +// this.oApp.exec("ATTACH_HOVER_EVENTS", [jQuery(">LI>BUTTON", this.aSCharList[i])]).get(); + }, + + _stopBrowserEvent : function(obj, sEvent){ + jQuery(obj).bind(sEvent, function(e){e.stopPropagation();e.preventDefault();} ) + } +}); +//} +//{ +/** + * @fileOverview This file contains Xpress plugin that takes care of the operations related to Undo/Redo + * @name hp_XE_UndoRedo.js + * @required XE_EditingAreaManager, XpressRangeManager + */ +xe.XE_UndoRedo = jQuery.Class({ + name : "XE_UndoRedo", + actionHistory : null, + // this may also be called, lastAdded/lastRestored + oCurStateIdx : null, + iMinimumSizeChange : 10, + sBlankContentsForFF : "
", + + $init : function(){ + this.aUndoHistory = []; + this.oCurStateIdx = {nIdx: 0, nStep: 0}; + }, + + $PRECONDITION : function(sCmd){ + if(sCmd.match(/_DO_RECORD_UNDO_HISTORY_AT$/)) return true; + + try{ + if(this.oApp.getEditingMode() != "WYSIWYG") return false; + }catch(e){ + return false; + } + + return true; + }, + + $BEFORE_MSG_APP_READY : function(){ + this.oApp.exec("DO_RECORD_UNDO_HISTORY_AT", [this.oCurStateIdx, "", "", null]); + }, + + $ON_MSG_APP_READY : function(){ + this.bFF = jQuery.browser.mozilla; + + this.oApp.exec("ADD_APP_PROPERTY", ["getUndoHistory", jQuery.fnBind(this.getUndoHistory, this)]); + this.oApp.exec("ADD_APP_PROPERTY", ["getUndoStateIdx", jQuery.fnBind(this.getUndoStateIdx, this)]); + + this.oApp.exec("REGISTER_UI_EVENT", ["undo", "click", "UNDO"]); + this.oApp.exec("REGISTER_UI_EVENT", ["redo", "click", "REDO"]); + + this.oApp.exec("REGISTER_HOTKEY", ["ctrl+z", "UNDO"]); + this.oApp.exec("REGISTER_HOTKEY", ["ctrl+y", "REDO"]); + }, + + $ON_UNDO : function(){ + var oTmpStateIdx = {}; + this.oApp.exec("DO_RECORD_UNDO_HISTORY", ["KEYPRESS", false, false, 1]); + if(this.oCurStateIdx.nIdx == 0) return; + + if(this.oCurStateIdx.nStep > 0){ + this.oCurStateIdx.nStep--; + }else{ + var oTmpHistory = this.aUndoHistory[this.oCurStateIdx.nIdx]; + + this.oCurStateIdx.nIdx--; + + if(oTmpHistory.nTotalSteps>1){ + this.oCurStateIdx.nStep = 0; + }else{ + oTmpHistory = this.aUndoHistory[this.oCurStateIdx.nIdx]; + this.oCurStateIdx.nStep = oTmpHistory.nTotalSteps-1; + } + } + + this.oApp.exec("RESTORE_UNDO_HISTORY", [this.oCurStateIdx.nIdx, this.oCurStateIdx.nStep]); + + this.oApp.exec("CHECK_STYLE_CHANGE", []); + }, + + + $ON_REDO : function(){ + if(this.oCurStateIdx.nIdx >= this.aUndoHistory.length) return; + + var oCurHistory = this.aUndoHistory[this.oCurStateIdx.nIdx]; + if(this.oCurStateIdx.nIdx == this.aUndoHistory.length-1 && this.oCurStateIdx.nStep >= oCurHistory.nTotalSteps-1) return; + + if(this.oCurStateIdx.nStep < oCurHistory.nTotalSteps-1){ + this.oCurStateIdx.nStep++; + }else{ + this.oCurStateIdx.nIdx++; + oCurHistory = this.aUndoHistory[this.oCurStateIdx.nIdx]; + this.oCurStateIdx.nStep = oCurHistory.nTotalSteps-1; + } + + this.oApp.exec("RESTORE_UNDO_HISTORY", [this.oCurStateIdx.nIdx, this.oCurStateIdx.nStep]); + + this.oApp.exec("CHECK_STYLE_CHANGE", []); + }, + + $ON_RECORD_UNDO_ACTION : function(sAction){ + this.oApp.exec("DO_RECORD_UNDO_HISTORY", [sAction]); + }, + + $ON_RECORD_UNDO_BEFORE_ACTION : function(sAction){ + this.oApp.exec("DO_RECORD_UNDO_HISTORY", [sAction, true, true]); + }, + + $ON_RECORD_UNDO_AFTER_ACTION : function(sAction){ + this.oApp.exec("DO_RECORD_UNDO_HISTORY", [sAction, true, false]); + }, + + $ON_RESTORE_UNDO_HISTORY : function(nUndoIdx, nUndoStateStep){ + this.oCurStateIdx.nIdx = nUndoIdx; + this.oCurStateIdx.nStep = nUndoStateStep; + + var oCurHistory = this.aUndoHistory[this.oCurStateIdx.nIdx]; + var sContent = oCurHistory.sContent[this.oCurStateIdx.nStep]; + var oBookmark = oCurHistory.oBookmark[this.oCurStateIdx.nStep]; + + this.oApp.setIR(sContent, true); + + // setting the innerHTML may change the internal DOM structure, so save the value again. + var sCurContent = this.oApp.getIR(); + if(this.bFF && sCurContent == this.sBlankContentsForFF){ + sCurContent = ""; + } + oCurHistory.sContent[this.oCurStateIdx.nStep] = sCurContent; + + var oSelection = this.oApp.getEmptySelection(); + if(oSelection.selectionLoaded){ + if(oBookmark){ + oSelection.moveToXPathBookmark(oBookmark); + }else{ + oSelection = this.oApp.getEmptySelection(); + } + + oSelection.select(); + } + }, + + $ON_DO_RECORD_UNDO_HISTORY : function(sAction, bTwoStepAction, bBeforeAction, nForceAddUnlessEqual){ + bTwoStepAction = bTwoStepAction || false; + bBeforeAction = bBeforeAction || false; + nForceAddUnlessEqual = nForceAddUnlessEqual || 0; + + // if we're in the middle of some action history, remove everything after current idx if any "little" change is made + if(!(this.oCurStateIdx.nIdx == this.aUndoHistory.length-1)) nForceAddUnlessEqual = 1; + + var oCurHistory = this.aUndoHistory[this.oCurStateIdx.nIdx]; + + var sCurContent = this.oApp.getIR(); + var sHistoryContent = oCurHistory.sContent[this.oCurStateIdx.nStep]; + + if(this.bFF && sCurContent == this.sBlankContentsForFF){ + sCurContent = ""; + } + + // every TwoStepAction needs to be recorded + if(!bTwoStepAction){ + switch(nForceAddUnlessEqual){ + case 0: + if(Math.abs(sHistoryContent.length - sCurContent.length) .bx", this.oUILayer).get(); + + this.oFindInputSet = oTmp[0]; + this.oReplaceInputSet = oTmp[1]; + + this.oFindInput_Keyword = jQuery("INPUT", this.oFindInputSet).get(0); + + oTmp = jQuery("INPUT", this.oReplaceInputSet).get(); + this.oReplaceInput_Original = oTmp[0]; + this.oReplaceInput_Replacement = oTmp[1]; + + this.oFindNextButton = jQuery("BUTTON.find_next", this.oUILayer).get(0); + this.oCancelButton = jQuery("BUTTON.cancel", this.oUILayer).get(0); + + this.oReplaceButton = jQuery("BUTTON.replace", this.oUILayer).get(0); + this.oReplaceAllButton = jQuery("BUTTON.replace_all", this.oUILayer).get(0); + + this.aCloseButtons = jQuery("BUTTON.close", this.oUILayer).get(); + this.aCloseButtons[this.aCloseButtons.length] = this.oCancelButton; + }, + + $ON_MSG_APP_READY : function(){ + // the right document will be available only when the src is completely loaded + if(this.oEditingWindow && this.oEditingWindow.tagName == "IFRAME") + this.oEditingWindow = this.oEditingWindow.contentWindow; + + this.oFindReplace = new xe.FindReplace(this.oEditingWindow); + if(!this.oFindReplace.bBrowserSupported){ + this.oApp.exec("DISABLE_UI", ["find_replace"]); + return; + } + + for(var i=0; i" + sURL + ""; + this.oSelection.pasteHTML(str); + }else{ + var nSession = Math.ceil(Math.random()*10000); + var arg = ( sURL == "" ? ["unlink"] : ["createLink", false, this.sATagMarker+nSession+sURL] ); + this.oApp.exec("EXECCOMMAND", arg); + + this.oSelection.setFromSelection(); + + var oDoc = this.oApp.getWYSIWYGDocument(); + var aATags = oDoc.body.getElementsByTagName("A"); + var nLen = aATags.length; + var rxMarker = new RegExp(this.sRXATagMarker+nSession, "i"); + var elATag; + for(var i=0; i this.iMaxRows) iRows = this.iMaxRows; + + this.oRowInput.value = iRows; + this._showNewTable(); + }, + + $ON_ST_SET_COLUMN_NUM : function(iColumns, iColumnDiff){ + iColumns = iColumns || parseInt(this.oColumnInput.value); + iColumnDiff = iColumnDiff || 0; + + iColumns += iColumnDiff; + + if(iColumns < this.iMinColumns) iColumns = this.iMinColumns; + if(iColumns > this.iMaxColumns) iColumns = this.iMaxColumns; + + this.oColumnInput.value = iColumns; + this._showNewTable(); + }, + + $ON_ST_INSERT_TABLE : function(){ + var sTable = this._getTableString(); + + this.oApp.exec("PASTE_HTML", [sTable]); + + this.oApp.exec("ST_CLOSE", []); + }, + + $ON_ST_CLOSE : function(){ + this.oApp.exec("HIDE_ACTIVE_LAYER", []); + }, + + $ON_ST_SET_BORDER_WIDTH : function(iBorderWidth, iBorderWidthDiff){ + iBorderWidth = iBorderWidth || parseInt(this.oBorderWidthInput.value); + iBorderWidthDiff = iBorderWidthDiff || 0; + + iBorderWidth += iBorderWidthDiff; + + if(iBorderWidth < this.iMinBorderWidth) iBorderWidth = this.iMinBorderWidth; + if(iBorderWidth > this.iMaxBorderWidth) iBorderWidth = this.iMaxBorderWidth; + + this.oBorderWidthInput.value = iBorderWidth; + this._showNewTable(); + }, + + $ON_ST_INC_BORDER_WIDTH : function(){ + this.oApp.exec("ST_SET_BORDER_WIDTH", [null, 1]); + }, + + $ON_ST_DEC_BORDER_WIDTH : function(){ + this.oApp.exec("ST_SET_BORDER_WIDTH", [null, -1]); + }, + + $ON_ST_TOGGLE_BORDER_COLOR_LAYER : function(){ + if(this.welDropdownLayer.hasClass("p1")) + this.oApp.exec("ST_HIDE_BORDER_COLOR_LAYER", []); + else + this.oApp.exec("ST_SHOW_BORDER_COLOR_LAYER", []); + }, + + $ON_ST_SHOW_BORDER_COLOR_LAYER : function(){ + this.welDropdownLayer.addClass("p1"); + this.welDropdownLayer.removeClass("p2"); + + this.oApp.exec("SHOW_COLOR_PALETTE", ["ST_SET_BORDER_COLOR_FROM_PALETTE", this.elDropdownLayer]); + }, + + $ON_ST_HIDE_BORDER_COLOR_LAYER : function(){ + this.welDropdownLayer.removeClass("p1"); + + this.oApp.exec("HIDE_COLOR_PALETTE", []); + }, + + $ON_ST_TOGGLE_BGCOLOR_LAYER : function(){ + if(this.welDropdownLayer.hasClass("p2")) + this.oApp.exec("ST_HIDE_BGCOLOR_LAYER", []); + else + this.oApp.exec("ST_SHOW_BGCOLOR_LAYER", []); + }, + + $ON_ST_SHOW_BGCOLOR_LAYER : function(){ + this.welDropdownLayer.removeClass("p1"); + this.welDropdownLayer.addClass("p2"); + + this.oApp.exec("SHOW_COLOR_PALETTE", ["ST_SET_BGCOLOR_FROM_PALETTE", this.elDropdownLayer]); + }, + + $ON_ST_HIDE_BGCOLOR_LAYER : function(){ + this.welDropdownLayer.removeClass("p2"); + + this.oApp.exec("HIDE_COLOR_PALETTE", []); + }, + + $ON_ST_SET_BORDER_COLOR_FROM_PALETTE : function(sColorCode){ + this.oApp.exec("ST_SET_BORDER_COLOR", [sColorCode]); + this.oApp.exec("ST_HIDE_BORDER_COLOR_LAYER", []); + }, + + $ON_ST_SET_BORDER_COLOR : function(sColorCode){ + this.oBorderColorInput.value = sColorCode; + this.oButton_BorderColorPreview.style.backgroundColor = sColorCode; + + this._showNewTable(); + }, + + $ON_ST_SET_BGCOLOR_FROM_PALETTE : function(sColorCode){ + this.oApp.exec("ST_SET_BGCOLOR", [sColorCode]); + this.oApp.exec("ST_HIDE_BGCOLOR_LAYER", []); + }, + + $ON_ST_SET_BGCOLOR : function(sColorCode){ + this.oBGColorInput.value = sColorCode; + this.oButton_BGColorPreview.style.backgroundColor = sColorCode; + + this._showNewTable(); + }, + + _showNewTable : function(){ + var oTmp = document.createElement("DIV"); + oTmp.innerHTML = this._getTableString(); + var oNewTable = oTmp.firstChild; + this.oSampleTable.parentNode.insertBefore(oNewTable, this.oSampleTable); + this.oSampleTable.parentNode.removeChild(this.oSampleTable); + this.oSampleTable = oNewTable; + }, + + // need to do something about the table width as the same HTML code is being used to the actual table and the preview table + _getTableString : function(){ + var sBorderColorCode = this.oBorderColorInput.value; + var sBGColorCode = this.oBGColorInput.value; + var iBorderWidth = this.oBorderWidthInput.value; + var sTD = ""; + if(jQuery.browser.msie){ + sTD = "

"; + }else{ + if(jQuery.browser.firefox){ + sTD = ""; + }else{ + sTD = ""; + } + } + + var sTable = '


 

'; + var sRow = ''; + var iColumns = this.oColumnInput.value; + for(var i=0; i/ig, + regex_meanless_css2 = /(?:(?:margin|padding)\s*:\s*0(?:px)?|\-(?:moz|ms|webkit|opera)\-[\w-]+\s*:\s*.*?|[\w-]+\s*:\s*\-(?:moz|ms|webkit|opera)\-[\w-]+|(?:line-height|font-variant|font-stretch|font-size-adjust|font-size)\s*:\s*[a-z_-]+)\s*;?\s*|font-(?:weight|style)\s*:\s*normal;?/ig, + regex_class = /<(.*?)\s+class\s*=(?:\s*"(.*?)"|\s*'(.*?)'|([^\s>]+))(.*?)>/ig, + regex_class2 = /xe_selected_cell/g; + regex_handler = /<(.*?)\s+on[a-z]+\s*=(?:\s*".*?"|\s*'.*?'|[^\s>]+)(.*?)>/ig, + //regex_id = /<(.*?)\s+id\s*=(?:[^\s>]+|\s*".*?"|\s*'.*?')(.*?)>/ig, + //regex_script = //ig, + regex_font_color = /color\s*=(?:\s*"(.*?)"|\s*'(.*?)'|([^\s>]+))/i, + regex_font_face = /face\s*=(?:\s*"(.*?)"|\s*'(.*?)'|([^\s>]+))/i, + regex_font_size = /size\s*=(?:\s*"(\d+)"|\s*'(\d+)'|(\d+))/i, + regex_style = /style\s*=\s*(?:\s*"(.*?)"|\s*'(.*?)'|([^\s>]+))/i, + regex_font_weight = /font-weight\s*:\s*([a-z]+);?/i, + regex_font_style = /font-style\s*:\s*italic;?/i, + regex_font_decoration = /text-decoration\s*:\s*([a-z -]+);?/i, + regex_jquery = /jQuery\d+\s*=(\s*"\d+"|\d+)/ig, + regex_quote_attr = /([\w-]+\s*=(?:\s*"[^"]+"|\s*'[^']+'))|([\w-]+)=([^\s]+)/g; //" + +var + allow_tags = 'a,abbr,acronym,address,area,blockquote,br,caption,center,cite,code,col,colgroup,dd,del,dfn,div,dl,dt,em,embed,h1,h2,h3,h4,h5,h6,hr,img,ins,kbd,li,map,object,ol,p,param,pre,q,samp,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,tt,u,ul,var,iframe,object,param,style'.split(','), + lonely_tags = 'area,br,col,embed,hr,img,input,param'.split(','); + +var + replace_tags = { + 'b' : 'strong', + 'i' : 'em', + 's' : 'del', + 'strike' : 'del' + }; + +xe.XE_XHTMLFormatter = $.Class({ + name : "XE_XHTMLFormatter", + + $ON_MSG_APP_READY : function() { + this.oApp.addConverter("WYSIWYG_TO_IR", this.TO_IR); + this.oApp.addConverter("HTMLSrc_TO_IR", this.TO_IR); + this.oApp.addConverter("IR_TO_HTMLSrc", this.IR_TO); + this.oApp.addConverter("IR_TO_WYSIWYG", this.IR_TO); + }, + + TO_IR : function(sContent) { + var stack = []; + + // remove xeHandled attrs + sContent = sContent.replace(/xeHandled="YES"/ig,''); + + + // remove all useless styles + /* + sContent = sContent.replace(regex_meanless_css1, function(m0,m1,m2,m3){ + m2 = m2.replace(regex_meanless_css2, ''); + + return '<'+m1+(m2?' style="'+m2+'"':'')+m3+'>'; + }); + */ + + // remove all useless classes + /* + sContent = sContent.replace(regex_class, function(m0,m1,m2,m3,m4,m5){ + var cls = jQuery.trim((m2 || m3 || m4 || "").replace(regex_class2, '')); + + return '<'+(m1||"")+(cls?' class="'+cls+'"':'')+(m5||"")+'>'; + }); + */ + + // remove all event handler + //sContent = sContent.replace(regex_handler, '<$1$2>'); + + // remove all id + //sContent = sContent.replace(regex_id, '<$1$2>'); + + // remove all scripts + //sContent = sContent.replace(regex_script, ''); + + if (jQuery.browser.msie) { + // remove jQuery attributes + sContent = sContent.replace(regex_jquery, ''); + + // quote all attrs + sContent = sContent.replace(/<(\w+) ([^>]+)>/g, function(m0,m1,m2){ + return '<'+m1+' '+ + m2.replace(regex_quote_attr, function(s0,s1,s2,s3){ + if (s1) return s1; + if(/^"/.test(s3)||/"$/.test(s3)) return s2+'='+s3; + return s2+'="'+s3+'"'; + }) + '>'; + }); + } + + // remove all useless tag and enclose tags + regex = /<(\/)?([:\w\/-]+)(.*?)>/ig; + sContent = sContent.replace(regex, function(m0,m1,m2,m3){ + var m3s = []; + var state = ''; + + m1 = m1 || ''; + m2 = m2.toLowerCase(); + m3 = $.trim(m3 || ''); + + if (!m1) { + if ($.inArray(m2,lonely_tags) >= 0) { + var len = m3.length; + if (m2 == 'br') m3 = ''; + if (!m3 || m3.substring(len-1,len) != '/') m3 += ' /'; + + return '<'+m2+' '+m3+'>'; + } + + /* + if (replace_tags[m2]) { + stack.push({tag:m2, state:'deleted'}); + + m2 = replace_tags[m2]; + state = 'inserted'; + } else if (m2 == 'font') { + stack.push({tag:m2, state:'deleted'}); + + m2 = 'span'; + m3s = []; + if (regex_font_color.test(m3)) m3s.push('color:'+(RegExp.$1||RegExp.$2||RegExp.$3)+';'); + if (regex_font_face.test(m3)) m3s.push('font-family:'+(RegExp.$1||RegExp.$2||RegExp.$3)+';'); + + m3 = m3s.length?'style="'+m3s.join('')+'"':''; + state = 'inserted'; + } else if (m2 == 'center') { + stack.push({tag:m2, state:'deleted'}); + + m2 = 'div' + m3 = 'style="text-align:center"'; + + state = 'inserted'; + } else if (m2 == 'span') { + var style = ''; + + if (!m3) { + stack.push({tag:m3, state:'deleted'}); + return ''; + } + + if (regex_style.test(m3)) { + var tmpstack = []; + var tmptag = ''; + + style = RegExp.$1||RegExp.$2||RegExp.$3; + m3 = m3.replace(regex_style, ''); + + if (regex_font_weight.test(style)) { + if (RegExp.$1 == 'bold' || RegExp.$1 == 'bolder') { + style = style.replace(regex_font_weight, ''); + tmpstack.push({tag:'strong', state:'inserted'}); + tmptag += ''; + } + } + + if (regex_font_style.test(style)) { + style = style.replace(regex_font_style, ''); + tmpstack.push({tag:'em', state:'inserted'}); + tmptag += ''; + } + + if (regex_font_decoration.test(style)) { + var deco_css = ' '+RegExp.$1.toLowerCase()+' '; + + if (deco_css.indexOf('underline ') > 0) { + deco_css = deco_css.replace('underline ', ''); + tmpstack.push({tag:'u', state:'inserted'}); + tmptag += ''; + } + + if (deco_css.indexOf('line-through ') > 0) { + deco_css = deco_css.replace('line-through ', ''); + tmpstack.push({tag:'del', state:'inserted'}); + tmptag += ''; + } + + deco_css = $.trim(deco_css); + style = style.replace(regex_font_decoration, (deco_css?'text-decoration:'+deco_css+';':'')); + } + + style = $.trim(style); + + stack.push({tag:m2, state:(!m3&&!style?'deleted':'')}); + stack = stack.concat(tmpstack); + + return (!m3&&!style?'':'')+tmptag; + } + } else { + state = (jQuery.inArray(m2,allow_tags) < 0)?'deleted':''; + if (state == 'deleted') return ''; + } + */ + + stack.push({tag:m2, state:state}); + } else { + var tags = [], t = ''; + + if (!stack.length) return ''; + + do { + t = stack.pop(); + if (t.state != 'inserted' && t.tag != m2) { + stack.push(t); + return tags.join(''); + } + if (t.state != 'deleted') tags.push(''); + } while(stack.length && t.tag != m2); + + return tags.join(''); + } + + return '<'+m1+m2+(m3?' '+m3:'')+'>'; + }); + if (stack.length) { + var t = ''; + + do { + t = stack.pop(); + if (t.state != 'deleted') sContent += ''; + } while(stack.length); + } + + return sContent; + }, + + IR_TO : function(sContent) { + return sContent; + } +}); + +// center, font, b, i, s, strike + +})(jQuery); +/** + * Support XE extensions + * @author gony + */ +xe.XE_Extension = jQuery.Class({ + name : "XE_Extension", + seq : '', + + $init : function(elAppContainer, editor_sequence) { + this.seq = editor_sequence; + this._assignHTMLObjects(elAppContainer); + }, + + _assignHTMLObjects : function(elAppContainer) { + this.elDropdownLayer = jQuery('DIV.xpress_xeditor_extension_layer', elAppContainer).get(0); + }, + + _removeAttrs : function(sContent) { + return sContent; + }, + + _addEvent : function() { + if (this.oApp.getEditingMode() != 'WYSIWYG') return; + + var doc = this.oApp.getWYSIWYGDocument(); + var seq = this.seq; + var fn = function(){ + var obj = jQuery(this); + var comp = obj.attr('editor_component'); + if (comp && jQuery.isFunction(openComponent)) { + editorPrevNode = obj.get(0); + openComponent(comp, seq); + } + }; + + jQuery('img,div[editor_component]', doc).each(function(){ + var obj = jQuery(this); + if(this.nodeName == 'IMG' && !obj.attr('editor_component')) obj.attr('editor_component','image_link') + if(!obj.attr('xeHandled')) { + obj.attr('xeHandled','YES'); + obj.dblclick(fn); + } + }); + }, + + $ON_MSG_APP_READY : function() { + this.oApp.exec('REGISTER_UI_EVENT', ['extension', 'click', 'TOGGLE_EXTENSION_LAYER']); + }, + + $ON_TOGGLE_EXTENSION_LAYER : function() { + this.oApp.exec('TOGGLE_TOOLBAR_ACTIVE_LAYER', [this.elDropdownLayer]); + }, + + $ON_CHANGE_EDITING_MODE : function(mode) { + var self = this; + setTimeout(function(){ self._addEvent(); }, 100); + }, + + $ON_PASTE_HTML : function() { + var self = this; + setTimeout(function(){ self._addEvent(); }, 100); + }, + + $ON_LOAD_IR_FIELD : function() { + var self = this; + setTimeout(function(){ self._addEvent(); }, 100); + }, + + $ON_SET_IR : function() { + var self = this; + setTimeout(function(){ self._addEvent(); }, 100); + } +}); +/** + * Auto saving + * @author gony + */ +xe.XE_AutoSave = jQuery.Class({ + name : "XE_AutoSave", + form : null, + textarea : null, + + $init : function(oIRTextarea, elAppContainer) { + this.form = oIRTextarea.form; + this.textarea = oIRTextarea; + + this._assignHTMLObjects(elAppContainer); + }, + + _assignHTMLObjects : function(elAppContainer) { + this.welMessageBox = jQuery('autosave_message'); + }, + + $ON_MSG_APP_READY : function() { + var elSrl = jQuery(this.form._saved_doc_srl); + var elTitle = jQuery(this.form._saved_doc_title); + var elContent = jQuery(this.form._saved_doc_content); + + var doc_srl = jQuery.trim(elSrl.val()); + var title = jQuery.trim(elTitle.val()); + var content = jQuery.trim(elContent.val()); + + if (title || content) { + if (confirm(this.form._saved_doc_message.value)) { + jQuery(this.form.title).val(title); + this.oApp.setIR(content); + if(typeof(editorGetAutoSavedDoc) == 'function') editorGetAutoSavedDoc(this.form); + } else { + editorRemoveSavedDoc(); + } + } + + editorEnableAutoSave(this.form, jQuery(this.form).attr("editor_sequence")); + + // register hotkey + this.oApp.exec('REGISTER_HOTKEY', ['ctrl+shift+s','AUTO_SAVE']); + }, + + $ON_AUTO_SAVE : function() { + _editorAutoSave(); + } +}); +/** + * Format Block plugin + * @author gony + */ +xe.XE_FormatWithSelectUI = jQuery.Class({ + name : "XE_FormatWithSelectUI", + + $init : function(elAppContainer){ + this._assignHTMLObjects(elAppContainer); + }, + + _assignHTMLObjects : function(elAppContainer){ + this.elFormatSelect = jQuery("SELECT.xpress_xeditor_ui_format_select", elAppContainer).get(0); + }, + + $ON_MSG_APP_READY : function(){ + this.oApp.registerBrowserEvent(this.elFormatSelect, "change", "SET_FORMAT_FROM_SELECT_UI"); + this.elFormatSelect.selectedIndex = 0; + }, + + $ON_MSG_STYLE_CHANGED : function(sAttributeName, sAttributeValue){ + var blockName = this.oApp.getWYSIWYGDocument().queryCommandValue("FormatBlock"); + + if (!blockName) return (this.elFormatSelect.selectedIndex = 0); + if (jQuery.browser.msie && /([0-9])/.test(blockName)) blockName = 'h'+(RegExp.$1); + + this.elFormatSelect.value = blockName.toLowerCase(); + if(this.elFormatSelect.selectedIndex < 0) this.elFormatSelect.selectedIndex = 0; + }, + + $ON_SET_FORMAT_FROM_SELECT_UI : function(){ + var sFormat = this.elFormatSelect.value; + if(!sFormat) return; + if(jQuery.browser.msie) sFormat = '<'+sFormat+'>'; + + this.oApp.exec("EXECCOMMAND", ["FormatBlock", false, sFormat]); + this.oApp.exec("CHECK_STYLE_CHANGE", []); + } +}); +/** + * Enhanced Table Fetures + * @author gony + */ + +// 표 편집 확장 기능 +xe.XE_Table = jQuery.Class({ + _startSel : null, + _endSel : null, + + $ON_MSG_APP_READY : function() { + this._doc = jQuery(this.oApp.getWYSIWYGDocument()); + + this.$FnMouseDown = jQuery.fnBind(this._mousedown, this); + this.$FnMouseUp = jQuery.fnBind(this._mouseup, this); + this.$FnMouseMove = jQuery.fnBind(this._mousemove, this); + + this._doc.mousedown(this.$FnMouseDown); + + // initialize + this._startSel = null; + this._endSel = null; + + // register buttons + this.oApp.exec('REGISTER_UI_EVENT', ['merge_cells', 'click', 'MERGE_CELLS']); + this.oApp.exec('REGISTER_UI_EVENT', ['split_col', 'click', 'CELL_SPLIT_BY_COL']); + this.oApp.exec('REGISTER_UI_EVENT', ['split_row', 'click', 'CELL_SPLIT_BY_ROW']); + + // register hotkeys + this.oApp.exec('REGISTER_HOTKEY', ['ctrl+alt+m', 'MERGE_CELLS']); + + // perform default ready action + this.$super.$ON_MSG_APP_READY(); + }, + + $ON_MERGE_CELLS : function() { + var html = ""; + var cell = jQuery('.xe_selected_cell', this.oApp.getWYSIWYGDocument()).filter('td,th'); + var self = this; + + // 선택된 셀이 없으면 종료 + if (!cell.length) return; + + // UNDO 지점 기록 + this.oApp.exec("RECORD_UNDO_ACTION", ["Cell:Merge"]); + + // 선택한 모든 셀의 데이터를 첫번째 셀로 복사 + cell.each(function(){ html += jQuery(this).html() }).eq(0).html(html); + + // 첫번째 셀 가로 확장 + var colspan = 0; + cell.eq(0).nextAll('td,th').andSelf().filter('.xe_selected_cell').each(function(idx){ + colspan += self._getSpan(this, 'col'); + }); + + // 마지막 셀까지 줄의 갯수 계산 + var rect = this._getRect(cell.eq(0)); + var start_tr = cell.eq(0).parent('tr'); + var end_tr = cell.eq(cell.length-1).parent('tr'); + var all_rows = cell.parents('table').eq(0).find('tr'); + var rowspan = all_rows.index(end_tr.get(0)) - all_rows.index(start_tr.get(0)) + this._getSpan(cell.eq(cell.length-1), 'row'); + + // 첫번째 셀 colspan, rowspan 속성 지정 + cell.eq(0).attr('colSpan', colspan).attr('rowSpan', rowspan); + + // 첫번째 셀을 제외한 다른 모든 셀 제거 + cell.slice(1).remove(); + }, + + $ON_CELL_SPLIT_BY_ROW : function(many) { + var cell = jQuery('.xe_selected_cell', this.oApp.getWYSIWYGDocument()).filter('td,th'); + var table = cell.parents('table').eq(0); + var self = this; + + // 선택된 셀이 없으면 종료 + if (!cell.length) return; + + // UNDO 지점 기록 + this.oApp.exec("RECORD_UNDO_ACTION", ["Cell:Split By Row"]); + + // 선택 영역의 상하 좌표 구함 + var _top = this._getRect(cell.eq(0)).top; + var _bottom = this._getRect(cell.eq(cell.length-1)).bottom; + + // 테이블의 모든 셀에서 선택영역에 해당하는 셀을 구한다(상하 기준). + (cell = table.find('td,th').filter(function(){ + var rect = self._getRect(jQuery(this)); + + return !(rect.bottom <= _top || rect.top >= _bottom); + })).filter('.xe_selected_cell').each(function(){ + var t = jQuery(this); + var row = t.parent('tr'); + var rowspan = self._getSpan(t, 'row'); + var rect = self._getRect(t); + var queue = []; + var clone = t.clone().html('
'); + var topspan = 1, botspan = 1; + + // rowspan > 1이면 현재 셀의 rowspan을 절반으로 분할한다. + if (rowspan > 1) { + + topspan = Math.ceil(rowspan/2); + botspan = rowspan - topspan; + + queue.push(function(){ + t.attr('rowSpan', topspan); + }); + + clone.attr('rowSpan', botspan); + } else { + // rowspan이 없으면 현재 셀과 영역이 겹치는 모든 셀에 rowspan을 추가 + cell.filter(function(){ + if (t.get(0) == this) return false; + + var tt = jQuery(this); + var rc = self._getRect(tt); + + // 범위를 넘은 부분은 제외 + if (rc.bottom <= rect.top || rc.top >= rect.bottom) return false; + + return true; + }).each(function(){ + var tt = jQuery(this); + var sp = self._getSpan(tt, 'row')+1; + + // rowspan 1 추가 + queue.push(function(){ + tt.attr('rowSpan', sp); + }); + }); + + // 새 줄을 추가한다. + if (jQuery.browser.msie) { + // Fix bug for IE + row.after(row.clone().empty().get(0).outerHTML); + } else { + row.after(row.clone().empty()); + } + } + + var rows = row.nextAll('tr'); + + // 현재 셀이 마지막 줄에 있다면 한 줄 추가 후 새로운 셀 추가 + if (!rows.length) { + row.after(row.clone().empty().append(clone)); + } else { + var next_sib = rows.eq(topspan - 1).children('td,th').filter(function(){ + return ( self._getRect(jQuery(this)).left > rect.left ); + }); + + if (jQuery.browser.msie) { + next_sib.length? + next_sib.eq(0).before(clone.get(0).outerHTML): + rows.eq(topspan-1).append(clone.get(0).outerHTML); + } else { + next_sib.length? + next_sib.slice(0,1).before(clone): + rows.slice(topspan-1,1).append(clone); + } + } + + // 함수를 바로 실행하면 좌표가 틀어지므로, 큐에 넣은 후 실행 + jQuery.each(queue, function(){ this(); }); + + }); + }, + + $ON_CELL_SPLIT_BY_COL : function(many) { + var cell = jQuery('.xe_selected_cell', this.oApp.getWYSIWYGDocument()).filter('td,th'); + var table = cell.parents('table').slice(0,1); + var self = this; + var ie_bug = [], tmpId = (new Date).getTime(), tmpStr = ''; + + // 선택된 셀이 없으면 종료 + if (!cell.length) return; + + // UNDO 지점 기록 + this.oApp.exec("RECORD_UNDO_ACTION", ["Cell:Split By Column"]); + + // 선택 영역의 좌우 좌표 구함 + var first_row = cell.eq(0).parent('tr'); + var _left = this._getRect(first_row.find('.xe_selected_cell:first')).left; + var _right = this._getRect(first_row.find('.xe_selected_cell:last')).right; + + // 테이블의 모든 셀에서 선택영역에 해당하는 셀을 구한다(좌우 기준). + (cell = table.find('td,th').filter(function(){ + var rect = self._getRect(jQuery(this)); + + return !(rect.right <= _left || rect.left >= _right); + })).filter('.xe_selected_cell').each(function(idx){ + var t = jQuery(this); + var colspan = self._getSpan(t, 'col'); + var clone = t.clone().html('
'); + + // colspan > 1 이면 colspan을 절반으로 분할한다. + if (colspan > 1) { + var leftspan = Math.ceil(colspan/2); + var rightspan = colspan - leftspan; + + t.attr('colSpan', leftspan); + clone.attr('colSpan', rightspan); + } else { + // colspan이 없으면 현재 셀과 영역이 겹치는 모든 셀에 colspan을 추가 + var rect = self._getRect(t); + + cell.filter(function(){ + if (t.get(0) == this) return false; + + var tt = jQuery(this); + var rc = self._getRect(tt); + + // 범위를 넘은 부분은 제외 + if (rc.right <= rect.left || rc.left >= rect.right) return false; + + return true; + }).each(function(){ + var tt = jQuery(this); + + // colspan 1 추가 + tt.attr('colSpan', self._getSpan(tt, 'col')+1); + }); + + clone.attr('colSpan', 1); + } + + if (jQuery.browser.msie) { + // Fix for IE bug + t.after(clone.get(0).outerHTML); + } else { + t.after(clone); + } + }); + }, + + $ON_CHECK_STYLE_CHANGE : function(){ + var ui = ['merge_cells', 'split_col', 'split_row']; + var app = this.oApp; + var command = (this._startSel && this._startSel.is('.xe_selected_cell'))?'ENABLE_UI':'DISABLE_UI'; + + jQuery.each(ui, function(){ app.exec(command, [this]); }); + }, + + _mousedown : function(event) { + var cur = jQuery(event.target); + var sel = cur.parents().andSelf().filter('td,th,table'); + var app = this.oApp; + var self = this; + + // 모든 선택영역 해제 + jQuery('td.xe_selected_cell', this.oApp.getWYSIWYGDocument()).removeClass('xe_selected_cell'); + + this._startSel = null; + this._endSel = null; + + if (!sel.length || !this._isLeftClicked(event.button)) return; + + function delayed(){ + sel = app.getSelection().cloneRange(); + sel.collapseToStart(); + sel = jQuery(sel.startContainer).parents().andSelf().filter('td,th').eq(0); + + if (!sel.length) return self._removeAllListener()||true; + + // 좌표를 구한다 + self._getRect(self._startSel = sel); + + // 이벤트 바인딩 + self._doc.bind('mousemove', self.$FnMouseMove); + self._doc.bind('mouseup', self.$FnMouseUp); + } + + // mousedown이 일어난 후에 선택 영역이 설정되므로 실행을 지연시킨다. + setTimeout(delayed, 0); + }, + + _mouseup : function(event) { + // 선택된 셀 확인 + this._removeAllListener(); + + // 시작셀과 종료셀 제거 + this._startSel = this._endSel = null; + }, + + _mousemove : function(event) { + var cur = jQuery(event.target); + var cell = cur.parents().andSelf().filter('td,th').eq(0); + var self = this; + + // 마우스 왼쪽 버튼이 눌리지 않았으면 종료 + if (!cell.length || !this._isLeftClicked(event.button)) return; + if (!this._endSel && cell.get(0) == this._startSel.get(0)) return; + if (this._endSel && cell.get(0) == this._endSel.get(0)) return; + + // 종료셀 && 종료셀의 좌표 + this._getRect(this._endSel = cell); + + // 선택 범위를 구한다 + var _top = Math.min(this._startSel.rect.top, this._endSel.rect.top); + var _left = Math.min(this._startSel.rect.left, this._endSel.rect.left); + var _bottom = Math.max(this._startSel.rect.bottom, this._endSel.rect.bottom); + var _right = Math.max(this._startSel.rect.right, this._endSel.rect.right); + + var table = cell.parents('table'); + var cells = table.find('td,th').removeClass('xe_selected_cell'); + var i = 0; + + // 복잡한 모양의 테이블을 위한 반복 처리 + var selected = jQuery(); + do { + // 선택한 셀로 최대 영역 재계산 + selected.each(function(){ + var rect = self._getRect(jQuery(this)); + + // 영역 재계산 + if (rect.right > _right) _right = rect.right; + if (rect.left < _left) _left = rect.left; + if (rect.top < _top) _top = rect.top; + if (rect.bottom > _bottom) _bottom = rect.bottom; + }); + + // 좌표 범위 안에 있는 선택할 셀을 추린다. + cells = cells.filter(':not(.xe_selected_cell)'); + selected = cells.filter(function(){ + var rect = self._getRect(jQuery(this)); + + if (rect.right <= _left || rect.left >= _right || rect.bottom <= _top || rect.top >= _bottom) return false; + + return true; + }).addClass('xe_selected_cell'); + } while(selected.length); + + // 브라우저의 기본 선택영역 해제 : FF 제외 - 기본 기능이 충분히 좋아서 + 이 부분을 실행하면 오류가 발생해서 + if (!jQuery.browser.mozilla) { + function delayed() { + var sel = self.oApp.getSelection(); + + if (!self._startSel) return; + if (!self._startSel.get(0).firstChild) self._startSel.text(" "); + + sel.selectNode(self._startSel.get(0).firstChild); + sel.collapseToStart(); + sel.select(); + } + + setTimeout(delayed, 0); + } + + return false; + }, + + _removeAllListener : function() { + // 이벤트 해제 + this._doc.unbind("mousemove", this.$FnMouseMove); + this._doc.unbind("mouseup", this.$FnMouseUp); + }, + + _isLeftClicked : function(value) { + return jQuery.browser.msie?!!(value & 1):(value == 0); + }, + + _getRect : function(obj) { + var el = obj.get(0); + + obj.rect = {}; + obj.rect.top = el.offsetTop; + obj.rect.left = el.offsetLeft; + obj.rect.bottom = obj.rect.top + el.offsetHeight; + obj.rect.right = obj.rect.left + el.offsetWidth; + + return obj.rect; + }, + + _getSpan : function(obj, type) { + var span = parseInt(jQuery(obj).attr(type+'span')); + + return isNaN(span)?1:span; + } +}).extend(xe.XE_Table); diff --git a/modules/editor/skins/xpresseditor/js/xe_interface.js b/modules/editor/skins/xpresseditor/js/xe_interface.js index 07948db08..bf808322b 100644 --- a/modules/editor/skins/xpresseditor/js/xe_interface.js +++ b/modules/editor/skins/xpresseditor/js/xe_interface.js @@ -1,273 +1,293 @@ -if (!window.xe) xe = {}; - -xe.Editors = []; - -function editorStart_xe(editor_sequence, primary_key, content_key, editor_height, colorset, content_style, content_font) { - if(typeof(colorset)=='undefined') colorset = 'white'; - if(typeof(content_style)=='undefined') content_style = 'xeStyle'; - if(typeof(content_font)=='undefined') content_font= ''; - - var target_src = request_uri+'modules/editor/styles/'+content_style+'/editor.html'; - - var textarea = jQuery("#xpress-editor-"+editor_sequence); - var iframe = jQuery('