From b0ec2d7b4b6a352052f64d98d124d256c691e65b Mon Sep 17 00:00:00 2001 From: haojilin Date: Tue, 20 Nov 2007 06:33:32 +0000 Subject: [PATCH 001/265] =?UTF-8?q?=EC=A4=91=EA=B5=AD=EC=96=B4=20-=20?= =?UTF-8?q?=ED=8F=AC=EC=9D=B8=ED=8A=B8=20=EB=AA=A8=EB=93=88=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=EB=B6=80=EB=B6=84=20=EB=B2=88=EC=97=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3024 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/point/lang/zh-CN.lang.php | 104 +++++++++++++++--------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/modules/point/lang/zh-CN.lang.php b/modules/point/lang/zh-CN.lang.php index 5c977a4ed..4a4b8b07c 100644 --- a/modules/point/lang/zh-CN.lang.php +++ b/modules/point/lang/zh-CN.lang.php @@ -1,52 +1,52 @@ - - * @brief 积分 (point) 模块简体中文语言包 - **/ - - $lang->point = "积分"; - $lang->level = "级别"; - - $lang->about_point_module = "积分系统可以在发表/删除新帖,发表/删除评论,上传/下载/删除/文件等动作时,付与其相应的积分。
积分系统模块只能设置各项积分,不能记录积分。只有激活积分插件后才可以正常记录相关积分。"; - $lang->about_act_config = "版面,博客等模块都有发表/删除新帖,发表/删除评论等动作。
要想与版面/博客之外的模块关联积分功能时,添加与其各模块功能相适合的act值即可。"; - - $lang->max_level = '最高级别'; - $lang->about_max_level = '可以指定最高级别。级别共设1000级,因此制作级别图标时要好好考虑一下。'; - - $lang->level_icon = '级别图标'; - $lang->about_level_icon = '级别图标要以 ./modules/point/icons/级别.gif形式指定,有时出现最高级别的图标跟您指定的最高级别图标不同的现象,敬请注意。'; - - $lang->point_name = '积分名'; - $lang->about_point_name = '可以指定积分名或积分单位。'; - - $lang->level_point = '级别积分'; - $lang->about_level_point = '积分达到或减少到下列各级别所设置的积分值时,将会自动调节相应级别。'; - - $lang->disable_download = '禁止下载'; - $lang->about_disable_download = '没有积分时,将禁止下载。 (图片除外)'; - - $lang->level_point_calc = '레벨별 포인트 계산'; - $lang->expression = '레벨 변수 i를 사용하여 자바스크립트 수식을 입력하세요. 예: Math.pow(i, 2) * 90'; - $lang->cmd_exp_calc = '계산'; - $lang->cmd_exp_reset = '초기화'; - - $lang->about_module_point = '可以分别对各模块进行积分设置,没有被设置的模块将使用默认值。
所有积分在相反动作下恢复原始值。即:发表新帖后再删除得到的积分为0分。'; - - $lang->point_signup = '注册'; - $lang->point_insert_document = '发表新帖'; - $lang->point_delete_document = '删除主题'; - $lang->point_insert_comment = '发表评论'; - $lang->point_delete_comment = '删除评论'; - $lang->point_upload_file = '上传文件'; - $lang->point_delete_file = '删除文件'; - $lang->point_download_file = '下载文件 (图片除外)'; - - - $lang->cmd_point_config = '基本设置'; - $lang->cmd_point_module_config = '对象模块设置'; - $lang->cmd_point_act_config = '功能act设置'; - $lang->cmd_point_member_list = '会员积分目录'; - - $lang->msg_cannot_download = '积分不足无法下载!'; -?> + + * @brief 积分 (point) 模块简体中文语言包 + **/ + + $lang->point = "积分"; + $lang->level = "级别"; + + $lang->about_point_module = "积分系统可以在发表/删除新帖,发表/删除评论,上传/下载/删除/文件等动作时,付与其相应的积分。
积分系统模块只能设置各项积分,不能记录积分。只有激活积分插件后才可以正常记录相关积分。"; + $lang->about_act_config = "版面,博客等模块都有发表/删除新帖,发表/删除评论等动作。
要想与版面/博客之外的模块关联积分功能时,添加与其各模块功能相适合的act值即可。"; + + $lang->max_level = '最高级别'; + $lang->about_max_level = '可以指定最高级别。级别共设1000级,因此制作级别图标时要好好考虑一下。'; + + $lang->level_icon = '级别图标'; + $lang->about_level_icon = '级别图标要以 ./modules/point/icons/级别.gif形式指定,有时出现最高级别的图标跟您指定的最高级别图标不同的现象,敬请注意。'; + + $lang->point_name = '积分名'; + $lang->about_point_name = '可以指定积分名或积分单位。'; + + $lang->level_point = '级别积分'; + $lang->about_level_point = '积分达到或减少到下列各级别所设置的积分值时,将会自动调节相应级别。'; + + $lang->disable_download = '禁止下载'; + $lang->about_disable_download = '没有积分时,将禁止下载。 (图片除外)'; + + $lang->level_point_calc = '等级别积分计算'; + $lang->expression = '使用等级变数 i输入Javascrīpt代码. 例: Math.pow(i, 2) * 90'; + $lang->cmd_exp_calc = '计算'; + $lang->cmd_exp_reset = '初期化'; + + $lang->about_module_point = '可以分别对各模块进行积分设置,没有被设置的模块将使用默认值。
所有积分在相反动作下恢复原始值。即:发表新帖后再删除得到的积分为0分。'; + + $lang->point_signup = '注册'; + $lang->point_insert_document = '发表新帖'; + $lang->point_delete_document = '删除主题'; + $lang->point_insert_comment = '发表评论'; + $lang->point_delete_comment = '删除评论'; + $lang->point_upload_file = '上传文件'; + $lang->point_delete_file = '删除文件'; + $lang->point_download_file = '下载文件 (图片除外)'; + + + $lang->cmd_point_config = '基本设置'; + $lang->cmd_point_module_config = '对象模块设置'; + $lang->cmd_point_act_config = '功能act设置'; + $lang->cmd_point_member_list = '会员积分目录'; + + $lang->msg_cannot_download = '积分不足无法下载!'; +?> From 877d230c95b1300f987989d2f700e39e85db0594 Mon Sep 17 00:00:00 2001 From: zero Date: Tue, 20 Nov 2007 06:49:39 +0000 Subject: [PATCH 002/265] =?UTF-8?q?=C3=AC=C2=B5=C2=9C=C3=AA=C2=B7=C2=BC=20?= =?UTF-8?q?=C3=AB=C2=8C=C2=93=C3=AA=C2=B8=C2=80=20=C3=AC=C2=B6=C2=9C=C3=AB?= =?UTF-8?q?=C2=A0=C2=A5=C3=AC=C2=8B=C2=9C=20=C3=AD=C2=95=C2=B4=C3=AB=C2=8B?= =?UTF-8?q?=C2=B9=20=C3=AB=C2=8C=C2=93=C3=AA=C2=B8=C2=80=C3=AC=C2=97=C2=90?= =?UTF-8?q?=20=C3=AA=C2=B6=C2=8C=C3=AD=C2=95=C2=9C=C3=AC=C2=9D=C2=84=20?= =?UTF-8?q?=C3=AC=C2=A3=C2=BC=C3=AC=C2=96=C2=B4=20=C3=AB=C2=B2=C2=84=C3=AB?= =?UTF-8?q?=C2=A6=C2=AC=C3=AB=C2=8D=C2=98=20=C3=AB=C2=AC=C2=B8=C3=AC=C2=A0?= =?UTF-8?q?=C2=9C=20=C3=AC=C2=88=C2=98=C3=AC=C2=A0=C2=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3025 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/comment/comment.model.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/comment/comment.model.php b/modules/comment/comment.model.php index 8497271c9..6826ff30d 100644 --- a/modules/comment/comment.model.php +++ b/modules/comment/comment.model.php @@ -147,7 +147,6 @@ $oComment = null; $oComment = new commentItem(); $oComment->setAttribute($attribute); - $oComment->setGrant(); $result[$key] = $oComment; } @@ -191,7 +190,7 @@ if(!$comment_srl) continue; - if($is_admin || $this->isGranted($comment_srl) || $member_srl == $logged_info->member_srl) $source_list[$i]->is_granted = true; + //if($is_admin || $this->isGranted($comment_srl) || $member_srl == $logged_info->member_srl) $source_list[$i]->is_granted = true; // 목록을 만듬 $list[$comment_srl] = $source_list[$i]; From 69c15ee1f010781ccb2874120762bf061ec2e9a1 Mon Sep 17 00:00:00 2001 From: zero Date: Tue, 20 Nov 2007 07:12:23 +0000 Subject: [PATCH 003/265] =?UTF-8?q?=C3=AB=C2=B8=C2=94=C3=AB=C2=A1=C2=9C?= =?UTF-8?q?=C3=AA=C2=B7=C2=B8=C3=AB=C2=AA=C2=A8=C3=AB=C2=93=C2=88=C3=AC?= =?UTF-8?q?=C2=97=C2=90=C3=AC=C2=84=C2=9C=20=C3=AD=C2=8A=C2=B9=C3=AC=C2=A0?= =?UTF-8?q?=C2=95=20=C3=AA=C2=B8=C2=80=C3=AC=C2=9D=C2=B4=20=C3=AD=C2=98?= =?UTF-8?q?=C2=B8=C3=AC=C2=B6=C2=9C=C3=AB=C2=90=C2=A0=20=C3=AA=C2=B2=C2=BD?= =?UTF-8?q?=C3=AC=C2=9A=C2=B0=20=C3=AB=C2=AA=C2=A9=C3=AB=C2=A1=C2=9D=20?= =?UTF-8?q?=C3=AC=C2=B2=C2=98=C3=AB=C2=A6=C2=AC=C3=AB=C2=A5=C2=BC=20=C3=AD?= =?UTF-8?q?=C2=95=C2=98=C3=AC=C2=A7=C2=80=20=C3=AC=C2=95=C2=8A=C3=AA=C2=B3?= =?UTF-8?q?=C2=A0=20=C3=AD=C2=95=C2=B4=C3=AB=C2=8B=C2=B9=20=C3=AA=C2=B8?= =?UTF-8?q?=C2=80=C3=AB=C2=A7=C2=8C=20=C3=AB=C2=B3=C2=B4=C3=AC=C2=9D=C2=B4?= =?UTF-8?q?=C3=AB=C2=8F=C2=84=C3=AB=C2=A1=C2=9D=20=C3=AD=C2=95=C2=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3026 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/blog/blog.view.php | 91 ++++++++++++++-------------- modules/blog/skins/xe_blog/list.html | 13 ++-- 2 files changed, 53 insertions(+), 51 deletions(-) diff --git a/modules/blog/blog.view.php b/modules/blog/blog.view.php index a2bf7f0f8..11eb3ba34 100644 --- a/modules/blog/blog.view.php +++ b/modules/blog/blog.view.php @@ -88,7 +88,7 @@ $oDocument = $oDocumentModel->getDocument(0, $this->grant->manager); - // document_srl이 있다면 해당 글을 구해오자 + // document_srl이 있다면 해당 글만 출력 if($this->grant->list && $document_srl) { // 글을 구함 @@ -109,70 +109,67 @@ // 조회수 증가 $oDocument->updateReadedCount(); - // 목록수를 1개로 수정 (글이 선택되었을 때만) - $this->list_count = 1; + // 카테고리 설정 + Context::set('category', $oDocument->get('category_srl')); - // 페이지 변수를 제거하여 직접 구하도록 변경 - unset($page); + // comment editor 생성/ 세팅 + $comment_editor[$oDocument->document_srl] = $this->getCommentEditor($oDocument->document_srl, 0, 100); + Context::set('comment_editor', $comment_editor); } - } Context::set('oDocument', $oDocument); - // 만약 document_srl은 있는데 page가 없다면 글만 호출된 경우 page를 구해서 세팅해주자.. - if($document_srl && !$page) { - $page = $oDocumentModel->getDocumentPage($document_srl, $this->module_srl, $this->list_count); - Context::set('page', $page); - } + // document_srl이 없다면 정해진데로 목록을 구함 + if(!$oDocument->isExists()) { + // 목록을 구하기 위한 옵션 + $args->module_srl = $this->module_srl; ///< 현재 모듈의 module_srl + $args->page = $page; ///< 페이지 + $args->list_count = $this->list_count; ///< 한페이지에 보여줄 글 수 + $args->page_count = $this->page_count; ///< 페이지 네비게이션에 나타날 페이지의 수 - // 목록을 구하기 위한 옵션 - $args->module_srl = $this->module_srl; ///< 현재 모듈의 module_srl - $args->page = $page; ///< 페이지 - $args->list_count = $this->list_count; ///< 한페이지에 보여줄 글 수 - $args->page_count = $this->page_count; ///< 페이지 네비게이션에 나타날 페이지의 수 + // 검색 옵션 + $args->search_target = trim(Context::get('search_target')); ///< 검색대상 + $args->search_keyword = trim(Context::get('search_keyword')); ///< 검색어 - // 검색 옵션 - $args->search_target = trim(Context::get('search_target')); ///< 검색대상 - $args->search_keyword = trim(Context::get('search_keyword')); ///< 검색어 + // 키워드 검색이 아닌 검색일 경우 목록의 수를 40개로 고정 + if($args->search_target && $args->search_keyword) $args->list_count = 40; - // 키워드 검색이 아닌 검색일 경우 목록의 수를 40개로 고정 - if($args->search_target && $args->search_keyword) $args->list_count = 40; + // 키워드 검색의 경우 제목,내용으로 검색 대상 고정 + if($args->search_keyword && !$args->search_target) $args->search_target = "title_content"; - // 키워드 검색의 경우 제목,내용으로 검색 대상 고정 - if($args->search_keyword && !$args->search_target) $args->search_target = "title_content"; + // 블로그 카테고리 + $args->category_srl = (int)Context::get('category'); - // 블로그 카테고리 - $args->category_srl = (int)Context::get('category'); + $args->sort_index = 'list_order'; ///< 소팅 값 - $args->sort_index = 'list_order'; ///< 소팅 값 + // 목록 구함, document->getDocumentList 에서 걍 알아서 다 해버리는 구조 + $output = $oDocumentModel->getDocumentList($args, true); - // 목록 구함, document->getDocumentList 에서 걍 알아서 다 해버리는 구조 - $output = $oDocumentModel->getDocumentList($args, true); + // 템플릿에 쓰기 위해서 document_model::getDocumentList() 의 return object에 있는 값들을 세팅 + Context::set('total_count', $output->total_count); + Context::set('total_page', $output->total_page); + Context::set('page', $output->page); + Context::set('document_list', $output->data); + Context::set('page_navigation', $output->page_navigation); - // 템플릿에 쓰기 위해서 document_model::getDocumentList() 의 return object에 있는 값들을 세팅 - Context::set('total_count', $output->total_count); - Context::set('total_page', $output->total_page); - Context::set('page', $output->page); - Context::set('document_list', $output->data); - Context::set('page_navigation', $output->page_navigation); - - // 문서 갯수만큼 comment editor 생성 - if(count($output->data)) { - foreach($output->data as $obj) { - $comment_editor[$obj->document_srl] = $this->getCommentEditor($obj->document_srl, 0, 100); + // 문서 갯수만큼 comment editor 생성 + if(count($output->data)) { + foreach($output->data as $obj) { + $comment_editor[$obj->document_srl] = $this->getCommentEditor($obj->document_srl, 0, 100); + } } - } - // 에디터 세팅 - Context::set('comment_editor', $comment_editor); + // 에디터 세팅 + Context::set('comment_editor', $comment_editor); - // 템플릿에서 사용할 검색옵션 세팅 - $count_search_option = count($this->search_option); - for($i=0;$i<$count_search_option;$i++) { - $search_option[$this->search_option[$i]] = Context::getLang($this->search_option[$i]); + // 템플릿에서 사용할 검색옵션 세팅 + $count_search_option = count($this->search_option); + for($i=0;$i<$count_search_option;$i++) { + $search_option[$this->search_option[$i]] = Context::getLang($this->search_option[$i]); + } + Context::set('search_option', $search_option); } - Context::set('search_option', $search_option); // 블로그의 코멘트는 ajax로 호출되기에 미리 css, js파일을 import Context::addJsFile('./modules/editor/tpl/js/editor.js'); diff --git a/modules/blog/skins/xe_blog/list.html b/modules/blog/skins/xe_blog/list.html index 5cec3afe5..dd99e17d4 100644 --- a/modules/blog/skins/xe_blog/list.html +++ b/modules/blog/skins/xe_blog/list.html @@ -1,6 +1,11 @@ - + + + + + + @@ -11,10 +16,8 @@ - - - + + + From e5c4395eb5a2eaf29b088506ec860a3684eeeb59 Mon Sep 17 00:00:00 2001 From: haneul Date: Tue, 20 Nov 2007 08:44:49 +0000 Subject: [PATCH 004/265] Add Russian (by X-[Vr]bL1s5) git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3027 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- .htaccess | 38 +- addons/member_extra_info/lang/ru.lang.php | 9 + common/lang/lang.info | 1 + common/lang/ru.lang.php | 235 +++++++++++++ modules/addon/lang/ru.lang.php | 15 + modules/admin/lang/ru.lang.php | 88 +++++ modules/blog/lang/ru.lang.php | 33 ++ modules/board/lang/ru.lang.php | 16 + modules/comment/lang/ru.lang.php | 27 ++ modules/counter/lang/ru.lang.php | 22 ++ modules/document/lang/ru.lang.php | 50 +++ modules/editor/lang/ru.lang.php | 85 +++++ modules/file/lang/ru.lang.php | 41 +++ modules/guestbook/lang/ru.lang.php | 16 + modules/importer/lang/ru.lang.php | 52 +++ modules/install/lang/ru.lang.php | 367 ++++++++++++++++++++ modules/integration_search/lang/ru.lang.php | 31 ++ modules/krzip/lang/ru.lang.php | 22 ++ modules/layout/lang/ru.lang.php | 32 ++ modules/member/lang/ru.lang.php | 197 +++++++++++ modules/menu/lang/ru.lang.php | 51 +++ modules/message/lang/ru.lang.php | 10 + modules/module/lang/ru.lang.php | 61 ++++ modules/opage/lang/ru.lang.php | 15 + modules/page/lang/ru.lang.php | 11 + modules/point/lang/ru.lang.php | 47 +++ modules/poll/lang/ru.lang.php | 38 ++ modules/rss/lang/ru.lang.php | 25 ++ modules/spamfilter/lang/ru.lang.php | 32 ++ modules/trackback/lang/ru.lang.php | 24 ++ modules/ttimporter/lang/ru.lang.php | 21 ++ modules/widget/lang/ru.lang.php | 43 +++ 32 files changed, 1736 insertions(+), 19 deletions(-) create mode 100644 addons/member_extra_info/lang/ru.lang.php create mode 100644 common/lang/ru.lang.php create mode 100644 modules/addon/lang/ru.lang.php create mode 100644 modules/admin/lang/ru.lang.php create mode 100644 modules/blog/lang/ru.lang.php create mode 100644 modules/board/lang/ru.lang.php create mode 100644 modules/comment/lang/ru.lang.php create mode 100644 modules/counter/lang/ru.lang.php create mode 100644 modules/document/lang/ru.lang.php create mode 100644 modules/editor/lang/ru.lang.php create mode 100644 modules/file/lang/ru.lang.php create mode 100644 modules/guestbook/lang/ru.lang.php create mode 100644 modules/importer/lang/ru.lang.php create mode 100644 modules/install/lang/ru.lang.php create mode 100644 modules/integration_search/lang/ru.lang.php create mode 100644 modules/krzip/lang/ru.lang.php create mode 100644 modules/layout/lang/ru.lang.php create mode 100644 modules/member/lang/ru.lang.php create mode 100644 modules/menu/lang/ru.lang.php create mode 100644 modules/message/lang/ru.lang.php create mode 100644 modules/module/lang/ru.lang.php create mode 100644 modules/opage/lang/ru.lang.php create mode 100644 modules/page/lang/ru.lang.php create mode 100644 modules/point/lang/ru.lang.php create mode 100644 modules/poll/lang/ru.lang.php create mode 100644 modules/rss/lang/ru.lang.php create mode 100644 modules/spamfilter/lang/ru.lang.php create mode 100644 modules/trackback/lang/ru.lang.php create mode 100644 modules/ttimporter/lang/ru.lang.php create mode 100644 modules/widget/lang/ru.lang.php diff --git a/.htaccess b/.htaccess index 04b152121..a64a94bdc 100644 --- a/.htaccess +++ b/.htaccess @@ -6,54 +6,54 @@ RewriteRule ^([a-zA-Z0-9_]+)/modules/(.*) ./modules/$2 [L] RewriteRule ^([a-zA-Z0-9_]+)/common/(.*) ./common/$2 [L] # page -RewriteRule ^([a-zA-Z0-9_]+)/([[:digit:]]+)page$ ./index.php?mid=$1&page=$2 [L] +RewriteRule ^([a-zA-Z0-9_]+)/([[:digit:]]+)page$ /~syhan/zbxe/index.php?mid=$1&page=$2 [L] # total rss -RewriteRule ^rss/([[:digit:]]+){0,14}/([[:digit:]]+){0,14}/([[:digit:]]+)$ ./index.php?module=rss&act=rss&start_date=$1&end_date=$2&page=$3 [L] -RewriteRule ^rss/([[:digit:]]+)$ ./index.php?module=rss&act=rss&page=$1 [L] -RewriteRule ^rss$ ./index.php?module=rss&act=rss [L] +RewriteRule ^rss/([[:digit:]]+){0,14}/([[:digit:]]+){0,14}/([[:digit:]]+)$ /~syhan/zbxe/index.php?module=rss&act=rss&start_date=$1&end_date=$2&page=$3 [L] +RewriteRule ^rss/([[:digit:]]+)$ /~syhan/zbxe/index.php?module=rss&act=rss&page=$1 [L] +RewriteRule ^rss$ /~syhan/zbxe/index.php?module=rss&act=rss [L] # administrator page -RewriteRule ^admin$ ./index.php?module=admin [L] +RewriteRule ^admin$ /~syhan/zbxe/index.php?module=admin [L] # mid + act -RewriteRule ^([a-zA-Z0-9_]+)/api$ ./index.php?mid=$1&act=api [L] +RewriteRule ^([a-zA-Z0-9_]+)/api$ /~syhan/zbxe/index.php?mid=$1&act=api [L] # document permanent link -RewriteRule ^([[:digit:]]+)$ ./index.php?document_srl=$1 [L] +RewriteRule ^([[:digit:]]+)$ /~syhan/zbxe/index.php?document_srl=$1 [L] # document + act link -RewriteRule ^([[:digit:]]+)/([a-zA-Z0-9_]+)$ ./index.php?document_srl=$1&act=$2 [L] +RewriteRule ^([[:digit:]]+)/([a-zA-Z0-9_]+)$ /~syhan/zbxe/index.php?document_srl=$1&act=$2 [L] # mid + document link -RewriteRule ^([a-zA-Z0-9_]+)/([[:digit:]]+)$ ./index.php?mid=$1&document_srl=$2 [L] +RewriteRule ^([a-zA-Z0-9_]+)/([[:digit:]]+)$ /~syhan/zbxe/index.php?mid=$1&document_srl=$2 [L] # mid + act link -RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)$ ./index.php?mid=$1&act=$2 [L] +RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)$ /~syhan/zbxe/index.php?mid=$1&act=$2 [L] # mid + page link -RewriteRule ^([a-zA-Z0-9_]+)/page/([[:digit:]]+)$ ./index.php?mid=$1&page=$2 [L] +RewriteRule ^([a-zA-Z0-9_]+)/page/([[:digit:]]+)$ /~syhan/zbxe/index.php?mid=$1&page=$2 [L] # mid + category link -RewriteRule ^([a-zA-Z0-9_]+)/category/([[:digit:]]+)$ ./index.php?mid=$1&category=$2 [L] +RewriteRule ^([a-zA-Z0-9_]+)/category/([[:digit:]]+)$ /~syhan/zbxe/index.php?mid=$1&category=$2 [L] # mid + category + page -RewriteRule ^([a-zA-Z0-9_]+)/category/([[:digit:]]+)/page/([[:digit:]]+)$ ./index.php?mid=$1&category=$2&page=$3 [L] +RewriteRule ^([a-zA-Z0-9_]+)/category/([[:digit:]]+)/page/([[:digit:]]+)$ /~syhan/zbxe/index.php?mid=$1&category=$2&page=$3 [L] # mid + search target regdate (year+month) -RewriteRule ^([a-zA-Z0-9_]+)/([[:digit:]]+)/([[:digit:]]+)$ ./index.php?mid=$1&search_target=regdate&search_keyword=$2$3 [L] +RewriteRule ^([a-zA-Z0-9_]+)/([[:digit:]]+)/([[:digit:]]+)$ /~syhan/zbxe/index.php?mid=$1&search_target=regdate&search_keyword=$2$3 [L] # mid + search target regdate (year+month+day) -RewriteRule ^([a-zA-Z0-9_]+)/([[:digit:]]+)/([[:digit:]]+)/([[:digit:]]+)$ ./index.php?mid=$1&search_target=regdate&search_keyword=$2$3$4 [L] +RewriteRule ^([a-zA-Z0-9_]+)/([[:digit:]]+)/([[:digit:]]+)/([[:digit:]]+)$ /~syhan/zbxe/index.php?mid=$1&search_target=regdate&search_keyword=$2$3$4 [L] # mid + search target tag -RewriteRule ^([a-zA-Z0-9_]+)/tag/(.*)$ ./index.php?mid=$1&search_target=tag&search_keyword=$2 [L] +RewriteRule ^([a-zA-Z0-9_]+)/tag/(.*)$ /~syhan/zbxe/index.php?mid=$1&search_target=tag&search_keyword=$2 [L] # mid + search target writer -RewriteRule ^([a-zA-Z0-9_]+)/writer/(.*)$ ./index.php?mid=$1&search_target=nick_name&search_keyword=$2 [L] +RewriteRule ^([a-zA-Z0-9_]+)/writer/(.*)$ /~syhan/zbxe/index.php?mid=$1&search_target=nick_name&search_keyword=$2 [L] # module link -RewriteRule ^([a-zA-Z0-9_]+)(/){0,1}$ ./index.php?mid=$1 [L] +RewriteRule ^([a-zA-Z0-9_]+)(/){0,1}$ /~syhan/zbxe/index.php?mid=$1 [L] # css/img/js/htc등의 경로 처리 -RewriteRule ^(.+)/common/js/iePngFix.htc ./common/js/iePngFix.htc [L] +RewriteRule ^(.+)/common/js/iePngFix.htc /~syhan/zbxe/common/js/iePngFix.htc [L] diff --git a/addons/member_extra_info/lang/ru.lang.php b/addons/member_extra_info/lang/ru.lang.php new file mode 100644 index 000000000..5601c132c --- /dev/null +++ b/addons/member_extra_info/lang/ru.lang.php @@ -0,0 +1,9 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->alert_new_message_arrived = 'У Вас есть новое сообщение. Хотите проверить сейчас?'; +?> diff --git a/common/lang/lang.info b/common/lang/lang.info index c91900c85..66722fbe2 100644 --- a/common/lang/lang.info +++ b/common/lang/lang.info @@ -3,3 +3,4 @@ en,English zh-CN,中文 jp,日本語 es,Español +ru,Русский diff --git a/common/lang/ru.lang.php b/common/lang/ru.lang.php new file mode 100644 index 000000000..fe7732cdc --- /dev/null +++ b/common/lang/ru.lang.php @@ -0,0 +1,235 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + // Основные слова для действий + $lang->cmd_write = 'Написать'; + $lang->cmd_reply = 'Ответить'; + $lang->cmd_delete = 'Удалить'; + $lang->cmd_modify = 'Изменить'; + $lang->cmd_edit = 'Редактировать'; + $lang->cmd_view = 'Просмотреть'; + $lang->cmd_view_all = 'Просмотреть Все'; + $lang->cmd_list = 'Список'; + $lang->cmd_prev = 'Пред.'; + $lang->cmd_next = 'След.'; + $lang->cmd_send_trackback = 'Отправить Трекбек'; + $lang->cmd_registration = $lang->cmd_submit = 'Принять'; + $lang->cmd_comment_registration = 'Добавить Комментарий'; + $lang->cmd_insert = 'Вставить'; + $lang->cmd_save = 'Сохранить'; + $lang->cmd_load = 'Загрузить'; + $lang->cmd_input = 'Ввести'; + $lang->cmd_search = 'Искать'; + $lang->cmd_cancel = 'Отменить'; + $lang->cmd_back = 'Вернуться'; + $lang->cmd_vote = 'Рекомендовать'; + $lang->cmd_vote_down = 'Критиковать'; + $lang->cmd_declare = 'Обвинить'; + $lang->cmd_declared_list = 'Список Обвинений'; + $lang->cmd_copy = 'Копировать'; + $lang->cmd_move = 'Переместить'; + $lang->cmd_move_up = 'Вверх'; + $lang->cmd_move_down = 'Вниз'; + $lang->cmd_add_indent = 'Отступ Вправо'; + $lang->cmd_remove_indent = 'Отступ Влево'; + $lang->cmd_management = 'Управление'; + $lang->cmd_make = 'Создать'; + $lang->cmd_select = 'Выделить'; + $lang->cmd_select_all = 'Выделить Все'; + $lang->cmd_unselect_all = 'Убрать Выделение Всех'; + $lang->cmd_reverse_all = 'Перевернуть'; + $lang->cmd_close_all = 'Закрыть Все'; + $lang->cmd_open_all = 'Открыть Все'; + $lang->cmd_reload = 'Перегрузить'; + $lang->cmd_close = 'Закрыть'; + $lang->cmd_open = 'Открыть'; + $lang->cmd_setup = 'Кунфигурировать'; + $lang->cmd_addition_setup = 'Дополнительная Настройка'; + $lang->cmd_option = 'Опция'; + $lang->cmd_apply = 'Применить'; + $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->enable = 'Включить'; + $lang->disable = 'Выключить'; + + // Существенные слова + $lang->no = 'No.'; + $lang->notice = 'Уведомление'; + $lang->secret = 'Секрет'; + $lang->category = 'Катигория'; + $lang->document_srl = 'Док. No.'; + $lang->user_id = 'Юзер ID'; + $lang->author = 'Разработчик'; + $lang->password = 'Пароль'; + $lang->password1 = 'Пароль'; + $lang->password2 = 'Подтверждение пароля'; + $lang->admin_id = 'Админ ID'; + $lang->writer = 'Автор'; + $lang->user_name = 'Имя'; + $lang->nick_name = 'Ник'; + $lang->email_address = 'Email'; + $lang->homepage = 'Домашняя страница'; + $lang->blog = 'Блог'; + $lang->birthday = 'Дата рождения'; + $lang->browser_title = 'Заголовок браузера'; + $lang->title = 'Предмет'; + $lang->title_content = 'Тема+Содержание'; + $lang->topic = 'Тема'; + $lang->replies = 'Ответы'; + $lang->content = 'Содержание'; + $lang->document = 'Статьи'; + $lang->comment = 'Комментарии'; + $lang->description = 'Описание'; + $lang->trackback = 'Трекбек'; + $lang->tag = 'Тег'; + $lang->allow_comment = 'Позволить Комментарии'; + $lang->lock_comment = 'Заблокировать Комментарии'; + $lang->allow_trackback = 'Позволить Трекбек'; + $lang->uploaded_file = 'Вложение'; + $lang->grant = 'Права доступа'; + $lang->target = 'Назначение'; + $lang->total = 'Всего'; + $lang->total_count = 'Общее кол-во'; + $lang->ipaddress = 'IP Адрес'; + $lang->path = 'Путь'; + $lang->cart = 'Выбранный объект'; + $lang->friend = 'Друзья'; + $lang->notify = 'Уведомление'; + + $lang->mid = 'Имя Модуля'; + $lang->layout = 'Лейаут'; + $lang->widget = 'Виджет'; + $lang->module = 'Модуль'; + $lang->skin = 'Тема'; + $lang->colorset = 'Цветовой набор'; + $lang->extra_vars = 'Доп. Перем.'; + + $lang->document_url = 'Адрес статьи'; + $lang->trackback_url = 'Адрес трекбек'; + $lang->blog_name = 'Название Блога'; + $lang->excerpt = 'Цитата'; + + $lang->document_count = 'Всего Статей'; + $lang->page_count = 'Кол-во Страниц'; + $lang->list_count = 'Кол-во Списков'; + $lang->readed_count = 'Хиты'; + $lang->voted_count = 'Голоса'; + $lang->member_count = 'Кол-во пользователей'; + $lang->date = 'Дата'; + $lang->regdate = 'Дата Регистрации'; + $lang->last_update = 'Последнее Обновление'; + $lang->last_post = 'Последний Комментарий'; + $lang->signup_date = 'Дата Регистрации'; + $lang->last_login = 'Последний Вход'; + $lang->first_page = 'Первая Страница'; + $lang->last_page = 'Последняя Страница'; + $lang->search_target = 'Назначение Поиска'; + $lang->search_keyword = 'Ключевые Слова'; + $lang->is_default = 'По умолчанию'; + + $lang->no_documents = 'Нет Статей'; + + $lang->board_manager = 'Настройки Форума'; + $lang->member_manager = 'Настройки Пользователей'; + $lang->layout_manager = 'Настройки Лейаута'; + + $lang->use = 'Использовать'; + $lang->notuse = 'Не использовать'; + $lang->not_exists = "Не существует"; + + $lang->unit_sec = 'сек.'; + $lang->unit_min = 'мин.'; + $lang->unit_hour = 'ч.'; + $lang->unit_day = 'д.'; + $lang->unit_week = 'нед.'; + $lang->unit_month = 'мес.'; + $lang->unit_year = 'г.'; + + // Описания + $lang->about_tag = 'Вы можете применить несколько тегов, разделенных запятыми (,)'; + $lang->about_layout = 'Лейауты украшают внешний вид Ваших модулей. Вы можете сконфигирировать их с помощью меню Лейаут сверху'; + + // Сообщение + $lang->msg_call_server = 'Идет обработка. Пожалуйста, подождите...'; + $lang->msg_db_not_setted = 'Даза данных не сконфигурирована'; + $lang->msg_invalid_queryid = 'Указанный ID запроса неверен'; + $lang->msg_not_permitted = 'У Вас нет прав доступа'; + $lang->msg_input_password = 'Пожалуйста, введите пароль'; + $lang->msg_invalid_document = 'Неверный номер статьи'; + $lang->msg_invalid_request = 'Неверный запрос'; + $lang->msg_invalid_password = 'Неверный пароль'; + $lang->msg_error_occured = 'Произошла ошибка'; + $lang->msg_not_founded = 'Сообщение не найдено'; + $lang->msg_no_result = 'Ничего не найдено'; + + $lang->msg_not_permitted_act = 'У Вас нет прав для исполнения запрошенного действия'; + $lang->msg_module_is_not_exists = 'Запрошенный модуль не найден'; + $lang->msg_module_is_not_standalone = 'Запрошенный модуль не может быть исполнен независимо'; + + $lang->success_registed = 'Зарегистрировано успешно'; + $lang->success_declared = 'Обвинение успешно'; + $lang->success_updated = 'Обновление успешно'; + $lang->success_deleted = 'Удалено успешно'; + $lang->success_voted = 'Рекомендовано успешно'; + $lang->success_moved = 'Перемещено успешно'; + $lang->success_sended = 'Отправлено успешно'; + $lang->success_reset = 'Сброшено успешно'; + $lang->success_leaved = 'Все данные пользователя были полностью удалены.'; + $lang->success_saved = 'Сохранено успешно'; + + $lang->fail_to_delete = 'Не может быть удалено'; + $lang->fail_to_move = 'Не может быть перемещено'; + + $lang->failed_voted = 'Ошибка при рекомендации'; + $lang->failed_declared = 'Ошибка при обвинении'; + $lang->fail_to_delete_have_children = 'Пожалуйста, попробуйте еще после удаления дочерних объектов'; + + $lang->confirm_submit = 'Вы подтверждаете применение?'; + $lang->confirm_logout = 'Вы подтверждаете выход?'; + $lang->confirm_vote = 'Вы подтверждаете рекомендацию?'; + $lang->confirm_delete = 'Вы подтверждаете удаление?'; + $lang->confirm_move = 'Вы подтверждаете перемещение?'; + $lang->confirm_reset = 'Вы подтверждаете сброс?'; + $lang->confirm_leave = 'Вы подтверждаете уход?'; + + $lang->column_type = 'Тип Колонки'; + $lang->column_type_list['text'] = 'one-line text'; + $lang->column_type_list['homepage'] = 'url'; + $lang->column_type_list['email_address'] = 'email'; + $lang->column_type_list['tel'] = 'phone number'; + $lang->column_type_list['textarea'] = 'multi-line textarea'; + $lang->column_type_list['checkbox'] = 'checkbox (multiple selection)'; + $lang->column_type_list['select'] = 'select box (single selection)'; + $lang->column_type_list['kr_zip'] = 'zip code (Korean)'; + $lang->column_type_list['date'] = 'date (yyyy/mm/dd)'; + //$lang->column_type_list['jp_zip'] = 'zip code (Japanese)'; + $lang->column_name = 'Имя Колонки'; + $lang->column_title = 'Название Колонки'; + $lang->default_value = 'Стандартное Значение'; + $lang->is_active = 'Активно'; + $lang->is_required = 'Требуемое Поле'; + + // Alert-сообщения для Javascript используя XML filter + $lang->filter->isnull = 'Пожалуйста, введите значение для %s'; + $lang->filter->outofrange = 'Пожалуйста, исправьте длину текста %s'; + $lang->filter->equalto = "Значение %s неверно"; + $lang->filter->invalid_email = "Формат %s неверен. Например: zbxe@zeroboard.com"; + $lang->filter->invalid_user_id = $lang->filter->invalid_userid = "Формат %s неверен.\\n Все значения должны состоять из алфавита, цифр и символа подчеркивания(_), и первая буква должна принадлежать латинскому алфавиту."; + $lang->filter->invalid_homepage = "Формат %s неверен. Например: http://www.zeroboard.com"; + $lang->filter->invalid_korean = "Формат %s неверен. Пожалуйста, вводите по-корейски"; + $lang->filter->invalid_korean_number = "Формат %s неверен. Пожалуйста, вводите по-корейски или цифрами"; + $lang->filter->invalid_alpha = "Формат %s неверен. Пожалуйста, вводите только алфавитные символы"; + $lang->filter->invalid_alpha_number = "Формат %s неверен. Пожалуйста, вводите алфавитные символы или цифры"; + $lang->filter->invalid_number = "Формат %s неверен. Пожалуйста, вводите только цифры"; +?> diff --git a/modules/addon/lang/ru.lang.php b/modules/addon/lang/ru.lang.php new file mode 100644 index 000000000..b4edea751 --- /dev/null +++ b/modules/addon/lang/ru.lang.php @@ -0,0 +1,15 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->addon = "Аддон"; + + $lang->addon_info = 'Информация об аддоне'; + $lang->addon_maker = 'Автор аддона'; + $lang->addon_history = 'История аддона'; + + $lang->about_addon = 'Аддон служит больше для контролирования действий, чем для отображения HTML-результатов.
Простым включением/выключением любых аддонов, Вы можете использовать очень полезные функции для администрирования Вашего веб-сайта'; +?> diff --git a/modules/admin/lang/ru.lang.php b/modules/admin/lang/ru.lang.php new file mode 100644 index 000000000..dee41a5f0 --- /dev/null +++ b/modules/admin/lang/ru.lang.php @@ -0,0 +1,88 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->admin_info = 'Информация Администратора'; + $lang->admin_index = 'Индексная Страница Администратора'; + + $lang->module_category_title = array( + 'service' => 'Служебные Модули', + 'manager' => 'Управляющие Модули', + 'utility' => 'Утилиратные Модули', + 'accessory' => 'Дополнительные Модули', + 'base' => 'Базовые Модули', + ); + + $lang->newest_news = "Последние Новости"; + + $lang->env_setup = "Настройка"; + + $lang->env_information = "Информация Окружения"; + $lang->current_version = "Текущая Версия"; + $lang->current_path = "Текущий Путь"; + $lang->released_version = "Последняя Версия"; + $lang->about_download_link = "Новая версия XE доступна. Чтобы скачать последнюю версию, нажмите ссылку закачки."; + + $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->cmd_shortcut_management = "Редактировать Меню"; + + $lang->msg_is_not_administrator = 'Только для администраторов!'; + $lang->msg_manage_module_cannot_delete = 'Ярлыки модулей, аддонов, лейаутов, виджетов не могут быть удалены'; + $lang->msg_default_act_is_null = 'Ярлык не может быть зарегистрирован, поскольку стандартное административное действие не установлено'; + + $lang->welcome_to_zeroboard_xe = 'Добро пожаловать на страницу администратора Zeroboard XE'; + $lang->about_admin_page = "Страница администратора все еще в разработке,\nМы добавим важные доработки, принимая много хороших предложений на этапе Closebeta."; + $lang->about_lang_env = "Чтобы применить выбранный язык для пользователей как страндартный, нажмите кнопку Сохранить [Save] после изменения."; + + $lang->zeroboard_xe_user_links = 'Ссылки для Пользователей'; + $lang->zeroboard_xe_developer_links = 'Ссылки для Разработчиков'; + + $lang->xe_user_links = array( + 'Официальный веб-сайт' => 'http://www.zeroboard.com', + //'Close Beta website' => 'http://spring.zeroboard.com', + //'Module morgue' => 'http://www.zeroboard.com', + //'Addon morgue' => 'http://www.zeroboard.com', + //'Widget morgue' => 'http://www.zeroboard.com', + //'Module Skin morgue' => 'http://www.zeroboard.com', + //'Widget Skin morgue' => 'http://www.zeroboard.com', + //'Layout Skin morgue' => 'http://www.zeroboard.com', + ); + + $lang->xe_developer_links = array( + //'Manual' => 'http://www.zeroboard.com/wiki/manual', + "Форум Разработчиков" => 'http://spring.zeroboard.com', + 'Обсуждение Восросов' => 'http://trac.zeroboard.com', + 'SVN Репозиторий' => 'http://svn.zeroboard.com', + 'Документация' => 'http://doc.zeroboard.com', + 'PDF Документация' => 'http://doc.zeroboard.com/zeroboard_xe.pdf', + ); + + $lang->zeroboard_xe_usefulness_module = 'Полезные Модули'; + $lang->xe_usefulness_modules = array( + 'dispEditorAdminIndex' => 'Менеждер Редактора', + 'dispDocumentAdminList' => 'Менеждер Статей', + 'dispCommentAdminList' => 'Менеждер Комментариев', + 'dispFileAdminList' => 'Менеждер Вложений', + 'dispPollAdminList' => 'Менеждер Голосований', + 'dispSpamfilterAdminConfig' => 'Менеждер Спам-фильтра', + 'dispCounterAdminIndex' => 'Лог Счетчика', + + ); + + $lang->xe_license = 'Zeroboard XE подчиняется Стандартной Общественной Лицензии GPL'; + $lang->about_shortcut = 'Вы можете удалить ярлыки модулей, зарегистрированных в списке часто используемых модулей'; +?> diff --git a/modules/blog/lang/ru.lang.php b/modules/blog/lang/ru.lang.php new file mode 100644 index 000000000..4a838361a --- /dev/null +++ b/modules/blog/lang/ru.lang.php @@ -0,0 +1,33 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + // Слова, использованные в кнопке + $lang->cmd_blog_list = 'Список Блогов'; + $lang->cmd_module_config = 'Общие настройки блога'; + $lang->cmd_view_info = 'Иформация Блога'; + $lang->cmd_manage_menu = 'Управление меню'; + $lang->cmd_make_child = 'Добавить дочернюю категорию'; + $lang->cmd_enable_move_category = "Изменить позицию категории (Перетащите верхнее меню после выделения)"; + $lang->cmd_remake_cache = 'Перепостроить файл кеша'; + $lang->cmd_layout_setup = 'Конфигурировать лейаут'; + $lang->cmd_layout_edit = 'Редактировать лейаут'; + + // Объект + $lang->parent_category_title = 'Родительская категория'; + $lang->category_title = 'Категория'; + $lang->expand = 'Расширить'; + $lang->category_group_srls = 'Доступные Группы'; + $lang->search_result = 'Результат поиска'; + + // blah blah.. или чушь всякая... ;) + $lang->about_category_title = 'Пожалуйста, введите название категории'; + $lang->about_expand = 'Если эта опция выбрана, расширение будут применено всегда'; + $lang->about_category_group_srls = 'Только выбранная группа будет способна видеть ткущие категории. (Вручную откройте xml файл, чтобы сделать видимыми)'; + $lang->about_layout_setup = 'Вы можете вручную изменять лейаут код блога. Вставляйте или управляйте кодом виджетов везде, где хотите'; + $lang->about_blog_category = 'Вы можете сделать категории блога.
Когда категория блога испорчена, попробуйте перепостроить файл кеша вручную.'; + $lang->about_blog = "Это модуть блогов, который может создавать и управлять блогом.\nПосле создания блога, пожалуйста, украсьте Ваш блог посредством менеджера категорий и скинов, поскольку этот модуль блогов использует лейаут включенный в скин блога.\nЕсли Вы хотите подключить другие форумы внутри блога, используйте модуль меню для создания меню и, затем, подключите его к менеджеру скинов"; +?> diff --git a/modules/board/lang/ru.lang.php b/modules/board/lang/ru.lang.php new file mode 100644 index 000000000..13961d296 --- /dev/null +++ b/modules/board/lang/ru.lang.php @@ -0,0 +1,16 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->board = "Форум"; + + // слова, использованные в кнопке + $lang->cmd_board_list = 'Список форумов'; + $lang->cmd_module_config = 'Общие настройки форума'; + $lang->cmd_view_info = 'Информация форума'; + + $lang->about_board = "Этот модуль служит для создания и управления форумами.\nВы можете выбрать имя модуля из списка после создания для дополнительного конифигурирования.\nПожалуйста, будте осторожны с именем модуля форума, поскольку оно будет URL. (например : http://domain/zb/?mid=имя_модуля)"; +?> diff --git a/modules/comment/lang/ru.lang.php b/modules/comment/lang/ru.lang.php new file mode 100644 index 000000000..c2870faac --- /dev/null +++ b/modules/comment/lang/ru.lang.php @@ -0,0 +1,27 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->cmd_comment_do = 'Вы бы...'; + + $lang->comment_list = 'Список Комментариев'; + $lang->cmd_delete_checked_comment = 'Удалить выбранный объект'; + + $lang->msg_cart_is_null = 'Пожалуйста, выберите статью для удаления.'; + $lang->msg_checked_comment_is_deleted = '%d комментарий(-ия) успешно удален(о).'; + + $lang->search_target_list = array( + 'content' => 'Содержание', + 'user_id' => 'ID', + 'user_name' => 'Имя', + 'nick_name' => 'Ник', + 'email_address' => 'Email', + 'homepage' => 'Домашняя страница', + 'regdate' => 'Дата', + 'last_update' => 'Последнее обновление', + 'ipaddress' => 'IP-адрес', + ); +?> diff --git a/modules/counter/lang/ru.lang.php b/modules/counter/lang/ru.lang.php new file mode 100644 index 000000000..a512a5414 --- /dev/null +++ b/modules/counter/lang/ru.lang.php @@ -0,0 +1,22 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->counter = "Счетчик"; + $lang->cmd_select_date = 'Выберите дату'; + $lang->cmd_select_counter_type = array( + 'hour' => 'По часам', + 'day' => 'По дням', + 'month' => 'По месяцам', + 'year' => 'По годам', + ); + + $lang->total_counter = 'Общее Состояние'; + $lang->selected_day_counter = 'Состояние на выбранный день'; + + $lang->unique_visitor = 'Посетителей'; + $lang->pageview = 'Просмотров страниц'; +?> diff --git a/modules/document/lang/ru.lang.php b/modules/document/lang/ru.lang.php new file mode 100644 index 000000000..ba46cdd90 --- /dev/null +++ b/modules/document/lang/ru.lang.php @@ -0,0 +1,50 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->document_list = 'Список Документов'; + $lang->thumbnail_type = 'Тип Миниатюры'; + $lang->thumbnail_crop = 'Обрезать'; + $lang->thumbnail_ratio = 'Отношение'; + $lang->cmd_delete_all_thumbnail = 'Удалить все миниарюры'; + $lang->move_target_module = "Переместить в"; + $lang->title_bold = 'Жирное Название'; + $lang->title_color = 'Цвет Названия'; + + $lang->cmd_temp_save = 'Сохранить временно'; + + $lang->cmd_toggle_checked_document = 'Перевернуть выбранные объекты'; + $lang->cmd_delete_checked_document = 'Удалить выбранные'; + $lang->cmd_document_do = 'Вы бы...'; + + $lang->msg_cart_is_null = 'Выберите статьи, которые Вы хотите удалить'; + $lang->msg_category_not_moved = 'Невозможно переместить'; + $lang->msg_is_secret = 'Эта статья секретна'; + $lang->msg_checked_document_is_deleted = 'Всего %d статей было удалено'; + + // Search targets in admin page + $lang->search_target_list = array( + 'title' => 'Тема', + 'content' => 'Содержание', + 'user_id' => 'Юзер ID', + 'member_srl' => 'Членский No.', + 'user_name' => 'Имя', + 'nick_name' => 'Ник', + 'email_address' => 'Email', + 'homepage' => 'Домашняя страница', + 'is_notice' => 'Уведомление', + 'is_secret' => 'Секрет', + 'tags' => 'Тег', + 'readed_count' => 'Кол-во Просмотров (Выше)', + 'voted_count' => 'Кол-во Голосов (Выше)', + 'comment_count ' => 'Кол-во Комментариев (Выше)', + 'trackback_count ' => 'Кол-во Трекбеков (Выше)', + 'uploaded_count ' => 'Кол-во Вложений (Выше)', + 'regdate' => 'Дата', + 'last_update' => 'Последнее Обновление', + 'ipaddress' => 'IP-Адрес', + ); +?> diff --git a/modules/editor/lang/ru.lang.php b/modules/editor/lang/ru.lang.php new file mode 100644 index 000000000..cfa051a19 --- /dev/null +++ b/modules/editor/lang/ru.lang.php @@ -0,0 +1,85 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->editor = "WYSIWYG-Редактор"; + $lang->component_name = "Компонент"; + $lang->component_version = "Версия"; + $lang->component_author = "Разработчик"; + $lang->component_link = "Ссылка"; + $lang->component_date = "Дата"; + $lang->component_description = "Описание"; + $lang->component_extra_vars = "Экстра перем."; + $lang->component_grant = "Настройки Прав Доступа"; + + $lang->about_component = "О компоненте"; + $lang->about_component_grant = "Только выбранным группам позволено использование. (Каждый может использовать его, если режим выключен)"; + + $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->edit->fontname = 'Шрифт'; + $lang->edit->fontsize = 'Размер'; + $lang->edit->use_paragraph = 'Функции Параграфа'; + $lang->edit->fontlist = array( + "Gulim", + "Dodum", + "Batang", + "Goongseo", + "times", + "Courier", + "Tahoma", + "Arial", + ); + + $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->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_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_paragrapth = "Нажмите Ctrl+Enter, чтобы отметить параграф. (Нажмите Alt+S , чтобы сохранить)"; + + $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 = 'Вы можете установить детальную конфигурацию компонента двойным щелчком по фону, тексту, рисункам или цитатам'; +?> diff --git a/modules/file/lang/ru.lang.php b/modules/file/lang/ru.lang.php new file mode 100644 index 000000000..744e0dc1e --- /dev/null +++ b/modules/file/lang/ru.lang.php @@ -0,0 +1,41 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->file = 'Вложение'; + $lang->file_name = 'Имя файла'; + $lang->file_size = 'Размер файла'; + $lang->download_count = 'Скачано'; + $lang->status = 'Состояние'; + $lang->is_valid = 'Верно'; + $lang->is_stand_by = 'Ожидание'; + $lang->file_list = 'Список Вложений'; + $lang->allowed_filesize = 'Лимит размера файла'; + $lang->allowed_attach_size = 'Общий лимит размера'; + $lang->allowed_filetypes = 'Разрешенные расширения'; + $lang->enable_download_group = 'Группы с разрешением на скачивание'; + + $lang->about_allowed_filesize = 'Вы можете присвоить лимит на размер для каждого файла. (Исключая администраторов)'; + $lang->about_allowed_attach_size = 'Вы можете присвоить лимит на размер для каждого документа. (Исключая администраторов'; + $lang->about_allowed_filetypes = 'Только файлы с разрешенными расширениями могут быть вложены. Чтобы разрешить расширение, ипользуйте "*.расширение". Чтобы разрешить несколько расширений, используйте ";" между ними.
например: *.* или *.jpg;*.gif;
(Исключая администраторов)'; + + $lang->cmd_delete_checked_file = 'Удалить Выделенные'; + $lang->cmd_move_to_document = 'Переместить в документ'; + $lang->cmd_download = 'Скачать'; + + $lang->msg_not_permitted_download = 'У Вас нет прав доступа для скачивания'; + $lang->msg_cart_is_null = 'Выберите файл, который Вы хотите удалить'; + $lang->msg_checked_file_is_deleted = 'Всего %d вложений было удалено'; + $lang->msg_exceeds_limit_size = 'Вложение провалено: превышен лимит размера файлов'; + + $lang->search_target_list = array( + 'filename' => 'Имя файла', + 'filesize' => 'Размер файла (байт, Выше)', + 'download_count' => 'Скачано (Выше)', + 'regdate' => 'Дата', + 'ipaddress' => 'IP-Адрес', + ); +?> diff --git a/modules/guestbook/lang/ru.lang.php b/modules/guestbook/lang/ru.lang.php new file mode 100644 index 000000000..627922be0 --- /dev/null +++ b/modules/guestbook/lang/ru.lang.php @@ -0,0 +1,16 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->guestbook = "Гостевая Книга"; + + // Слова, использованные в кнопках + $lang->cmd_guestbook_list = 'Список Гостевых Книг'; + $lang->cmd_module_config = 'Общая Конфигурация Гостевых Книг'; + $lang->cmd_view_info = 'Информация Гостевой Книги'; + + $lang->about_board = "Этот модуль служит для создания и управления гостевыми книгами.\nВы можете выбрать имя модуля из списка после создания для дополнительного конифигурирования.\nПожалуйста, будте осторожны с именем модуля форума, поскольку оно будет URL. (например : http://domain/zb/?mid=имя_модуля)"; +?> diff --git a/modules/importer/lang/ru.lang.php b/modules/importer/lang/ru.lang.php new file mode 100644 index 000000000..d746413cc --- /dev/null +++ b/modules/importer/lang/ru.lang.php @@ -0,0 +1,52 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + // слова для кнопок + $lang->cmd_sync_member = 'Синхронизировать'; + $lang->cmd_continue = 'Продолжить'; + + // объекты + $lang->importer = 'Импортировать данные zeroboard'; + $lang->source_type = 'Предыдущее назначение'; + $lang->type_member = 'Данные пользователей'; + $lang->type_module = 'Данные статей'; + $lang->type_syncmember = 'Синхронизировать данные пользователей'; + $lang->target_module = 'Модуль назначения'; + $lang->xml_file = 'XML файл'; + + $lang->import_step_title = array( + 1 => 'Шаг 1. Выберите предыдущее назначение', + 12 => 'Шаг 1-2. Выберите модуль назначения', + 13 => 'Шаг 1-3. Выберите категорию назначения', + 2 => 'Шаг 2. Загрузить XML файл', + 3 => 'Шаг 2. Синхронизировать данные пользователей и статей', + ); + + $lang->import_step_desc = array( + 1 => 'Пожалуйста, выберите тип XML файла, который Вы хотите импортировать.', + 12 => 'Пожалуйста, выберите модуль, в который Вы хотите импортировать данные.', + 13 => 'Пожалуйста, выберите категорию назначения, в которую Вы хотите импортировать данные.', + 2 => "Пожайлуста, введите расположение XML файла, который Вы хотите импортировать.\nЕсли он находится в одном аккаунте, то введите абсолютный/относительный путь. Если нет, то введите URL, начинающийся с http://...", + 3 => 'Данные пользователей и статей могут быть некорректны после импорта. В таком случае, выполните синхронизацию для восстановления, основанного на user_id.', + ); + + // гид/алерт + $lang->msg_sync_member = 'Синхронизация данных пользователей и статей начнется по нажатию книпоки "Синхронизировать".'; + $lang->msg_no_xml_file = 'XML файл не найден. Пожалуйста, проверьте путь еще раз'; + $lang->msg_invalid_xml_file = 'Неверный тип XML файла.'; + $lang->msg_importing = 'Пишем %d данные %d. (Если процесс "завис", нажмите кнопку "Продолжить")'; + $lang->msg_import_finished = '%d данные были поностью импортированы. В зависимости от ситуации, некоторые данные могут не быть импортированы.'; + $lang->msg_sync_completed = 'Выполнена синхронизация пользователей, статей и комментариев.'; + + // blah blah.. чепуха) + $lang->about_type_member = 'Если Вы импортируете информацию пользователей, выберите эту опцию'; + $lang->about_type_module = 'Если Вы импортируете информацию форума или статей, выберите эту опцию'; + $lang->about_type_syncmember = 'Если Вы пытаетесь синхронизировать информацию пользователей после импорта информации пользователей и статей, выберите эту опцию'; + $lang->about_importer = "Вы можете импортировать данные Zeroboard4, Zeroboard5 Beta или других программ в ZeroboardXE.\nЧтобы импортировать, Вам следует использовать XML Экспортер (XML Exporter), чтобы конвертировать нужные данные в XML Файл и затем загрузить его."; + + $lang->about_target_path = "Чтобы получить вложения с Zeroboard4, пожалуйста, введите адрес, где установлена Zeroboard4.\nЕсли она раположена на том же сервере, введите путь к Zeroboard4 как /home/USERID/public_html/bbs\nЕсли нет, введите адрес, где Zeroboard4 установлена. Например: http://Domain/bbs"; +?> diff --git a/modules/install/lang/ru.lang.php b/modules/install/lang/ru.lang.php new file mode 100644 index 000000000..37acc7f19 --- /dev/null +++ b/modules/install/lang/ru.lang.php @@ -0,0 +1,367 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->introduce_title = 'Установка Zeroboard XE'; + $lang->license = <<http://www.zeroboard.com +- Автор : zero (zero@zeroboard.com, http://www.zeroboard.com) + +Эта программа является бесплатным программным обеспечением, которое следует GPL лицензии. +Но, когда включены скины с дизайнерскими элементами, владелецы могут применять их индивидуальную лицензию. + +ПЕРЕВОД НА РУССКИЙ ЯЗЫК GENERAL PUBLIC LICENSE GNU + +автор перевода Елена Тяпкина [ tiapkina@hotmail.com ], 09-Aug-2001 + +This is an unofficial translation of the GNU General Public License into Russian. It was not published by the Free Software Foundation, and does not legally state the distribution terms for software that uses the GNU GPL - only the original English text of the GNU GPL does that. However, we hope that this translation will help Russian speakers understand the GNU GPL better. + +Настоящий перевод Стандартной Общественной Лицензии GNU на русский язык не является официальным. Он не публикуется Free Software Foundation и не устанавливает имеющих юридическую силу условий для распространения программного обеспечения, которое распространяется на условиях Стандартной Общественной Лицензии GNU. Условия, имеющие юридическую силу, закреплены исключительно в аутентичном тексте Стандартной Общественной Лицензии GNU на английском языке. Я надеюсь, что настоящий перевод поможет русскоязычным пользователям лучше понять содержание Стандартной Общественной Лицензии GNU. + +Текст GNU GPL на английском языке вы можете прочитать здесь http://www.gnu.org/copyleft/gpl.html + +Содержание + + * Стандартная Общественная Лицензия GNU + o Преамбула + o Условия воспроизведения, распространения и модификации + o Порядок применения условий Стандартной Общественной Лицензии к созданной вами программе + +GNU GENERAL PUBLIC LICENSE + +Версия 2, июнь 1991г. + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +Каждый вправе копировать и распространять экземпляры настоящей Лицензии без внесения изменений в ее текст. +Преамбула + +Большинство лицензий на программное обеспечение лишаeт вас права распространять и вносить изменения в это программное обеспечение. Стандартная Общественная Лицензия GNU, напротив, разработана с целью гарантировать вам право совместно использовать и вносить изменения в свободное программное обеспечение, т.е. обеспечить свободный доступ к программному обеспечению для всех пользователей. Условия настоящей Стандартной Общественной Лицензии применяются к большей части программного обеспечения Free Software Foundation, а также к любому другому программному обеспечению по желанию его автора. (К некоторому программному обеспечению Free Software Foundation применяются условия Стандартной Общественной Лицензии GNU для Библиотек). Вы также можете применять Стандартную Общественную Лицензию к разработанному вами программному обеспечению. + +Говоря о свободном программном обеспечении, мы имеем в виду свободу, а не безвозмездность. Настоящая Стандартная Общественная Лицензия разработана с целью гарантировать вам право распространять экземпляры свободного программного обеспечения (и при желании получать за это вознаграждение), право получать исходный текст программного обеспечения или иметь возможность его получить, право вносить изменения в программное обеспечение или использовать его части в новом свободном программном обеспечении, а также право знать, что вы имеете все вышеперечисленные права. + +Чтобы защитить ваши права, мы вводим ряд ограничений с тем, чтобы никто не имел возможности лишить вас этих прав или обратиться к вам с предложением отказаться от этих прав. Данные ограничения налагают на вас определенные обязанности в случае, если вы распространяете экземпляры программного обеспечения или модифицируете программное обеспечение. + +Например, если вы распространяете экземпляры такого программного обеспечения за плату или бесплатно, вы обязаны передать новым обладателям все права в том же объеме, в каком они принадлежат вам. Вы обязаны обеспечить получение новыми обладателями программы ее исходного текста или возможность его получить. Вы также обязаны ознакомить их с условиями настоящей Лицензии. + +Для защиты ваших прав мы: (1) оставляем за собой авторские права на программное обеспечение и (2) предлагаем вам использовать настоящую Лицензию, в соответствии с условиями которой вы вправе воспроизводить, распространять и/или модифицировать программное обеспечение. + +Кроме того, для защиты как нашей репутации, так и репутации других авторов программного обеспечения, мы уведомляем всех пользователей, что на данное программное обеспечение никаких гарантий не предоставляется. Те, кто приобрел программное обеспечение, с внесенными в него третьими лицами изменениями, должны знать, что они получают не оригинал, в силу чего автор оригинала не несет ответственности за ошибки в работе программного обеспечения, допущенные третьими лицами при внесении изменений. + +Наконец, программное обеспечение перестает быть свободным в случае, если лицо приобретает на него исключительные права [1]. Недопустимо, чтобы лица, распространяющие свободное программное обеспечение, могли приобрести исключительные права на использование данного программного обеспечения и зарегистрировать их в Патентном ведомстве. Чтобы избежать этого, мы заявляем, что обладатель исключительных прав обязан предоставить любому лицу права на использование программного обеспечения либо не приобретать исключительных прав вообще. + +Ниже изложены условия воспроизведения, распространения и модификации программного обеспечения. +Условия воспроизведения, распространения и модификации + +0. Условия настоящей Лицензии применяются ко всем видам программного обеспечения или любому иному произведению, которое содержит указание правообладателя на то, что данное произведение может распространяться на условиях Стандартной Общественной Лицензии. Под термином "Программа" далее понимается любое подобное программное обеспечение или иное произведение. Под термином "произведение, производное от Программы" понимается Программа или любое иное производное произведение в соответствии с законодательством об авторском праве [2], т.е. произведение, включающее в себя Программу или ее часть, как с внесенными в ее текст изменениями, так и без них и/или переведенную на другой язык. (Здесь и далее, понятие "модификация" включает в себя понятие перевода в самом широком смысле). Каждый приобретатель экземпляра Программы именуется в дальнейшем "Лицензиат". + +Действие настоящей Лицензии не распространяется на осуществление иных прав, кроме воспроизведения, распространения и модификации программного обеспечения. Не устанавливается ограничений на запуск Программы. Условия Лицензии распространяются на выходные данные из Программы только в том случае, если их содержание составляет произведение, производное от Программы (независимо от того, было ли такое произведение создано в результате запуска Программы). Это зависит от того, какие функции выполняет Программа. + +1. Лицензиат вправе изготовлять и распространять экземпляры исходного текста Программы в том виде, в каком он его получил, без внесения в него изменений на любом носителе, при соблюдении следующих условий: на каждом экземпляре помещен знак охраны авторского права и уведомление об отсутствии гарантий; оставлены без изменений все уведомления, относящиеся к настоящей Лицензии и отсутствию гарантий; вместе с экземпляром Программы приобретателю передается копия настоящей Лицензии. + +Лицензиат вправе взимать плату за передачу экземпляра Программы, а также вправе за плату оказывать услуги по гарантийной поддержке Программы. + +2. Лицензиат вправе модифицировать свой экземпляр или экземпляры Программы полностью или любую ее часть. Данные действия Лицензиата влекут за собой создание произведения, производного от Программы. Лицензиат вправе изготовлять и распространять экземпляры такого произведения, производного от Программы, или собственно экземпляры изменений в соответствии с пунктом 1 настоящей Лицензии при соблюдении следующих условий: + +а) файлы, измененные Лицензиатом, должны содержать хорошо заметную пометку, что они были изменены, а также дату внесения изменений; + +b) при распространении или публикации Лицензиатом любого произведения, которое содержит Программу или ее часть или является производным от Программы или от ее части, Лицензиат обязан передавать права на использование данного произведения третьим лицам на условиях настоящей Лицензии, при этом Лицензиат не вправе требовать уплаты каких-либо лицензионных платежей. Распространяемое произведение лицензируется как одно целое; + +c) если модифицированная Программа при запуске обычно читает команды в интерактивном режиме, Лицензиат обязан обеспечить вывод на экран дисплея или печатающее устройство, сообщение, которое должно включать в себя: +знак охраны авторского права; +уведомление об отсутствии гарантий на Программу (или иное, если Лицензиат предоставляет гарантии); +указание на то, что пользователи вправе распространять экземпляры Программы в соответствии с условиями настоящей Лицензии, а также на то, каким образом пользователь может ознакомиться с текстом настоящей Лицензии. (Исключение: если оригинальная Программа является интерактивной, но не выводит в своем обычном режиме работы сообщение такого рода, то вывод подобного сообщения произведением, производным от Программы, в этом случае не обязателен). + +Вышеуказанные условия применяются к модифицированному произведению, производному от Программы, в целом. В случае если отдельные части данного произведения не являются производными от Программы, являются результатом творческой деятельности и могут быть использованы как самостоятельное произведение, Лицензиат вправе распространять отдельно такое произведение на иных лицензионных условиях. В случае если Лицензиат распространяет вышеуказанные части в составе произведения, производного от Программы, то условия настоящей Лицензии применяются к произведению в целом, при этом права, приобретаемые сублицензиатами на основании Лицензии, передаются им в отношении всего произведения, включая все его части, независимо от того, кто является их авторами. + +Целью настоящего пункта 2 не является заявление прав или оспаривание прав на произведение, созданное исключительно Лицензиатом. Целью настоящего пункта является обеспечение права контролировать распространение произведений, производных от Программы, и составных произведений, производных от Программы. + +Размещение произведения, которое не является производным от Программы, на одном устройстве для хранения информации или носителе вместе с Программой или произведением, производным от Программы, не влечет за собой распространения условий настоящей Лицензии на такое произведение. + +3. Лицензиат вправе воспроизводить и распространять экземпляры Программы или произведения, которое является производным от Программы, в соответствии с пунктом 2 настоящей Лицензии, в виде объектного кода или в исполняемой форме в соответствии с условиями п.п.1 и 2 настоящей Лицензии при соблюдении одного из перечисленных ниже условий: + +а) к экземпляру должен прилагаться соответствующий полный исходный текст в машиночитаемой форме, который должен распространяться в соответствии с условиями п.п. 1 и 2 настоящей Лицензии на носителе, обычно используемом для передачи программного обеспечения, либо + +b) к экземпляру должно прилагаться действительное в течение трех лет предложение в письменной форме к любому третьему лицу передать за плату, не превышающую стоимость осуществления собственно передачи, экземпляр соответствующего полного исходного текста в машиночитаемой форме в соответствии с условиями п.п. 1 и 2 настоящей Лицензии на носителе, обычно используемом для передачи программного обеспечения, либо + +c) к экземпляру должна прилагаться полученная Лицензиатом информация о предложении, в соответствии с которым можно получить соответствующий исходный текст. (Данное положение применяется исключительно в том случае, если Лицензиат осуществляет некоммерческое распространение программы, при этом программа была получена самим Лицензиатом в виде объектного кода или в исполняемой форме и сопровождалась предложением, соответствующим условиям пп.b п.3 настоящей Лицензии). + +Под исходным текстом произведения понимается такая форма произведения, которая наиболее удобна для внесения изменений. Под полным исходным текстом исполняемого произведения понимается исходный текст всех составляющих произведение модулей, а также всех файлов, связанных с описанием интерфейса, и сценариев, предназначенных для управления компиляцией и установкой исполняемого произведения. Однако, в качестве особого исключения, распространяемый исходный текст может не включать того, что обычно распространяется (в виде исходного текста или в бинарной форме) с основными компонентами (компилятор, ядро и т.д.) операционной системы, в которой работает исполняемое произведение, за исключением случаев, когда исполняемое произведение сопровождается таким компонентом. + +В случае если произведение в виде объектного кода или в исполняемой форме распространяется путем предоставления доступа для копирования его из определенного места, обеспечение равноценного доступа для копирования исходного текста из этого же места удовлетворяет требованиям распространения исходного текста, даже если третьи лица при этом не обязаны копировать исходный текст вместе с объектным кодом произведения. + +4. Лицензиат вправе воспроизводить, модифицировать, распространять или передавать права на использование Программы только на условиях настоящей Лицензии. Любое воспроизведение, модификация, распространение или передача прав на иных условиях являются недействительными и автоматически ведут к расторжению настоящей Лицензии и прекращению всех прав Лицензиата, предоставленных ему настоящей Лицензией. При этом права третьих лиц, которым Лицензиат в соответствии с настоящей Лицензией передал экземпляры Программы или права на нее, сохраняются в силе при условии полного соблюдения ими настоящей Лицензии. + +5. Лицензиат не обязан присоединяться к настоящей Лицензии, поскольку он ее не подписал. Однако только настоящая Лицензия предоставляет право распространять или модифицировать Программу или произведение, производное от Программы. Подобные действия нарушают действующее законодательство, если они не осуществляются в соответствии с настоящей Лицензией. Если Лицензиат внес изменения или осуществил распространение экземпляров Программы или произведения, производного от Программы, Лицензиат тем самым подтвердил свое присоединение к настоящей Лицензии в целом, включая условия, определяющие порядок воспроизведения, распространения или модификации Программы или произведения, производного от Программы. + +6. При распространении экземпляров Программы или произведения, производного от Программы, первоначальный лицензиар автоматически передает приобретателю такого экземпляра право воспроизводить, распространять и модифицировать Программу в соответствии с условиями настоящей Лицензии. Лицензиат не вправе ограничивать каким-либо способом осуществление приобретателями полученных ими прав. Лицензиат не несет ответственности за несоблюдение условий настоящей Лицензии третьими лицами. + +7. Лицензиат не освобождается от исполнения обязательств в соответствии с настоящей Лицензией в случае, если в результате решения суда или заявления о нарушении исключительных прав или в связи с наступлением иных обстоятельств, не связанных непосредственно с нарушением исключительных прав, на Лицензиата на основании решения суда, договора или ином основании возложены обязательства, которые противоречат условиям настоящей Лицензии. В этом случае Лицензиат не вправе распространять экземпляры Программы, если он не может одновременно исполнить условия настоящей Лицензии и возложенные на него указанным выше способом обязательства. Например, если по условиям лицензионного соглашения сублицензиатам не может быть предоставлено право бесплатного распространения экземпляров Программы, которые они приобрели напрямую или через третьих лиц у Лицензиата, то в этом случае Лицензиат обязан отказаться от распространения экземпляров Программы. + +Если любое положение настоящего пункта при наступлении конкретных обстоятельств будет признано недействительным или неприменимым, настоящий пункт применяется за исключением такого положения. Настоящий пункт применяется в целом при прекращении вышеуказанных обстоятельств или их отсутствии. + +Целью данного пункта не является принуждение Лицензиата к нарушению патента или заявления на иные права собственности или к оспариванию действительности такого заявления. Единственной целью данного пункта является защита неприкосновенности системы распространения свободного программного обеспечения, которая обеспечивается за счет общественного лицензирования. Многие люди внесли свой щедрый вклад в создание большого количества программного обеспечения, которое распространяется через данную систему в надежде на ее длительное и последовательное применение. Лицензиат не вправе вынуждать автора распространять программное обеспечение через данную систему. Право выбора системы распространения программного обеспечения принадлежит исключительно его автору. + +Настоящий пункт 7 имеет целью четко определить те цели, которые преследуют все остальные положения настоящей Лицензии. + +8. В том случае если распространение и/или использование Программы в отдельных государствах ограничено соглашениями в области патентных или авторских прав, первоначальный правообладатель, распространяющий Программу на условиях настоящей Лицензии, вправе ограничить территорию распространения Программы, указав только те государства, на территории которых допускается распространение Программы без ограничений, обусловленных такими соглашениями. В этом случае такое указание в отношении территорий определенных государств признается одним из условий настоящей Лицензии. + +9. Free Software Foundation может публиковать исправленные и/или новые версии настоящей Стандартной Общественной Лицензии. Такие версии могут быть дополнены различными нормами, регулирующими правоотношения, которые возникли после опубликования предыдущих версий, однако в них будут сохранены основные принципы, закрепленные в настоящей версии. + +Каждой версии присваивается свой собственный номер. Если указано, что Программа распространяется в соответствии с определенной версией, т.е. указан ее номер, или любой более поздней версией настоящей Лицензии, Лицензиат вправе присоединиться к любой из этих версий Лицензии, опубликованных Free Software Foundation. Если Программа не содержит такого указания на номер версии Лицензии Лицензиат вправе присоединиться к любой из версий Лицензии, опубликованных когда-либо Free Software Foundation. + +10. В случае если Лицензиат намерен включить часть Программы в другое свободное программное обеспечение, которое распространяется на иных условиях, чем в настоящей Лицензии, ему следует испросить письменное разрешение на это у автора программного обеспечения. Разрешение в отношении программного обеспечения, права на которое принадлежат Free Software Foundation, следует испрашивать у Free Software Foundation. В некоторых случаях Free Software Foundation делает исключения. При принятии решения Free Software Foundation будет руководствоваться двумя целями: сохранение статуса свободного для любого произведения, производного от свободного программного обеспечения Free Software Foundation и обеспечение наиболее широкого совместного использования программного обеспечения. + +ОТСУТСТВИЕ ГАРАНТИЙНЫХ ОБЯЗАТЕЛЬСТВ + +11. ПОСКОЛЬКУ НАСТОЯЩАЯ ПРОГРАММА РАСПРОСТРАНЯЕТСЯ БЕСПЛАТНО, ГАРАНТИИ НА НЕЕ НЕ ПРЕДОСТАВЛЯЮТСЯ В ТОЙ СТЕПЕНИ, В КАКОЙ ЭТО ДОПУСКАЕТСЯ ПРИМЕНИМЫМ ПРАВОМ. НАСТОЯЩАЯ ПРОГРАММА ПОСТАВЛЯЕТСЯ НА УСЛОВИЯХ "КАК ЕСТЬ". ЕСЛИ ИНОЕ НЕ УКАЗАНО В ПИСЬМЕННОЙ ФОРМЕ, АВТОР И/ИЛИ ИНОЙ ПРАВООБЛАДАТЕЛЬ НЕ ПРИНИМАЕТ НА СЕБЯ НИКАКИХ ГАРАНТИЙНЫХ ОБЯЗАТЕЛЬСТВ, КАК ЯВНО ВЫРАЖЕННЫХ, ТАК И ПОДРАЗУМЕВАЕМЫХ, В ОТНОШЕНИИ ПРОГРАММЫ, В ТОМ ЧИСЛЕ ПОДРАЗУМЕВАЕМУЮ ГАРАНТИЮ ТОВАРНОГО СОСТОЯНИЯ ПРИ ПРОДАЖЕ И ПРИГОДНОСТИ ДЛЯ ИСПОЛЬЗОВАНИЯ В КОНКРЕТНЫХ ЦЕЛЯХ, А ТАКЖЕ ЛЮБЫЕ ИНЫЕ ГАРАНТИИ. ВСЕ РИСКИ, СВЯЗАННЫЕ С КАЧЕСТВОМ И ПРОИЗВОДИТЕЛЬНОСТЬЮ ПРОГРАММЫ, НЕСЕТ ЛИЦЕНЗИАТ. В СЛУЧАЕ ЕСЛИ В ПРОГРАММЕ БУДУТ ОБНАРУЖЕНЫ НЕДОСТАТКИ, ВСЕ РАСХОДЫ, СВЯЗАННЫЕ С ТЕХНИЧЕСКИМ ОБСЛУЖИВАНИЕМ, РЕМОНТОМ ИЛИ ИСПРАВЛЕНИЕМ ПРОГРАММЫ, НЕСЕТ ЛИЦЕНЗИАТ. + +12. ЕСЛИ ИНОЕ НЕ ПРЕДУСМОТРЕНО ПРИМЕНЯЕМЫМ ПРАВОМ ИЛИ НЕ СОГЛАСОВАНО СТОРОНАМИ В ДОГОВОРЕ В ПИСЬМЕННОЙ ФОРМЕ, АВТОР И/ИЛИ ИНОЙ ПРАВООБЛАДАТЕЛЬ, КОТОРЫЙ МОДИФИЦИРУЕТ И/ИЛИ РАСПРОСТРАНЯЕТ ПРОГРАММУ НА УСЛОВИЯХ НАСТОЯЩЕЙ ЛИЦЕНЗИИ, НЕ НЕСЕТ ОТВЕТСТВЕННОСТИ ПЕРЕД ЛИЦЕНЗИАТОМ ЗА УБЫТКИ, ВКЛЮЧАЯ ОБЩИЕ, РЕАЛЬНЫЕ, ПРЕДВИДИМЫЕ И КОСВЕННЫЕ УБЫТКИ (В ТОМ ЧИСЛЕ УТРАТУ ИЛИ ИСКАЖЕНИЕ ИНФОРМАЦИИ, УБЫТКИ, ПОНЕСЕННЫЕ ЛИЦЕНЗИАТОМ ИЛИ ТРЕТЬИМИ ЛИЦАМИ, НЕВОЗМОЖНОСТЬ РАБОТЫ ПРОГРАММЫ С ЛЮБОЙ ДРУГОЙ ПРОГРАММОЙ И ИНЫЕ УБЫТКИ). АВТОР И/ИЛИ ИНОЙ ПРАВООБЛАДАТЕЛЬ В СООТВЕТСТВИИ С НАСТОЯЩИМ ПУНКТОМ НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ДАЖЕ В ТОМ СЛУЧАЕ, ОНИ БЫЛИ ПРЕДУПРЕЖДЕНЫ О ВОЗМОЖНОСТИ ВОЗНИКНОВЕНИЯ ТАКИХ УБЫТКОВ. +Порядок применения условий Стандартной Общественной Лицензии к созданной вами программе + +Если вы создали новую программу и хотите, чтобы она принесла наибольшую пользу обществу, лучший способ достичь этого - сделать вашу программу свободной, когда каждый сможет распространять ее и вносить в нее изменения в соответствии с условиями настоящей Лицензии. + +В этих целях Программа должна содержать приведенное ниже уведомление. Наиболее правильным будет поместить его в начале исходного текста каждого файла для максимально ясного указания на то, что гарантии на данную программу не предоставляются. Каждый файл в любом случае должен содержать знак охраны авторского права и пояснение, где можно ознакомиться с полным текстом уведомления. + +[одна строка с наименованием Программы и кратким описанием ее назначения] +© имя (наименование) автора или иного правообладателя, год первого опубликования программы + +Данная программа является свободным программным обеспечением. Вы вправе распространять ее и/или модифицировать в соответствии с условиями версии 2 либо по вашему выбору с условиями более поздней версии Стандартной Общественной Лицензии GNU, опубликованной Free Software Foundation. + +Мы распространяем эту программу в надежде на то, что она будет вам полезной, однако НЕ ПРЕДОСТАВЛЯЕМ НА НЕЕ НИКАКИХ ГАРАНТИЙ, в том числе ГАРАНТИИ ТОВАРНОГО СОСТОЯНИЯ ПРИ ПРОДАЖЕ и ПРИГОДНОСТИ ДЛЯ ИСПОЛЬЗОВАНИЯ В КОНКРЕТНЫХ ЦЕЛЯХ.Для получения более подробной информации ознакомьтесь со Стандартной Общественной Лицензией GNU. + +Вместе с данной программой вы должны были получить экземпляр Стандартной Общественной Лицензии GNU. Если вы его не получили, сообщите об этом в Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Также укажите, как можно связаться с вами по электронной или обычной почте. + +Если программа работает в интерактивном режиме, сделайте так, чтобы при запуске в интерактивном режиме выводилось короткое сообщение в соответствии с образцом: + +Gnomovision version 69, © имя автора, год первого опубликования программы +Gnomovision распространяется БЕЗ ВСЯКИХ ГАРАНТИЙ; чтобы ознакомиться с более подробной информацией, наберите "show w". Данная программа является свободным программным обеспечением и вы можете распространять ее в соответствии с условиями Стандартной Общественной Лицензии GNU. Для получения более подробной информации, наберите "show c". + +При введении предлагаемых команд "show w" и "show c" на экран должны выводиться соответствующие пункты Стандартной Общественной Лицензии. Не обязательно использовать именно команды "show w" и "show c". В зависимости от функций программы, команды могут вызываться нажатием кнопки мыши или быть добавлены в меню программы. + +Если вы создали программу в порядке выполнения служебных обязанностей или служебного задания работодателя, вам следует получить от него в случае необходимости письменный отказ от исключительных прав на использование данной программы [3 ]. Нижеприведенный текст вы можете использовать в качестве образца, заменив соответствующие имена и наименования: + +ЗАО "АБВ" настоящим отказывается от всех исключительных прав на использование программы для ЭВМ "Gnomovision", автором которой является Иванов Алексей Петрович, и передает все исключительные права на использование указанной программы ее автору, Иванову Алексею Петровичу. + +Подпись руководителя организации, печать, 1 января 2001г. +[Фамилия, Имя, Отчество], Генеральный директор + +Стандартная Общественная Лицензия GNU запрещает включать вашу программу в программы, использование которых ограничено их правообладателями. Если ваша программа является библиотекой подпрограмм, вероятно, более полезным будет разрешить связывание программ, использование которых ограничено их правообладателями, с вашей библиотекой. В этом случае вам следует использовать Стандартную Общественную Лицензию GNU для Библиотек вместо настоящей Лицензии. + +Примечания переводчика + +[1] - в параграфе 7 Преамбулы в английском тексте Стандартной Общественной Лицензии GNU упоминается патент на программное обеспечение (Software Patents). В начале 90х годов XX века Апелляционный суд Федерального округа США предпринял попытку установить, когда изобретение, частью которого является программное обеспечение, является патентоспособным. Суд постановил, что в этом случае следует провести экспертизу в отношении произведения в целом. Изобретение не будет признано патентоспособным, если оно представляет собой исключительно математический алгоритм. Однако, если положенный в основу изобретения способ при помощи программного обеспечения позволяет получить конкретные, промышленно применимые результаты, в этом случае изобретение является патентоспособным. В отличие от США, в РФ соответствии с Патентным законом от 23.09.1992г. не признаются патентоспособными изобретениями программы для вычислительных машин. Защита программ для ЭВМ осуществляется на основании норм законодательства об авторском праве. Исключительные права на программу для ЭВМ принадлежат автору или иному правообладателю, который приобрел их на основании договора или ином основании, предусмотренным законом. Правообладатель всех имущественных прав на программу для ЭВМ в течение срока действия авторского права может по своему желанию зарегистрировать программу для ЭВМ путем подачи заявки в Патентное ведомство РФ + +[2] - Здесь имеется в виду законодательство об авторском праве США. + +[3] - В данном абзаце в английском тексте указано, что вам следует получить письменный отказ от исключительных прав на использование созданной вами программы у вашего работодателя, если вы работаете программистом, или у учебного заведения, в котором вы обучаетесь (школа, университет, институт, колледж). В соответствии с Законом РФ "Об авторском праве и смежных правах" такой отказ следует получить только от своего работодателя. В соответствии с указанным Законом РФ авторское право на произведение, созданное в порядке выполнения служебных обязанностей или служебного задания работодателя (служебное произведение), принадлежит автору служебного произведения. Исключительные права на использование служебного произведения (в том числе программы для ЭВМ) принадлежат лицу, с которым автор состоит в трудовых отношениях (работодателю), если в договоре между ними и автором не предусмотрено иное. Данное положение не распространяется на создание в порядке выполнения служебных обязанностей или служебного задания работодателя энциклопедий, энциклопедических словарей, периодических и продолжающихся сборников научных трудов, газет, журналов и других периодических изданий. Издателю энциклопедий, энциклопедических словарей, периодических и продолжающихся изданий принадлежат исключительные права на использование таких изданий. Авторы произведений, включенных в такие издания, сохраняют исключительные права на использование своих произведений независимо от издания в целом. + +My goal was not just a verbal translation of English text of GNU General Public License in Russian, but a translation, which will follow the rules of current legislation of Russian Federation on copyrights. I hope that this will help to use GNU General Public License when distributing free software in Russian Federation. Below you may find some comments (in Russian) on current legislation of Russian Federation. + +Моей целью был не просто перевод Стандартной Общественной Лицензии GNU, который бы максимально точно соответствовал аутентичному тексту на английском языке, но также учитывал нормы действующего законодательства РФ об авторском праве, что увеличило бы возможность использовать Стандартную Общественную Лицензию GPL для распространения свободного программного обеспечения на территории РФ. Ниже Вы можете ознакомиться с некоторыми комментариями относительно действующего законодательства РФ. + +В настоящее время на территории Российской Федерации порядок воспроизведения, распространения и модификации программного обеспечения регулируется Законом РФ "О правовой охране программ для ЭВМ и баз данных" от 23.09.1992г. ╧3523-1 и Законом РФ "Об авторском праве и смежных правах" от 09.07.1993г. ╧5351-1. + +С целью наибольшего соответствия настоящего неофициального перевода Стандартной Общественной Лицензии GNU на русский язык нормам действующего законодательства РФ об авторском праве, ниже приводятся основные понятие, используемые в тексте перевода, и их определения в соответствии с указанными выше Законами РФ: + +Программное обеспечение - данное понятие не применяется в указанных Законах, однако оно является наиболее общепринятым при обозначении программ для ЭВМ в переводах лицензионных соглашений, в частности Лицензионных соглашений с конечным пользователем (EULA), на русский язык. В силу этого понятие "Программное обеспечение" используется в тексте перевода для обозначения понятия "программа для ЭВМ". Под программой для ЭВМ Законе РФ понимается объективная форма представления совокупности данных и команд, предназначенных для функционирования электронных вычислительных машин (ЭВМ) и других компьютерных устройств с целью получения определенного результата, включая подготовительные материалы, полученные в ходе разработки программы для ЭВМ, и порождаемые ею аудиовизуальные отображения. + +Исключительные права на использование произведения - означает право осуществлять или разрешать следующие действия: воспроизводить произведение (право на воспроизведение); распространять экземпляры произведения любым способом: продавать, сдавать в прокат и так далее (право на распространение); публично показывать произведение (право на публичный показ), переводить произведение (право на перевод); переделывать, аранжировать или другим образом перерабатывать произведение (право на переработку), а также иные права в соответствии с Законом РФ "Об авторском праве и смежных правах". + +Исключительные (или имущественные) права на использование программы для ЭВМ - означает исключительное право осуществлять и (или) разрешать осуществление следующих действий: выпуск в свет программы для ЭВМ, воспроизведение программы для ЭВМ (полное или частичное) в любой форме, любыми способами, распространение программы для ЭВМ, модификацию программы для ЭВМ, в том числе перевод программы для ЭВМ с одного языка на другой, а также иное использование в соответствии с Законом РФ "О правовой охране программ для ЭВМ и баз данных". + +Воспроизведение Программного Обеспечения - это изготовление одного или более экземпляров Программного обеспечения в любой материальной форме, а также его запись в память ЭВМ. + +Модификация (переработка) Программного Обеспечения - любые его изменения, не являющиеся адаптацией. + +Распространение Программного Обеспечения - это предоставление доступа для воспроизведения в любой материальной форме Программного Обеспечения, в том числе сетевыми и иными способами, а также путем продажи, проката, сдачи в наем, предоставление взаймы, включая импорт для любой из этих целей. + +© Перевод лицензии: Елена Тяпкина, 2001г. +© License Translation: Elena Tyapkina, 2001. + + +Перевод Zeroboard XE на русский язык произвел Масленников Евгений aka X-[Vr]bL1s5. +Перевод следует Лицензии Свободной Документации GNU (GNU Free Documentation License), с содержимым которой можно ознакомиться по следующему адесу: http://www.gnu.org/licenses/fdl.html +Кантакты: x-bliss(at)tut.by, ICQ: 225035467, MSN: x-bliss(at)tut.by, YIM: maenwen, AIM: mayoojin, Skype: maenwen + +Translation of Zeroboard XE into Russian language is made by Maslennikov Evgeny aka X-[Vr]bL1s5. +The translation follows GNU Free Documentation License, which you can observe on the following address: http://www.gnu.org/licenses/fdl.html +Contacts: x-bliss(at)tut.by, ICQ: 225035467, MSN: x-bliss(at)tut.by, YIM: maenwen, AIM: mayoojin, Skype: maenwen + + +Оригинал лицензии GNU GPL на английским языке. + +GNU GENERAL PUBLIC LICENSE + +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification follow. +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: + +a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. +b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. +c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. + +3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: + +a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, +b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, +c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. + +If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. + +5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. + +This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. + +9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +END OF TERMS AND CONDITIONS + + + + + +EndOfLicense; + + $lang->install_condition_title = "Пожалуйста, проверьте требования к установке."; + + $lang->install_checklist_title = array( + 'php_version' => 'Версия PHP', + 'permission' => 'Права доступа', + 'xml' => 'XML Библиотека', + 'iconv' => 'ICONV Библиотека', + 'gd' => 'GD Библиотека', + 'session' => 'Session.auto_start настройка', + ); + + $lang->install_checklist_desc = array( + 'php_version' => '[Требуется] Если версия PHP равна 5.2.2, то zeroboard не будет установлена из-за бага', + 'permission' => '[Требуется] Путь установки Zeroboard или директория ./files должна иметь права доступа 707', + 'xml' => '[Требуется] XML Библиотека нужна для XML коммуникации', + 'session' => '[Требуется] Файл настроек PHP (php.ini) \'Session.auto_start\' должен быть равен нулю, чтобы zeroboard могла использовать сессии', + 'iconv' => 'Iconv должна быть установлена для конвертирования между UTF-8 и иными языковыми кодировками', + 'gd' => 'GD Библиотека должна быть установлена для использования функции конвертироваия изображений', + ); + + $lang->install_checklist_xml = 'Установить XML Библиотеку'; + $lang->install_without_xml = 'XML Библиотека не установлена'; + $lang->install_checklist_gd = 'Установить GD Библиотеку'; + $lang->install_without_gd = 'GD Библиотека не установлена'; + $lang->install_checklist_gd = 'Установить GD Библиотеку'; + $lang->install_without_iconv = 'Iconv Библиотека не установлена'; + $lang->install_session_auto_start = 'Возможно возникнут проблемы из-за настройки PHP session.auto_start, установленной в 1'; + $lang->install_permission_denied = 'Права доступа пути не установлены в 707'; + + $lang->cmd_agree_license = 'Я согласен с данной Лицензией'; + $lang->cmd_install_fix_checklist = 'Я удоволетворил требуемые условия'; + $lang->cmd_install_next = 'Продолжить установку'; + + $lang->db_desc = array( + 'mysql' => 'Используем mysql*() функцию, чтобы использовать базу данных mysql.
Транзакция отключена из-за того, что файл базы данных создан посредством myisam.', + 'mysql_innodb' => 'Используем innodb чтобы использовать базу данных mysql.
Транзакция включена для innodb', + 'sqlite2' => 'Поддерживает sqlite2, которая сохраняет данные в файл.
Устанавливая, следует размещать файл базы данных в недоступном с веб месте.
(Никогда не тестировалось на стабильность)', + 'sqlite3_pdo' => 'Поддерживает sqlite3 посредством PHP\'s PDO.
Устанавливая, следует размещать файл базы данных в недоступном с веб месте.', + 'cubrid' => 'Используем CUBRID DB.', + ); + + $lang->form_title = 'Пожалуйста, введите дазу данных & Административная Информация'; + $lang->db_title = 'Пожалуйста, введите информацию базы данных'; + $lang->db_type = 'Тип базы данных'; + $lang->select_db_type = 'Пожалуйста, выберите базу данных, которую Вы хотите использовать.'; + $lang->db_hostname = 'Хост базы данных'; + $lang->db_port = 'Порт базы данных'; + $lang->db_userid = 'ID базы данных'; + $lang->db_password = 'Пароль базы данных'; + $lang->db_database = 'Имя базы данных'; + $lang->db_database_file = 'Файл базы данных'; + $lang->db_table_prefix = 'Префикс таблиц'; + + $lang->admin_title = 'Административная Информация'; + + $lang->env_title = 'Конфигурация'; + $lang->use_optimizer = 'Включить Оптимизатор'; + $lang->about_optimizer = 'Если оптимизатор включен, пользователи могут быстро использовать этот сайт, поскольку несколько CSS / JS файлов собраны вместе и сжаты до передачи.
Тем не менее, эта оптимизация может быть проблематичной согласно CSS или JS. Если Вы выключите ее, движок будет работать правильно, хотя и медленее.'; + $lang->use_rewrite = 'Использовать модуль перезаписи (rewrite mod)'; + $lang->about_rewrite = "Если сервер предлагает rewrite mod, длинные URL такие как http://blah/?document_srl=123 могут быть сокращены до http://blah/123"; + $lang->time_zone = 'Часовой пояс'; + $lang->about_time_zone = "Если серверное время и Ваше локальное время не совпадают, Вы можете установить такое же время, как Ваше локальное, используя часовой пояс"; + + $lang->about_database_file = 'Sqlite сохраняет данные в файл. Размещение базы данных должно быть недоступно с веб
Файл базы данных должен иметь права доступа 707.'; + + $lang->success_installed = 'Установка Завершена'; + $lang->success_updated = 'Обновление Завершено'; + + $lang->msg_cannot_proc = 'Невозможно исполнить запрос, поскольку окружение установки не указано'; + $lang->msg_already_installed = 'Zeroboard уже установлена'; + $lang->msg_dbconnect_failed = "Произошла ошибка подключения к базе данных.\nПожалуйста, проверьте иформацию базы данных еще раз"; + $lang->msg_table_is_exists = "Таблица существует в базе данных.\nФайл конфигурации создан заново"; + $lang->msg_install_completed = "Установка завершена.\nСпасибо Вам за выбор ZeroboardXE"; + $lang->msg_install_failed = "Произошла ошибка при создании файла конфигурации."; +?> diff --git a/modules/integration_search/lang/ru.lang.php b/modules/integration_search/lang/ru.lang.php new file mode 100644 index 000000000..26ec9acbb --- /dev/null +++ b/modules/integration_search/lang/ru.lang.php @@ -0,0 +1,31 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->integration_search = "Интеграция Поиска"; + + $lang->sample_code = "Код Примера"; + $lang->about_target_module = "Только выбранные модули являются назначением. Пожалуйста, будте осторожны, устанавливая контроль"; + $lang->about_sample_code = "Вы можете добавить интеграцию поиска на лейаут посредством добавления выше указанного кода"; + $lang->msg_no_keyword = "Введите ключевое слово для поиска"; + + $lang->is_result_text = "%d результатов для '%s'"; + + $lang->is_search_option = array( + 'title' => 'Тема', + 'content' => 'Содержание', + 'title_content' => 'Тема+Содержание', + 'comment' => 'Комментарии', + 'tag' => 'Теги', + ); + + $lang->is_sort_option = array( + 'regdate' => 'Дата Регистрации', + 'comment_count' => 'Кол-во Комментариев', + 'readed_count' => 'Кол-во Хитов', + 'voted_count' => 'Кол-во Голосов', + ); +?> diff --git a/modules/krzip/lang/ru.lang.php b/modules/krzip/lang/ru.lang.php new file mode 100644 index 000000000..db73c3d24 --- /dev/null +++ b/modules/krzip/lang/ru.lang.php @@ -0,0 +1,22 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + // нормальные слова + $lang->krzip = "Корейский Почтовый Индекс"; + $lang->krzip_server_hostname = "Имя сервера для проверки почтового индекса"; + $lang->krzip_server_port = "Порт сервера для проверки почтового индекса"; + $lang->krzip_server_query = "Путь на сервере для проверки почтового индекса"; + + // описания + $lang->about_krzip_server_hostname = "Пожалуйста, введите доменное имя сервера для проверки почтового идекса и получения списка результатов"; + $lang->about_krzip_server_port = "Пожалуйста, введите порт сервера для проверки почтового идекса"; + $lang->about_krzip_server_query = "Пожалуйста, введите URL запроса на сервер для проверки почтового идекса"; + + // ошибки + $lang->msg_not_exists_addr = "Назначение для поиска не существует"; + $lang->msg_fail_to_socket_open = "Невозможно подключиться к серверу для проверки почтового почтового индекса"; +?> diff --git a/modules/layout/lang/ru.lang.php b/modules/layout/lang/ru.lang.php new file mode 100644 index 000000000..161e82f9f --- /dev/null +++ b/modules/layout/lang/ru.lang.php @@ -0,0 +1,32 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->cmd_layout_management = 'Настройки Лейаута'; + $lang->cmd_layout_edit = 'Редактировать Лейаут'; + + $lang->layout_name = 'Имя Лейаута'; + $lang->layout_maker = "Разработчик Лейаута"; + $lang->layout_history = "Обновления"; + $lang->layout_info = "Информация Лейаута"; + $lang->layout_list = 'Список Лейаутов'; + $lang->menu_count = 'Меню'; + $lang->downloaded_list = 'Список Закачек'; + $lang->layout_preview_content = 'Содержимое отображается здесь'; + $lang->not_apply_menu = 'Применить Лейауты'; + + $lang->cmd_move_to_installed_list = "Просмотреть созданный список"; + + $lang->about_downloaded_layouts = "Список скаченных лейаутов"; + $lang->about_title = 'Пожалуйста, введите название, которое легко проверить при подключении к модулю'; + $lang->about_not_apply_menu = 'Все подключенные лейауты модулей будут изменены при включении это опции.'; + + $lang->about_layout = "Модуль лейаутов помогает Вам создать лейаут сайта с легкостью.
Используя настройки лейаута и подключение меню, полная форма сайта будет отображена множеством модулей.
* Теми лейаутами, которые невозможно удалить или изменить, являются лейауты блога и лейауты других модулей."; + $lang->about_layout_code = + "Применения к службе будут проиведены, когда Вы сохраните код лейаут после редактирование. + Пожалуйста, сначала используйте предпросмотр кода и затем сохраните его. + Вы можете обратиться к грамматике шаблонов Zeroboard XE с ZeroboardXE Template."; +?> diff --git a/modules/member/lang/ru.lang.php b/modules/member/lang/ru.lang.php new file mode 100644 index 000000000..a05f38f4a --- /dev/null +++ b/modules/member/lang/ru.lang.php @@ -0,0 +1,197 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->member = 'Пользователь'; + $lang->member_default_info = 'Базовая Информация'; + $lang->member_extend_info = 'Дополнительная Информация'; + $lang->default_group_1 = "Общая Группа"; + $lang->default_group_2 = "Особая Группа"; + $lang->admin_group = "Администативная Группа"; + $lang->remember_user_id = 'Сохранить ID'; + $lang->already_logged = "Вы уже вошли"; + $lang->denied_user_id = 'Извините. Этот ID запрещен.'; + $lang->null_user_id = 'Пожалуйста, введите ID пользователя'; + $lang->null_password = 'Пожалуйста, введите пароль'; + $lang->invalid_authorization = 'Не авторизировано'; + $lang->invalid_user_id= "Указанный ID не существует"; + $lang->invalid_password = 'Неверный пароль'; + $lang->allow_mailing = 'Присоединиться к Списку Рассылки'; + $lang->allow_message = 'Разрешить Прием Сообщений'; + $lang->allow_message_type = array( + 'Y' => 'Принимать Все', + 'N' => 'Отклонять Все', + 'F' => 'Только Друзья', + ); + $lang->denied = 'Отказано'; + $lang->is_admin = 'Суперадминистративные Права'; + $lang->group = 'Присвоенная Группа'; + $lang->group_title = 'Имя Группы'; + $lang->group_srl = 'Номер Группы'; + $lang->signature = 'Подпись'; + $lang->profile_image = 'Изображение Профиля'; + $lang->profile_image_max_width = 'Макс. Ширина'; + $lang->profile_image_max_height = 'Макс. Высота'; + $lang->image_name = 'Имя Изображения'; + $lang->image_name_max_width = 'Макс. Ширина'; + $lang->image_name_max_height = 'Макс. Высота'; + $lang->image_mark = 'Изображение-марка'; + $lang->image_mark_max_width = 'Макс. Ширина'; + $lang->image_mark_max_height = 'Макс. Высота'; + $lang->enable_openid = 'Включить Открытый ID (OpenID)'; + $lang->enable_join = 'Позволить Пользователям Регистрироваться'; + $lang->limit_day = 'Временный Лимит Даты'; + $lang->limit_date = 'Дата Лимита'; + $lang->redirect_url = 'URL после Регистрации'; + $lang->agreement = 'Пользовательское Соглашение Регистрации'; + $lang->accept_agreement = 'Согласен'; + $lang->sender = 'Отправитель'; + $lang->receiver = 'Получатель'; + $lang->friend_group = 'Группа Друзей'; + $lang->default_friend_group = 'Неприсвоенная Группа'; + $lang->member_info = 'Пользовательская Информация'; + $lang->current_password = 'Текущий Пароль'; + $lang->openid = 'OpenID'; + + $lang->webmaster_name = "Имя Веб-мастера"; + $lang->webmaster_email = "Email Веб-мастера"; + + $lang->about_webmaster_name = "Пожалуйста, введите имя веб-мастера, которое будет использоваться для аутентификационных писем или другого адиминистрирования сайта. (по умолчанию : webmaster)"; + $lang->about_webmaster_email = "Пожалуйста, введите email адрес веб-мастера."; + + $lang->search_target_list = array( + 'user_id' => 'ID', + 'user_name' => 'Имя', + 'nick_name' => 'Ник', + 'email_address' => 'Email', + 'regdate' => 'Дата Регистрации', + 'last_login' => 'Дата Последнего Входа', + 'extra_vars' => 'Экстра Перем.', + ); + + $lang->message_box = array( + 'R' => 'Принятые', + 'S' => 'Отправленные', + 'T' => 'Почтовый Ящик', + ); + + $lang->readed_date = "Дата Прочтения"; + + $lang->cmd_login = 'Войти'; + $lang->cmd_logout = 'Выйти'; + $lang->cmd_signup = 'Регистрация'; + $lang->cmd_modify_member_info = 'Изменить Информацию Пользователя'; + $lang->cmd_modify_member_password = 'Изменить Пароль'; + $lang->cmd_view_member_info = 'Информация Пользователя'; + $lang->cmd_leave = 'Покинуть'; + $lang->cmd_find_member_account = 'Найти Информацию Аккаунта'; + + $lang->cmd_member_list = 'Список Пользователей'; + $lang->cmd_module_config = 'Стандартные Настройки'; + $lang->cmd_member_group = 'Увтавление Группами'; + $lang->cmd_send_mail = 'Отправить Почту'; + $lang->cmd_manage_id = 'Управление Запрещенными ID'; + $lang->cmd_manage_form = 'Управление Формой Регистрации'; + $lang->cmd_view_own_document = 'Просмотреть Написанные Статьи'; + $lang->cmd_view_scrapped_document = 'Черновики'; + $lang->cmd_view_saved_document = 'Просмотреть Сохраненные Статьи'; + $lang->cmd_send_email = 'Отправить Почту'; + $lang->cmd_send_message = 'Отправить Сообщение'; + $lang->cmd_reply_message = 'Ответить'; + $lang->cmd_view_friend = 'Дзузья'; + $lang->cmd_add_friend = 'Сделать Другом'; + $lang->cmd_view_message_box = 'Ящик Сообщений'; + $lang->cmd_store = "Сохранить"; + $lang->cmd_add_friend_group = 'Добавить Группу Друзей'; + $lang->cmd_rename_friend_group = 'Изменить Имя Группы Друзей'; + + $lang->msg_email_not_exists = "Email адрес не существует"; + + $lang->msg_alreay_scrapped = 'Эта статья уже в черновиках'; + + $lang->msg_cart_is_null = 'Пожалуйста, выберите назначение'; + $lang->msg_checked_file_is_deleted = '%d вложенных файлов удалено'; + + $lang->msg_find_account_title = 'Информация Аккаунта'; + $lang->msg_find_account_info = 'Это требуемая информация аккаунта.'; + $lang->msg_find_account_comment = 'Пароль будет изменен на указанный выше после нажатия по ссылке ниже.
Пожалуйста, изменить пароль после входа.'; + $lang->msg_auth_mail_sended = 'Аутентификационное почтовое сообщение было отправлено для %s. Пожалуйста, проверьте Вашу почту.'; + $lang->msg_invalid_auth_key = 'Неверный запрос на аутентификацию.
Пожалуйста, попытайтеть найти информацию аккаунта или свяжитесь с администратором.'; + $lang->msg_success_authed = 'Ваш аккаунт был успешно аутентифицирован. Вход произведен. Пожалуйста, измените пароль на Ваш собственный.'; + + $lang->msg_no_message = 'Нет сообщений'; + $lang->message_received = 'Новое сообщение'; + + $lang->msg_new_member = 'Добавить Пользователя'; + $lang->msg_update_member = 'Изменить Информацию Пользователя'; + $lang->msg_leave_member = 'Покинуть'; + $lang->msg_group_is_null = 'Нет зарегистрированной группы'; + $lang->msg_not_delete_default = 'Стандартные объекты не могут быть удалены'; + $lang->msg_not_exists_member = "Пользователь не существует"; + $lang->msg_cannot_delete_admin = 'Административный ID не может быть удален. Пожалуйста, удалить ID из администрации и попробуйте снова.'; + $lang->msg_exists_user_id = 'Этот ID уже существует. Пожалуйста, попробуйте другой.'; + $lang->msg_exists_email_address = 'Этот email адрес уже существует. Пожалуйста, попробуйте другой.'; + $lang->msg_exists_nick_name = 'Этот ник уже существует. Пожалуйста, попробуйте другой.'; + $lang->msg_signup_disabled = 'Вы не можете зарегистрироваться'; + $lang->msg_already_logged = 'Вы уже зарегистрированы'; + $lang->msg_not_logged = 'Пожалуйста, сначала войдите'; + $lang->msg_title_is_null = 'Пожалуйста, введите тему сообщения'; + $lang->msg_content_is_null = 'Пожалуйста, введите содержание'; + $lang->msg_allow_message_to_friend = "Отправка провалена, поскольку получатель принимает сообщения только от друзей"; + $lang->msg_disallow_message = 'Отправка провалена, поскольку получатель отклоняет прием сообщений'; + $lang->msg_insert_group_name = 'Пожалуйста, введите имя группы'; + + $lang->msg_not_uploaded_image_name = 'Имя изображения не может быть зарегистрировано'; + $lang->msg_not_uploaded_image_mark = 'Марка не может быть зарегистрирована'; + + $lang->msg_accept_agreement = 'Вы должны принять Соглашение'; + + $lang->msg_user_denied = 'Введенный ID сейчас запрещен'; + $lang->msg_user_limited = 'Введенный ID может использоваться после %s'; + + $lang->about_user_id = 'Юзер ID должен быть 3~20 знаков и содержать алфавит или цифры, начинаясь с алфафитного знака.'; + $lang->about_password = 'Пароль должен быть 6~20 знаков'; + $lang->about_user_name = 'Имя должно быть 2~20 знаков'; + $lang->about_nick_name = 'Ник должен быть 2~20 знаков'; + $lang->about_email_address = 'Email адрес используется для изменения/получения пароля после его сертификации.'; + $lang->about_homepage = 'Пожалуйста, введите, если у Вас есть веб-сайт'; + $lang->about_blog_url = 'Пожалуйста, введите, если у Вас есть блог'; + $lang->about_birthday = 'Пожалуйста, введите Вашу дату рождения'; + $lang->about_allow_mailing = "Если Вы не присоединитесь к списку рассылки, Вы не сможете получать почтовые сообщения, направленные Вашей группе"; + $lang->about_allow_message = 'Вы можете определить политику принятия сообщений'; + $lang->about_denied = 'Запретить ID'; + $lang->about_is_admin = 'Наделить Суперадминистративными правами'; + $lang->about_description = "Заметки администратора о пользователях"; + $lang->about_group = 'ID может принадлежать нескольким группам'; + + $lang->about_column_type = 'Пожалуйста, установите формат дополнительной формы регистрации'; + $lang->about_column_name = 'Пожалуйста, введите английское название, которое будет использоваться в шаблоне как переменная'; + $lang->about_column_title = 'Это будет отображено, когда пользователь регистрируется или изменяет/просматривает информацию пользователя'; + $lang->about_default_value = 'Вы можете установить значения по умолчанию'; + $lang->about_active = 'Вам следует выбрать активные объекты для отображения на форме регистрации'; + $lang->about_form_description = 'Если Вы введете описание, оно будет отображено на форме регистрации'; + $lang->about_required = 'Сделать элемент обязательным на форме регистрации'; + + $lang->about_enable_openid = 'Позволить пользователям регистрироваться как OpenID'; + $lang->about_enable_join = 'Позволить пользователям регистрироваться'; + $lang->about_limit_day = 'Вы можете ограничить дату сертификации после регистрации'; + $lang->about_limit_date = 'Пользователь не может войти до указанной даты'; + $lang->about_redirect_url = 'Пожалуйста, введите URL, куда пользователи попадут после регистрации. Когда поле пустое, будет установлена страница предшествуящая странице регистрации.'; + $lang->about_agreement = "Регистрационное соглашение будет показано, если оно содержит текст"; + + $lang->about_image_name = "Позволить пользователям использовать изображение вместо текста"; + $lang->about_image_mark = "Позволить пользователям использовать марку перед их именами"; + $lang->about_profile_image = 'Позволить пользователям использовать изображения профиля'; + $lang->about_accept_agreement = "Я прочитал соглашение полностью и согласен"; + + $lang->about_member_default = 'Это будет установлено как стандартная группа при регистрации'; + + $lang->about_openid = 'Когда Вы регистрируетесь как OpenID, базовая информация такая как ID или email адрес будет сохранена на сайте, но пароль и менеджмент сертификации будет произведен над текущим OpenID'; + $lang->about_openid_leave = 'Покидание пользователей с OpenID означает удаление Вашей информации пользователя на сайте.
Если Вы войдете после покидания, это будет разпознано как новый пользователь, поэтому доступ к написанным Вами прежде статьям будет закрыт.'; + + $lang->about_member = "Этот модуль служит для создания/изменения/удаления пользователей, управления их группами и формой регистрации.\nВы можете управлять пользователями посредством создания новых групп, и получить дополнительную информацию, управляя формой регистрации"; + $lang->about_find_member_account = 'Ваша информация аккаунта будет направлена на зарегистрированный email.
Пожалуйста, введите email адрес, который Вы ввели при регистрации и нажмите кнопку "Найти Информацию Аккаунта".
'; +?> diff --git a/modules/menu/lang/ru.lang.php b/modules/menu/lang/ru.lang.php new file mode 100644 index 000000000..9811e89a6 --- /dev/null +++ b/modules/menu/lang/ru.lang.php @@ -0,0 +1,51 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->cmd_menu_insert = 'Создать меню'; + $lang->cmd_menu_management = 'Менеджмент меню'; + + $lang->menu = 'Меню'; + $lang->menu_count = 'Меню No.'; + $lang->menu_management = 'Менеджмент меню'; + $lang->depth = 'Шаг'; + $lang->parent_menu_name = 'Имя родительского меню'; + $lang->menu_name = 'Имя меню'; + $lang->menu_srl = 'SRL меню'; + $lang->menu_id = 'ID меню'; + $lang->menu_url = 'URL меню'; + $lang->menu_open_window = 'Открыть новое окно'; + $lang->menu_expand = 'Раскрыть'; + $lang->menu_img_btn = 'Изображение кнопки'; + $lang->menu_normal_btn = 'Обычное'; + $lang->menu_hover_btn = 'Мышь над'; + $lang->menu_active_btn = 'Когда выбрано'; + $lang->menu_group_srls = 'Группы с доступом'; + $lang->layout_maker = "Маркет лейаута"; + $lang->layout_history = "История обновлений"; + $lang->layout_info = "Информация лейаутов"; + $lang->layout_list = 'Список лейаутов'; + $lang->downloaded_list = 'Список закачек'; + $lang->limit_menu_depth = 'Лимит глубины'; + + $lang->cmd_make_child = 'Добавть дочернее меню'; + $lang->cmd_move_to_installed_list = "Просмотреть созданные меню"; + $lang->cmd_enable_move_menu = "Переместить меню (Перетащите верхнее меню после выделения)"; + $lang->cmd_search_mid = "Поиск меню id"; + + $lang->msg_cannot_delete_for_child = 'Невозможно удалить меню с дочерними меню.'; + + $lang->about_title = 'Пожалуйста, введите название меню, которое легко проверить при подключению к модулю.'; + $lang->about_menu_management = "Управление меню позволяет Вам заключить меню в вабранный лейаут.\nВы можете создать меню до установленной грубины и ввести информацию детально посредством целчка по нему.\nМеню будет разкрыто щелчком по изображению папки.\nЕсли меню не отображается нормально, обновите информацию щелчком по кнопке \"Пересоздать файл кеша\".\n* Меню, созданное за пределами лимита глубины может отображаться неверно."; + $lang->about_menu_name = 'Это имя будет показано, если это не административная книпка или кнопка с изображением.'; + $lang->about_menu_url = "Это URL, связанный с меню.
Вы можете ввести только id значение к ссылке на другой модуль.
Если содержания нет, ничего не произойдет при щелчке по меню."; + $lang->about_menu_open_window = 'Вы можете присвоить это для открытия ссылки в новом окне при щелчке по меню.'; + $lang->about_menu_expand = 'Это позволяет меню оставаться раскрытым, когда древовидное меню (tree_menu.js) используется.'; + $lang->about_menu_img_btn = 'Если Вы регистрируете кнопку с изображением, изображение автоматически заменит текстовую кнопку, и будет показано в лейауте.'; + $lang->about_menu_group_srls = 'Если Вы выберите группу, то только ее члены могут видеть это меню. (если XML файл открыт напрямую, оно будет показано.)'; + + $lang->about_menu = "Модуль меню поможет Вам создать полноценный сайт посредством удобного менеджмента меню, которое расставляет созданные модули и ссылки в лейауты без всякой ручной работы.\nМеню не является менеджером сайта, но оно содержит информацию, которая может связываться с модулями и лейаутами так, что Вы можете выразить различные виды меню."; +?> diff --git a/modules/message/lang/ru.lang.php b/modules/message/lang/ru.lang.php new file mode 100644 index 000000000..793cf7b74 --- /dev/null +++ b/modules/message/lang/ru.lang.php @@ -0,0 +1,10 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->message = 'Отображать ошибки'; + $lang->about_skin = "Вы можете выбрать скин сообщений об ошибках"; +?> diff --git a/modules/module/lang/ru.lang.php b/modules/module/lang/ru.lang.php new file mode 100644 index 000000000..3c9918e11 --- /dev/null +++ b/modules/module/lang/ru.lang.php @@ -0,0 +1,61 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->module_list = "Список Модулей"; + $lang->module_index = "Список Модулей"; + $lang->module_category = "Категория Модуля"; + $lang->module_info = "Информация"; + $lang->add_shortcut = "Добавить Ярлыки"; + $lang->module_action = "Действия"; + $lang->module_maker = "Разработчик Модуля"; + $lang->module_history = "История Обновлений"; + $lang->category_title = "Название Категории"; + $lang->header_text = 'Верхний Колонтитул'; + $lang->footer_text = 'Нижний Колонтитул'; + $lang->use_category = 'Включить Категорию'; + $lang->category_title = 'Название Категории'; + $lang->checked_count = 'Число выбранных статей'; // translator's note: возможно "checked" следует перевести как "проверенных" + $lang->skin_default_info = 'Информация Стандартного Скина'; + $lang->skin_maker = 'Разработчик Скина'; + $lang->skin_maker_homepage = "Домашняя Страница Разработчика"; + $lang->module_copy = "Копировать Модуль"; + + $lang->cmd_add_shortcut = "Добавить Ярлык"; + $lang->cmd_install = "Установить"; + $lang->cmd_update = "Обновить"; + $lang->cmd_manage_category = 'Управление Категориями'; + $lang->cmd_manage_grant = 'Управление Правами Доступа'; + $lang->cmd_manage_skin = 'Управление Скинами'; + $lang->cmd_manage_document = 'Управление Статьями'; + + $lang->msg_new_module = "Создать новый модуль"; + $lang->msg_update_module = "Изменить модуль"; + $lang->msg_module_name_exists = "Имя уже существует. Пожалуйста, попробуйте другое."; + $lang->msg_category_is_null = 'Зарегистрированной категории не существует.'; + $lang->msg_grant_is_null = 'Списка для управления правами доступа не существует.'; + $lang->msg_no_checked_document = 'Нет выбранных статей.'; // translator's note: выше... + $lang->msg_move_failed = 'Невозможно переместить'; + $lang->msg_cannot_delete_for_child = 'Невозможно удалить категорию, имеющую дочерние категории.'; + + $lang->about_browser_title = "Это будет показано в заголовке браузера. Также, это будет использоваться в RSS/Трекбеке."; + $lang->about_mid = "Имя модуля будет использовано как http://address/?mid=Имя_модуля.\n(только латиница, цифры и символ подчеркивания(_) разрешены.)"; + $lang->about_default = "Если выбрано, модуль будет главным на сайте. Для доступа не нужен будет идентификатор модуля."; + $lang->about_module_category = "Это позволяет Вам управлять посредством категорий модулей.\nURL для менеджера модулей Manage module > Категория Модуля ."; + $lang->about_description= 'Это описание только для менеджера.'; + $lang->about_default = 'Если выбрано, этот модуль будет показан, когда пользователи входят на сайт без идентификатора модуля (mid=NoValue).'; + $lang->about_header_text = 'Это содержимое будет показано сверху модуля. (HTML разрешен)'; + $lang->about_footer_text = 'Это содержимое будет показано снизу модуля. (HTML разрешен)'; + $lang->about_skin = 'Вы можете выбрать скин модуля.'; + $lang->about_use_category = 'Если выбрано, функция категорий будет включена.'; + $lang->about_list_count = 'Вы можете установить лимит показа статей на страницу. (по умолчанию: 1)'; + $lang->about_page_count = 'Вы можете установить число страниц внизу. (по умолчанию: 10)'; + $lang->about_admin_id = 'Вы можете разрешить менеджеру иметь полные права доступа к этому модулю.\nВы можете ввести несколько ID, используя
запятую \n(но менеджер модуля не имеет права доступа к странице администрирования сайта.)'; + $lang->about_grant = 'Если Вы отключите все права доступа для отдельного объекта, не прошедшие процедуру входа на сайт пользователи получат доступ.'; + $lang->about_module = "Zeroboard XE состоит из модулей, за исключением базовой библиотеки.\n Управление модулем покажет все установленные модули и поможет управлять ими.\nПосредством функции добавления ярлыка, Вы можете легче управлять часто используемыми модулями."; + + $lang->about_extra_vars_default_value = 'Если нужно несколько значений по умолчанию, разделите их запятыми(,).'; +?> diff --git a/modules/opage/lang/ru.lang.php b/modules/opage/lang/ru.lang.php new file mode 100644 index 000000000..59fa5cd63 --- /dev/null +++ b/modules/opage/lang/ru.lang.php @@ -0,0 +1,15 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->opage = "Внешняя Страница"; + $lang->opage_path = "Расположение Внешнего Документа"; + $lang->opage_caching_interval = "Установить Время Кеширования"; + + $lang->about_opage = "Этот модуль позволяет использовать внешние HTML или PHP файлы в Zeroboard XE.
Требует ввода абсолютного или относительного пути. Если URL начинается с 'http://', внешняя страница с другого сервера будет показана."; + $lang->about_opage_path= "Пожалуйста, введите размещение внешнего документа.
Абсолютный путь как '/path1/path2/sample.php', так и относительный как '../path2/sample.php' могут быть использованы.
Если Вы введете путь как 'http://url/sample.php', результат будет сначала получен и затем показан.
Это текущий абсолютный путь к Zeroboard XE.
"; + $lang->about_opage_caching_interval = "Единица измерения равна одной минуте. Это отображает временно сохраненные данные для присвоенного времени.
Рекомендуется устанавливать разумное время кеширования, если множество ресурсов нуждаются в показе данных с других серверов.
Значение 0 отключает кеширование."; +?> diff --git a/modules/page/lang/ru.lang.php b/modules/page/lang/ru.lang.php new file mode 100644 index 000000000..5e2e09aa5 --- /dev/null +++ b/modules/page/lang/ru.lang.php @@ -0,0 +1,11 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->page = "Страница"; + $lang->about_page = "Это модуль блога, который создает полную страницу.\nИспользуя последние и другие виджеты, Вы можете создавать динамические страницы. Посредством компонента редактора, Вы можете также создать различные вариации страницы.\nURL модуля следует тем же правилам, что и другие модули: mid=имя_модуля.\n Если он выбран как модуль по умолчанию, то он будет главной страницей сайта."; + $lang->cmd_page_modify = "Изменить"; +?> diff --git a/modules/point/lang/ru.lang.php b/modules/point/lang/ru.lang.php new file mode 100644 index 000000000..c3d8cb842 --- /dev/null +++ b/modules/point/lang/ru.lang.php @@ -0,0 +1,47 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->point = "Поинты"; + $lang->level = "Уровень"; + + $lang->about_point_module = "Вы можете распределять поинты за написание/добавление комментариев, закачку/скачку файлов.
Модуль поинтов только конфигурирует настройки, а набор поинтов будет осуществлять, если только аддон поинтов будет активирован"; + $lang->about_act_config = "Каждый модуль, такой как форум/блог, имеет имеет свои действия, такие как\"написание/удаление/добавление комментариев/удаление комментариев\".
Вы можете просто добавить значения действий, чтобы связать ситему поинтов, за исключением форума/блога.
Запятая(,) используется как разделитель значений."; + + $lang->max_level = 'Макс. Уровень'; + $lang->about_max_level = 'Вы можете установить максимальный уровень. Иконки уровней должны быть присвоены. (макс. значение равно 1000)'; + + $lang->level_icon = 'Иконка Уровня'; + $lang->about_level_icon = 'Путь иконок уровней "./module/point/icons/[level].gif" и максимальный уровень может меняться с набором иконок. Поэтому будте осторожны'; + + $lang->point_name = 'Имя Поинта'; + $lang->about_point_name = 'Вы можете дать имя или единицу измерения для поинта'; + + $lang->level_point = 'Уровень Поинтов'; + $lang->about_level_point = 'Уровень будет изменен, когда поинты достигают каждого уровня поинтов или падают ниже его'; + + $lang->disable_download = 'Запретить Скачивание'; + $lang->about_disable_download = "Это запретит скачивание файлов, когда не хватает достаточного кол-ва поинтов. (За исключением файлов изображений)"; + + $lang->about_module_point = "Вы можете установть поинты для каждого модуля, а модули, не имеющие значения будут использовать значение по умолчанию для поинтов.
Все поинты будут восстановлены при обратном действии."; + + $lang->point_signup = 'Присвоить'; + $lang->point_insert_document = 'При Написании'; + $lang->point_delete_document = 'При Удалении'; + $lang->point_insert_comment = 'При Добавлении Комментариев'; + $lang->point_delete_comment = 'При Удалении Комментариев'; + $lang->point_upload_file = 'При Закачке Файлов'; + $lang->point_delete_file = 'При Скачке Файлов'; + $lang->point_download_file = 'При Скачке Файлов (кроме изображений)'; + + + $lang->cmd_point_config = 'Настройки По Умолчанию'; + $lang->cmd_point_module_config = 'Настройки Модуля'; + $lang->cmd_point_act_config = 'Настройки Действий'; + $lang->cmd_point_member_list = 'Список Поинтов Пользователей'; + + $lang->msg_cannot_download = "У Вас нет достаточного количества поитов, чтобы иметь разрешение скачивать файлы."; +?> diff --git a/modules/poll/lang/ru.lang.php b/modules/poll/lang/ru.lang.php new file mode 100644 index 000000000..919a3df14 --- /dev/null +++ b/modules/poll/lang/ru.lang.php @@ -0,0 +1,38 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->poll = "Опрос"; + $lang->poll_stop_date = "Дата Истечения"; + $lang->poll_join_count = "Участников"; + $lang->poll_checkcount = "Число полей выбора"; + + $lang->cmd_poll_list = 'Просмотреть список опросов'; + $lang->cmd_delete_checked_poll = 'Удалить выбранные опросы'; + $lang->cmd_apply_poll = 'Применеть опрос'; + $lang->cmd_view_result = 'Предпросмотр результата'; + $lang->cmd_delete_checked_poll = 'Удалить выбранные опросы'; // translator's remark for devs: double entry, already has $lang->cmd_delete_checked_poll + + $lang->success_poll = 'Благодарим за присоединение к опросу.'; + + $lang->msg_already_poll = 'Вы уже голосовали!'; + $lang->msg_cart_is_null = 'Пожалуйста, выберите статью для удаления.'; + $lang->msg_checked_poll_is_deleted = '%d опросов удалено.'; + $lang->msg_check_poll_item = 'Пожалуйста, выберите ответ, чтобы проголосовать.\n(Требуемые объекты могут различаться для каждого из опросов.)'; + $lang->msg_cart_is_null = 'Пожалуйста, выберите опрос для удаления.'; // translator's remark for devs: double entry, already has it... + $lang->msg_checked_poll_is_deleted = '%d опросов удалено.'; // translator's remark for devs: double entry, already has it... + $lang->msg_poll_not_exists = 'Выбранный опрос не существует.'; + + $lang->cmd_null_item = "Не выбран ответ для голосования. Пожалуйста, попробуйте еще."; + + $lang->confirm_poll_submit = "Подтверждаете ли Вы размещение опроса?"; + + $lang->search_target_list = array( + 'title' => 'Заголовок', + 'regdate' => 'Дата Размещения', // // translator's remark: this may be as "Дата Регистрации" + 'ipaddress' => 'IP-адрес', + ); +?> diff --git a/modules/rss/lang/ru.lang.php b/modules/rss/lang/ru.lang.php new file mode 100644 index 000000000..f7876c22e --- /dev/null +++ b/modules/rss/lang/ru.lang.php @@ -0,0 +1,25 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + // главные слова + $lang->rss_disable = "Отключить RSS"; + $lang->rss_type = "Тип RSS"; + $lang->open_rss = 'Открыть RSS'; + $lang->open_rss_types = array( + 'Y' => 'Открыть все', + 'H' => 'Открыть резюме', + 'N' => 'Не открывать', + ); + + // для описаний + $lang->about_rss_disable = "Если выбрано, RSS будет отключен."; + $lang->about_rss_type = "Вы можете присвоить тип RSS."; + $lang->about_open_rss = 'Вы можете выбрать для того, чтобы RSS доступен публично.\nНезависимо от разрешений для статьи, RSS будет доступна публично согласно ее настройке.'; + + // для ошибок + $lang->msg_rss_is_disabled = "Функция RSS быключена."; +?> diff --git a/modules/spamfilter/lang/ru.lang.php b/modules/spamfilter/lang/ru.lang.php new file mode 100644 index 000000000..0e7b5a979 --- /dev/null +++ b/modules/spamfilter/lang/ru.lang.php @@ -0,0 +1,32 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + // действия + $lang->cmd_denied_ip = "Черный Список IP-адресов"; + $lang->cmd_denied_word = "Черный Список Слов"; + + // главные слова + $lang->spamfilter = "Фильтр спама"; + $lang->denied_ip = "IP в черный список"; + $lang->interval = "Интервал фильтрования спама"; + $lang->limit_count = "Лимит публикаций"; + $lang->check_trackback = "Проверять трекбек"; + $lang->word = "Слово"; + + // описание + $lang->about_interval = "Все попытки разместить статьи в установленное время будут заблокированы."; + $lang->about_limit_count = "Если Вы вышли за лимит публикаций (статей/комментариев),\n Ваша статья будет разпознана как спам, и Ваш IP-адрес будет добавлен в черный список."; + $lang->about_denied_ip = "Вы можете добавить в черный список диапазон IP-адресов как 127.0.0.*, используя знак звездочки (*)."; + $lang->about_denied_word = "Когда Вы добавляете слово в черный список,\n статьи с этим словом не будут опубликованы"; + $lang->about_check_trackback = "Только трекбек для оного IP на статью может быть разрешен."; + + // для отправки сообщений + $lang->msg_alert_limited_by_config = 'Размещение статьи с интервалом в %s секунд не разрешено.\n Если Вы будете многократно пытаться это сделать, Ваш IP-адрес может быть добавлен в черный список.'; + $lang->msg_alert_denied_word = 'Слово "%s" запрещено для публикации.'; + $lang->msg_alert_registered_denied_ip = 'Ваш IP-адрес занесен в черный список,\n поэтому Вы можете иметь ограничения на полноценное использование этого сайта.\n Если у Вас есть вопросы насчет этого, пожалуйста, сообщите администратору сайта.'; + $lang->msg_alert_trackback_denied = 'Разрешен только один трекбек на статью.'; +?> diff --git a/modules/trackback/lang/ru.lang.php b/modules/trackback/lang/ru.lang.php new file mode 100644 index 000000000..7007e6298 --- /dev/null +++ b/modules/trackback/lang/ru.lang.php @@ -0,0 +1,24 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->cmd_delete_checked_trackback = 'Удалить выбранные трекбеки'; + + $lang->msg_cart_is_null = 'Пожалуйста, выберите трекбек для удаления.'; + $lang->msg_checked_trackback_is_deleted = '%d трекбеков удалено.'; + + $lang->search_target_list = array( + 'url' => 'URL Назначения', + 'blog_name' => 'Имя Сайта', + 'title' => 'Заголовок', + 'excerpt' => 'Выдержка', + 'regdate' => 'Дата Отправки', + 'ipaddress' => 'IP-адрес', + ); + + $lang->enable_trackback = "Включить трекбек"; + $lang->about_enable_trackback = "Эта опция включает/выключает фукцию трекбека."; +?> diff --git a/modules/ttimporter/lang/ru.lang.php b/modules/ttimporter/lang/ru.lang.php new file mode 100644 index 000000000..1d9ae75b0 --- /dev/null +++ b/modules/ttimporter/lang/ru.lang.php @@ -0,0 +1,21 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->ttimporter = "Имортировать данные Tetter Tools"; + $lang->about_tt_importer = "Вы можете ипортировать дынне Tetter Tools в любой модуль.\n Вложенный файл будет напрямую скачан через Веб, поэтому, пожалуйста, убедитесь в том, что оригинальный Tetter Tools работает."; + + $lang->target_module = "Модуль назначения"; + $lang->target_file = "XML файл назначения"; + $lang->target_url = "URL Блога"; + + $lang->cmd_continue = 'Продолжить'; + + $lang->msg_no_xml_file = 'Невозможно найти XML файл! Пожалуйста, проверьте URL.'; + $lang->msg_invalid_xml_file = 'Неверный тип XML файла!'; + $lang->msg_importing = 'Импортирование: %d (если будет задержка, пожалуйста, нажмите кнопку "Продолжить".)'; + $lang->msg_import_finished = 'Импортировано: %d (согласно состоянию, некоторые данные могут быть импортированы неверно.)'; +?> diff --git a/modules/widget/lang/ru.lang.php b/modules/widget/lang/ru.lang.php new file mode 100644 index 000000000..8f4f06f68 --- /dev/null +++ b/modules/widget/lang/ru.lang.php @@ -0,0 +1,43 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->cmd_generate_code = 'Генерировать Код'; + + $lang->widget_name = 'Имя Виджета'; + $lang->widget_maker = 'Разработчик Виджета'; + $lang->widget_history = 'История Обновлений'; + $lang->widget_info = 'Информация Виджета'; + $lang->widget_code = 'Код'; + $lang->widget_cache = 'Кеш'; + + $lang->widget_fix_width = 'Фиксированная Ширина'; + $lang->widget_width = 'Ширина'; + $lang->widget_position = 'Позиция'; + $lang->widget_position_none = 'Следующая Строка'; + $lang->widget_position_left = 'Лево'; + $lang->widget_position_right = 'Право'; + $lang->widget_margin = 'Поля'; + $lang->widget_margin_top = 'Верхнее Поле'; + $lang->widget_margin_right = 'Правое Поле'; + $lang->widget_margin_bottom = 'Шижнее Поле'; + $lang->widget_margin_left= 'Левое Поле'; + $lang->about_widget_fix_width = 'Пожалуйста, установите для фиксирования ширины.'; + $lang->about_widget_width = 'Пожалуйста, установите ширину виджета.'; + $lang->about_widget_position = 'Пожалуйста, выберите позицию виджета, если Вы хотите отобразить несколько виджетов в одной строке.'; + $lang->about_widget_margin = "Вы можете установить поля виждета, т.е. его отступы со всех четырех сторон."; + $lang->about_widget_cache = 'Кешированные данные будут использоваться на указанный срок.'; + + $lang->generated_code = 'Сгенерированный Код'; + + $lang->msg_widget_is_not_exists = '%s виджет не существует.'; + $lang->msg_widget_object_is_null = '%s объектов виджета не могут быть созданы.'; + $lang->msg_widget_proc_is_null = 'proc() %s виджета не может быть исполнена.'; + + $lang->about_widget_code = 'Пожалуйста, сначала введите тредуемые значения, и затем щелкните кнопку [Генерировать Код] для генерации кода и добавления его в файл шаблона.'; + $lang->about_widget_code_in_page = 'После ввода требуемых значений, нажмите пнопку [Добавить], чтобы вставить код виджета в страницу.'; + $lang->about_addon = "Виджет -- это маленькая самостоятельная программа, используемая в лейауте или модуле страниц.\n Он может быть связан с внутренним модулем или внешними открытыми API. Посредством его детального конфигурирования можно добиться широкого его применения. \n Вы можете напрямую добавить виджет, используя функцию генерирования кода без использования модулей страниц или лейаутов Zeroboard XE."; +?> From e64de1e2c394ea8282538ab1dba93ae658f52315 Mon Sep 17 00:00:00 2001 From: haneul Date: Tue, 20 Nov 2007 08:47:30 +0000 Subject: [PATCH 005/265] =?UTF-8?q?[3026]=20=EC=97=90=EC=84=9C=20=EC=9E=98?= =?UTF-8?q?=EB=AA=BB=EB=90=9C=20htaccess=20=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3028 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- .htaccess | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/.htaccess b/.htaccess index a64a94bdc..04b152121 100644 --- a/.htaccess +++ b/.htaccess @@ -6,54 +6,54 @@ RewriteRule ^([a-zA-Z0-9_]+)/modules/(.*) ./modules/$2 [L] RewriteRule ^([a-zA-Z0-9_]+)/common/(.*) ./common/$2 [L] # page -RewriteRule ^([a-zA-Z0-9_]+)/([[:digit:]]+)page$ /~syhan/zbxe/index.php?mid=$1&page=$2 [L] +RewriteRule ^([a-zA-Z0-9_]+)/([[:digit:]]+)page$ ./index.php?mid=$1&page=$2 [L] # total rss -RewriteRule ^rss/([[:digit:]]+){0,14}/([[:digit:]]+){0,14}/([[:digit:]]+)$ /~syhan/zbxe/index.php?module=rss&act=rss&start_date=$1&end_date=$2&page=$3 [L] -RewriteRule ^rss/([[:digit:]]+)$ /~syhan/zbxe/index.php?module=rss&act=rss&page=$1 [L] -RewriteRule ^rss$ /~syhan/zbxe/index.php?module=rss&act=rss [L] +RewriteRule ^rss/([[:digit:]]+){0,14}/([[:digit:]]+){0,14}/([[:digit:]]+)$ ./index.php?module=rss&act=rss&start_date=$1&end_date=$2&page=$3 [L] +RewriteRule ^rss/([[:digit:]]+)$ ./index.php?module=rss&act=rss&page=$1 [L] +RewriteRule ^rss$ ./index.php?module=rss&act=rss [L] # administrator page -RewriteRule ^admin$ /~syhan/zbxe/index.php?module=admin [L] +RewriteRule ^admin$ ./index.php?module=admin [L] # mid + act -RewriteRule ^([a-zA-Z0-9_]+)/api$ /~syhan/zbxe/index.php?mid=$1&act=api [L] +RewriteRule ^([a-zA-Z0-9_]+)/api$ ./index.php?mid=$1&act=api [L] # document permanent link -RewriteRule ^([[:digit:]]+)$ /~syhan/zbxe/index.php?document_srl=$1 [L] +RewriteRule ^([[:digit:]]+)$ ./index.php?document_srl=$1 [L] # document + act link -RewriteRule ^([[:digit:]]+)/([a-zA-Z0-9_]+)$ /~syhan/zbxe/index.php?document_srl=$1&act=$2 [L] +RewriteRule ^([[:digit:]]+)/([a-zA-Z0-9_]+)$ ./index.php?document_srl=$1&act=$2 [L] # mid + document link -RewriteRule ^([a-zA-Z0-9_]+)/([[:digit:]]+)$ /~syhan/zbxe/index.php?mid=$1&document_srl=$2 [L] +RewriteRule ^([a-zA-Z0-9_]+)/([[:digit:]]+)$ ./index.php?mid=$1&document_srl=$2 [L] # mid + act link -RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)$ /~syhan/zbxe/index.php?mid=$1&act=$2 [L] +RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)$ ./index.php?mid=$1&act=$2 [L] # mid + page link -RewriteRule ^([a-zA-Z0-9_]+)/page/([[:digit:]]+)$ /~syhan/zbxe/index.php?mid=$1&page=$2 [L] +RewriteRule ^([a-zA-Z0-9_]+)/page/([[:digit:]]+)$ ./index.php?mid=$1&page=$2 [L] # mid + category link -RewriteRule ^([a-zA-Z0-9_]+)/category/([[:digit:]]+)$ /~syhan/zbxe/index.php?mid=$1&category=$2 [L] +RewriteRule ^([a-zA-Z0-9_]+)/category/([[:digit:]]+)$ ./index.php?mid=$1&category=$2 [L] # mid + category + page -RewriteRule ^([a-zA-Z0-9_]+)/category/([[:digit:]]+)/page/([[:digit:]]+)$ /~syhan/zbxe/index.php?mid=$1&category=$2&page=$3 [L] +RewriteRule ^([a-zA-Z0-9_]+)/category/([[:digit:]]+)/page/([[:digit:]]+)$ ./index.php?mid=$1&category=$2&page=$3 [L] # mid + search target regdate (year+month) -RewriteRule ^([a-zA-Z0-9_]+)/([[:digit:]]+)/([[:digit:]]+)$ /~syhan/zbxe/index.php?mid=$1&search_target=regdate&search_keyword=$2$3 [L] +RewriteRule ^([a-zA-Z0-9_]+)/([[:digit:]]+)/([[:digit:]]+)$ ./index.php?mid=$1&search_target=regdate&search_keyword=$2$3 [L] # mid + search target regdate (year+month+day) -RewriteRule ^([a-zA-Z0-9_]+)/([[:digit:]]+)/([[:digit:]]+)/([[:digit:]]+)$ /~syhan/zbxe/index.php?mid=$1&search_target=regdate&search_keyword=$2$3$4 [L] +RewriteRule ^([a-zA-Z0-9_]+)/([[:digit:]]+)/([[:digit:]]+)/([[:digit:]]+)$ ./index.php?mid=$1&search_target=regdate&search_keyword=$2$3$4 [L] # mid + search target tag -RewriteRule ^([a-zA-Z0-9_]+)/tag/(.*)$ /~syhan/zbxe/index.php?mid=$1&search_target=tag&search_keyword=$2 [L] +RewriteRule ^([a-zA-Z0-9_]+)/tag/(.*)$ ./index.php?mid=$1&search_target=tag&search_keyword=$2 [L] # mid + search target writer -RewriteRule ^([a-zA-Z0-9_]+)/writer/(.*)$ /~syhan/zbxe/index.php?mid=$1&search_target=nick_name&search_keyword=$2 [L] +RewriteRule ^([a-zA-Z0-9_]+)/writer/(.*)$ ./index.php?mid=$1&search_target=nick_name&search_keyword=$2 [L] # module link -RewriteRule ^([a-zA-Z0-9_]+)(/){0,1}$ /~syhan/zbxe/index.php?mid=$1 [L] +RewriteRule ^([a-zA-Z0-9_]+)(/){0,1}$ ./index.php?mid=$1 [L] # css/img/js/htc등의 경로 처리 -RewriteRule ^(.+)/common/js/iePngFix.htc /~syhan/zbxe/common/js/iePngFix.htc [L] +RewriteRule ^(.+)/common/js/iePngFix.htc ./common/js/iePngFix.htc [L] From 4660abb3f23408d831c643796ad87d51f42de0f4 Mon Sep 17 00:00:00 2001 From: zero Date: Wed, 21 Nov 2007 01:39:43 +0000 Subject: [PATCH 006/265] =?UTF-8?q?=EA=B4=80=EB=A6=AC=EC=9E=90=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EB=94=94=EC=9E=90=EC=9D=B8=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3029 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- common/css/default.css | 18 ++++++++++++++++++ modules/admin/tpl/css/admin.css | 6 +++--- modules/admin/tpl/css/admin_layout.css | 20 ++++++++++---------- modules/admin/tpl/layout.html | 6 +++--- modules/blog/tpl/index.html | 8 ++++---- modules/board/tpl/index.html | 2 +- modules/comment/tpl/comment_list.html | 2 +- modules/document/tpl/document_list.html | 2 +- modules/file/tpl/file_list.html | 6 +++--- modules/guestbook/tpl/index.html | 2 +- modules/opage/tpl/index.html | 2 +- modules/page/tpl/index.html | 2 +- modules/poll/tpl/poll_list.html | 4 ++-- modules/trackback/tpl/trackback_list.html | 2 +- 14 files changed, 50 insertions(+), 32 deletions(-) diff --git a/common/css/default.css b/common/css/default.css index deae4c967..bcc6fe48a 100644 --- a/common/css/default.css +++ b/common/css/default.css @@ -41,11 +41,29 @@ form { margin:0; padding:0; } .w40 { width:40px; } .w60 { width:60px; } +.w70 { width:70px; } .w80 { width:80px; } +.w90 { width:90px; } .w100 { width:100px; } +.w110 { width:110px; } .w120 { width:120px; } +.w130 { width:130px; } .w140 { width:140px; } +.w150 { width:150px; } +.w160 { width:160px; } +.w170 { width:170px; } +.w180 { width:180px; } +.w190 { width:190px; } .w200 { width:200px; } +.w210 { width:210px; } +.w220 { width:220px; } +.w230 { width:230px; } +.w240 { width:240px; } +.w250 { width:250px; } +.w260 { width:260px; } +.w270 { width:270px; } +.w280 { width:280px; } +.w290 { width:290px; } .w300 { width:300px; } .w400 { width:400px; } diff --git a/modules/admin/tpl/css/admin.css b/modules/admin/tpl/css/admin.css index b91adb06c..c0459909f 100644 --- a/modules/admin/tpl/css/admin.css +++ b/modules/admin/tpl/css/admin.css @@ -20,7 +20,7 @@ h3 .gray { color:#9d9d9d;} .adminTable { width:100%; border-left:1px solid #E3E3E2; border-top:1px solid #E3E3E2; margin-bottom:10px; table-layout:fixed;} .adminTable caption { background:url("../images/s_application.gif") no-repeat 3px 5px; padding:6px 5px 4px 22px; text-align:left; border:1px solid #E3E3E2; border-bottom:none; font-weight:bold; background-color:#F9F8F5; color:#5E6266; } -.adminTable th { background-color:#FAF8F4; padding:5px; font-weight:normal; text-align:left; padding-left:10px; color:#606060; border-right:1px solid #E3E3E2; border-bottom:1px solid #E3E3E2; white-space:nowrap; } +.adminTable th { overflow:hidden; background-color:#FAF8F4; padding:5px; font-weight:normal; text-align:left; padding-left:10px; color:#606060; border-right:1px solid #E3E3E2; border-bottom:1px solid #E3E3E2; } .adminTable th.button { text-align:right; } .adminTable th.centerButton { text-align:center; } @@ -44,7 +44,7 @@ h3 .gray { color:#9d9d9d;} .adminTable th a.green { color:#218E08; } .adminTable th select { height:20px; } -.adminTable td { background-color:#FFFFFF; padding:5px; font-weight:normal; text-align:left; padding-left:10px; color:#5A5A5A; border-right:1px solid #E3E3E2; border-bottom:1px solid #E3E3E2;} +.adminTable td { overflow:hidden; background-color:#FFFFFF; padding:5px; font-weight:normal; text-align:left; padding-left:10px; color:#5A5A5A; border-right:1px solid #E3E3E2; border-bottom:1px solid #E3E3E2;} .adminTable td.tahoma { font-family:tahoma; font-size:7pt; } .adminTable td.tahoma a { font-family:tahoma; font-size:7pt; } @@ -77,7 +77,7 @@ h3 .gray { color:#9d9d9d;} .adminTable td .graph .num { position:relative; background:#ffffff; color:#636363; font:.9em Tahoma; padding-left:10px; white-space:nowrap;} .admin_news { width:540px; float:left; margin-right:10px; } -.admin_link { width:250px; float:right; } +.admin_link { width:300px; float:right; } select.time_zone { width:70%; position:relative; top:4px; } .gap1 { margin-top:.8em; } diff --git a/modules/admin/tpl/css/admin_layout.css b/modules/admin/tpl/css/admin_layout.css index 42dfdea5f..1db365577 100644 --- a/modules/admin/tpl/css/admin_layout.css +++ b/modules/admin/tpl/css/admin_layout.css @@ -2,31 +2,31 @@ body { background:url("../images/admin_background.gif") repeat-x left top; background-color:#DBD8D3; } -#adminLayout { background:url("../images/admin_logo.gif") no-repeat left top; background-color:#F8F6F2; overflow:hidden; width:1000px; border-right:1px solid #B2B2B2; margin:5px 0 0 5px; } +#adminLayout { background:url("../images/admin_logo.gif") no-repeat left top; background-color:#F8F6F2; overflow:hidden; width:1050px; border-right:1px solid #B2B2B2; margin:5px 0 0 5px; } -#adminContentBody { width:800px; float:left; background-color:#FFFFFF; padding:25px 10px 20px 10px; vertical-align:top; background:url(../images/admin_top_bg.gif) repeat-x left top; background-color:#FFFFFF; } +#adminContentBody { width:850px; float:left; background-color:#FFFFFF; padding:25px 10px 20px 10px; vertical-align:top; background:url(../images/admin_top_bg.gif) repeat-x left top; background-color:#FFFFFF; } -#adminLayoutBottom { background:url("../images/admin_bottom_bg.gif") repeat-x left top; height:3px; clear:both; overflow:hidden; width:1001px; margin:0 0 0 5px; } +#adminLayoutBottom { background:url("../images/admin_bottom_bg.gif") repeat-x left top; height:3px; clear:both; overflow:hidden; width:1051px; margin:0 0 0 5px; } #adminMenuContent { width:179px; float:left; margin-top:70px; padding-bottom:20px; vertical-align:top; background:none; overflow:hidden; border-right:1px solid #B2B2B2; } -#adminMenuContent .adminInfoBox { border:1px solid #E3E3E2; padding:3px; margin:0 0 0 8px; width:130px; background-color:#FFFFFF; overflow:hidden; width:154px; margin-bottom:10px;} -#adminMenuContent .adminInfoBox .adminInfo { border:1px solid #E3E3E2; padding:5px 3px 3px 23px; background:url("../images/icon_key.gif") no-repeat 3px 3px; color:#555555; font-weight:bold; overflow:hidden; background-color:#F8F6F2; } -#adminMenuContent .adminInfoBox .adminInfo div.expandButton { float:right; height:16px; overflow:hidden; } +#adminMenuContent .adminInfoBox { border:1px solid #E3E3E2; padding:3px; margin:0 0 0 8px; width:130px; background-color:#FFFFFF; width:154px; margin-bottom:10px;} +#adminMenuContent .adminInfoBox .adminInfo { border:1px solid #E3E3E2; padding:5px 3px 3px 23px; background:url("../images/icon_key.gif") no-repeat 3px 5px; color:#555555; font-weight:bold; background-color:#F8F6F2; } +#adminMenuContent .adminInfoBox .adminInfo div.expandButton { float:right; height:16px; } #adminMenuContent .adminInfoBox div.logoutButton { margin-top:5px; text-align:center; clear:both; } #adminMemberInfo { padding:10px 5px 10px 24px; background:url("../images/icon_user.gif") no-repeat 5px 8px; color:#336699; font-weight:bold; letter-spacing:-1px;} -#adminMenuContent h3 { border:1px solid #E3E3E2; border-top:none; color:#555555; font-size:1em; text-indent:none; padding:6px 5px 3px 25px; white-space:nowrap; margin:0 0 0 8px; width:130px; overflow:hidden;} +#adminMenuContent h3 { border:1px solid #E3E3E2; border-top:none; color:#555555; font-size:1em; text-indent:none; padding:6px 0 3px 25px; margin:0 0 0 8px; width:135px;} #adminMenuContent h3 a { color:#555555; text-decoration:none; } -#adminMenuContent h3 span.expandButton { float:right; height:16px; overflow:hidden; } -#adminMenuContent h3.summary { background:url("../images/icon_summary.gif") no-repeat 3px 3px; background-color:#FFFFFF; margin-top:0px; border-top:1px solid #E3E3E2; } +#adminMenuContent h3 span.expandButton { float:right; padding:none; margin:none; height:16px; white-space:nowrap; overflow:hidden;} +#adminMenuContent h3.summary { background:url("../images/icon_summary.gif") no-repeat 3px 5px; background-color:#FFFFFF; margin-top:0px; border-top:1px solid #E3E3E2; } #adminMenuContent h3.service { background:url("../images/icon_service_module.gif") no-repeat 3px 5px; background-color:#FFFFFF; } #adminMenuContent h3.manager { background:url("../images/icon_manager_module.gif") no-repeat 3px 5px; background-color:#FFFFFF;} #adminMenuContent h3.utility { background:url("../images/icon_utility_module.gif") no-repeat 3px 5px; background-color:#FFFFFF;} #adminMenuContent h3.accessory { background:url("../images/icon_accessory_module.gif") no-repeat 3px 5px; background-color:#FFFFFF;} #adminMenuContent h3.base { background:url("../images/icon_base_module.gif") no-repeat 3px 5px; background-color:#FFFFFF;} -#adminMenuContent ul { width:170px; overflow:hidden; } +#adminMenuContent ul { width:170px; } #adminMenuContent ul li { background-color:#F8F6F3; list-style:none; padding:5px 10px 3px 10px; margin-left:8px; white-space:nowrap; overflow:hidden; color:#888785; border-bottom:1px solid #E3E3E2; cursor:pointer; } #adminMenuContent ul li:hover { background-color:#EFE6D3; border-left:1px solid #E3E3E2; border-right:1px solid #E3E3E2;} #adminMenuContent li.on { background-color:#EFE6D3; border-left:1px solid #E3E3E2; border-right:1px solid #E3E3E2;} diff --git a/modules/admin/tpl/layout.html b/modules/admin/tpl/layout.html index a9a322f1f..7a380b402 100644 --- a/modules/admin/tpl/layout.html +++ b/modules/admin/tpl/layout.html @@ -9,6 +9,7 @@
{$lang->admin_info}
toggle
+

- {$lang->admin_index} + {$lang->admin_index}

- {$val} - toggle + {$val}

    diff --git a/modules/blog/tpl/index.html b/modules/blog/tpl/index.html index 6f1e417b9..aa8653fe3 100644 --- a/modules/blog/tpl/index.html +++ b/modules/blog/tpl/index.html @@ -8,12 +8,12 @@ -+---+++ diff --git a/modules/board/tpl/index.html b/modules/board/tpl/index.html index e15582afa..25249868e 100644 --- a/modules/board/tpl/index.html +++ b/modules/board/tpl/index.html @@ -8,7 +8,7 @@
    {$lang->no}
    -+diff --git a/modules/comment/tpl/comment_list.html b/modules/comment/tpl/comment_list.html index b0af9356f..6dd8363e8 100644 --- a/modules/comment/tpl/comment_list.html +++ b/modules/comment/tpl/comment_list.html @@ -23,7 +23,7 @@ - + - + diff --git a/modules/guestbook/tpl/index.html b/modules/guestbook/tpl/index.html index 0058321f3..73ca611b1 100644 --- a/modules/guestbook/tpl/index.html +++ b/modules/guestbook/tpl/index.html @@ -8,7 +8,7 @@
    - diff --git a/modules/document/tpl/document_list.html b/modules/document/tpl/document_list.html index c5c0e3891..26fe4d655 100644 --- a/modules/document/tpl/document_list.html +++ b/modules/document/tpl/document_list.html @@ -26,7 +26,7 @@
    - diff --git a/modules/file/tpl/file_list.html b/modules/file/tpl/file_list.html index 8b33fa8c2..a37840805 100644 --- a/modules/file/tpl/file_list.html +++ b/modules/file/tpl/file_list.html @@ -26,7 +26,7 @@
    - @@ -37,10 +37,10 @@
    {$lang->file_size} {$lang->is_valid}{$lang->download_count}{$lang->cmd_download} {$lang->date} {$lang->ipaddress}{$lang->cmd_move_to_document}{$lang->cmd_move}
    -+diff --git a/modules/opage/tpl/index.html b/modules/opage/tpl/index.html index 9bad57188..10ca72b6c 100644 --- a/modules/opage/tpl/index.html +++ b/modules/opage/tpl/index.html @@ -9,7 +9,7 @@
    -+diff --git a/modules/page/tpl/index.html b/modules/page/tpl/index.html index dd9354e2d..dde5226ce 100644 --- a/modules/page/tpl/index.html +++ b/modules/page/tpl/index.html @@ -9,7 +9,7 @@
    -+diff --git a/modules/poll/tpl/poll_list.html b/modules/poll/tpl/poll_list.html index 32d29868d..a7977ede4 100644 --- a/modules/poll/tpl/poll_list.html +++ b/modules/poll/tpl/poll_list.html @@ -15,10 +15,10 @@ - - + + diff --git a/modules/trackback/tpl/trackback_list.html b/modules/trackback/tpl/trackback_list.html index 98ba825d1..0079bd52d 100644 --- a/modules/trackback/tpl/trackback_list.html +++ b/modules/trackback/tpl/trackback_list.html @@ -33,7 +33,7 @@
    {$lang->no}
    - + From d30b776900147ce65632366366855926fbce06f6 Mon Sep 17 00:00:00 2001 From: zero Date: Wed, 21 Nov 2007 01:44:00 +0000 Subject: [PATCH 007/265] =?UTF-8?q?xe=5Fofficial=20=EC=99=B8=EB=B6=80?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=EC=98=81=EC=97=AD=EC=97=90=EC=84=9C?= =?UTF-8?q?=20=EC=82=AC=EC=9A=A9=EC=9E=90=20=EB=A9=94=EB=89=B4=EC=9D=98=20?= =?UTF-8?q?=EA=B8=80=EC=9E=90=EA=B0=80=20=EA=B8=B8=EC=96=B4=EC=A7=80?= =?UTF-8?q?=EB=8D=94=EB=9D=BC=EB=8F=84=20=EC=9D=B4=EC=83=81=EC=97=86?= =?UTF-8?q?=EC=9D=B4=20=EB=B3=B4=EC=9D=B4=EB=8F=84=EB=A1=9D=20css=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3030 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- widgets/login_info/skins/xe_official/css/black.css | 2 +- widgets/login_info/skins/xe_official/css/default.css | 4 ++-- widgets/login_info/skins/xe_official/login_info.html | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/widgets/login_info/skins/xe_official/css/black.css b/widgets/login_info/skins/xe_official/css/black.css index c3eb0872e..57fbbc9fe 100644 --- a/widgets/login_info/skins/xe_official/css/black.css +++ b/widgets/login_info/skins/xe_official/css/black.css @@ -20,7 +20,7 @@ .login_black form .userName strong { color:#cbcbcb; padding:4px 0 0 2px; font:bold .9em Tahoma;} .login_black form .userName a { position:relative; right:0px; } .login_black form ul.userMenu { padding:0 0 6px 4px; overflow:hidden; margin-top:10px;} -.login_black form ul.userMenu li { list-style:none; color:#cbcbcb; list-style:none;padding-left:10px; background:url(../images/black/bulletFF1A00.gif) no-repeat left 4px; height:18px; } +.login_black form ul.userMenu li { list-style:none; color:#cbcbcb; list-style:none;padding-left:10px; background:url(../images/black/bulletFF1A00.gif) no-repeat left 4px; } .login_black form ul.userMenu li a { color:#cbcbcb;text-decoration:none;} .login_black form ul.userMenu li a:hover {text-decoration:underline;} .login_black form p.latestLogin { color:#818181; font:.9em "돋움", Dotum, "굴림", Gulim, AppleGothic, Sans-serif;} diff --git a/widgets/login_info/skins/xe_official/css/default.css b/widgets/login_info/skins/xe_official/css/default.css index 6e5493cd5..819a6c241 100644 --- a/widgets/login_info/skins/xe_official/css/default.css +++ b/widgets/login_info/skins/xe_official/css/default.css @@ -19,8 +19,8 @@ .login_default form .userName { position:relative; width:172px; overflow:hidden; border-bottom:1px solid #e4e4e4; padding:0 0 6px 0; margin-top:-5px;} .login_default form .userName strong { color:#282828; padding:4px 0 0 2px; font:bold .9em Tahoma;} .login_default form .userName a { position:relative; right:0px; } -.login_default form ul.userMenu { padding:0 0 6px 4px; overflow:hidden; margin-top:10px;} -.login_default form ul.userMenu li { list-style:none; padding-left:10px; background:url(../images/default/bulletFF1A00.gif) no-repeat left 4px; height:18px; } +.login_default form ul.userMenu { padding:0 0 6px 4px; margin-top:10px;} +.login_default form ul.userMenu li { list-style:none; padding-left:10px; background:url(../images/default/bulletFF1A00.gif) no-repeat left 4px; } .login_default form ul.userMenu li a { color:#54564b; text-decoration:none;} .login_default form ul.userMenu li a:hover { text-decoration:underline;} .login_default form p.latestLogin { color:#999999; font:.9em "돋움", Dotum, "굴림", Gulim, AppleGothic, Sans-serif;} diff --git a/widgets/login_info/skins/xe_official/login_info.html b/widgets/login_info/skins/xe_official/login_info.html index e670ebb41..e40d7d1e5 100644 --- a/widgets/login_info/skins/xe_official/login_info.html +++ b/widgets/login_info/skins/xe_official/login_info.html @@ -29,6 +29,6 @@ -

    {$lang->last_login} : {zDate($logged_info->last_login, "Y-m-d H:i")}

    +

    {$lang->last_login}
    {zDate($logged_info->last_login, "Y-m-d H:i")}

    From ef82656fe1918ffc9b21405f1debf61d0b77838b Mon Sep 17 00:00:00 2001 From: zero Date: Wed, 21 Nov 2007 01:49:35 +0000 Subject: [PATCH 008/265] =?UTF-8?q?#273=20=EC=98=A4=ED=94=88=EC=95=84?= =?UTF-8?q?=EC=9D=B4=EB=94=94=20=EC=9D=B8=EC=A6=9D=EC=8B=9C=20=EB=B9=84?= =?UTF-8?q?=EB=B0=80=EB=B2=88=ED=98=B8=EB=A5=BC=20=ED=99=95=EC=9D=B8?= =?UTF-8?q?=ED=95=98=EB=8D=98=20=EB=A3=A8=ED=8B=B4=EC=9D=84=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0=ED=95=98=EC=97=AC=20=EC=A0=95=EC=83=81=EC=A0=81?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=EB=90=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3031 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/member/member.controller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/member/member.controller.php b/modules/member/member.controller.php index 7fdfb9d03..c10c1f4de 100644 --- a/modules/member/member.controller.php +++ b/modules/member/member.controller.php @@ -1203,7 +1203,7 @@ if(!$user_id || $member_info->user_id != $user_id) return new Object(-1, 'invalid_user_id'); // 비밀번호 검사 - if(!$oMemberModel->isValidPassword($member_info->password, $password)) return new Object(-1, 'invalid_password'); + if($password && !$oMemberModel->isValidPassword($member_info->password, $password)) return new Object(-1, 'invalid_password'); // denied == 'Y' 이면 알림 if($member_info->denied == 'Y') return new Object(-1,'msg_user_denied'); From 9556c6fd86ca35226069f3c849388ffc23d2e81f Mon Sep 17 00:00:00 2001 From: zero Date: Wed, 21 Nov 2007 01:53:56 +0000 Subject: [PATCH 009/265] =?UTF-8?q?=EC=97=90=EB=94=94=ED=84=B0=EC=9D=98=20?= =?UTF-8?q?iframe=20obj=EC=9D=98=20width=EA=B0=80=20=EC=9E=98=EB=AA=BB=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9=EB=90=98=EB=8D=98=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3032 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/editor/tpl/js/editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/editor/tpl/js/editor.js b/modules/editor/tpl/js/editor.js index f7efdad0f..759745d1b 100755 --- a/modules/editor/tpl/js/editor.js +++ b/modules/editor/tpl/js/editor.js @@ -99,7 +99,7 @@ function editorStart(editor_sequence, primary_key, content_key, editor_height) { // iframe obj를 찾음 var iframe_obj = editorGetIFrame(editor_sequence); if(!iframe_obj) return; - xWidth(iframe_obj, xWidth(iframe_obj.parentNode)-12); + iframe_obj.style.width = '100%'; // 현 에디터를 감싸고 있는 form문을 찾음 var fo_obj = editorGetForm(editor_sequence); From fbfa0a9b8181257b6b6a1b6e2613c5644285b665 Mon Sep 17 00:00:00 2001 From: zero Date: Wed, 21 Nov 2007 03:35:21 +0000 Subject: [PATCH 010/265] =?UTF-8?q?=ED=99=95=EC=9E=A5=EB=B3=80=EC=88=98?= =?UTF-8?q?=EC=9D=98=20=EC=A0=84=ED=99=94=EB=B2=88=ED=98=B8=EB=A5=BC=20?= =?UTF-8?q?=EB=AC=B4=EC=A1=B0=EA=B1=B4=20=EC=A0=95=EC=88=98=ED=99=94?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EB=A3=A8=ED=8B=B4=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3033 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/blog/skins/xe_blog/extra_var_value.html | 6 +++--- modules/board/skins/xe_board/extra_var_value.html | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/blog/skins/xe_blog/extra_var_value.html b/modules/blog/skins/xe_blog/extra_var_value.html index bdcd63980..fd889bab2 100644 --- a/modules/blog/skins/xe_blog/extra_var_value.html +++ b/modules/blog/skins/xe_blog/extra_var_value.html @@ -28,11 +28,11 @@ - {(int)htmlspecialchars($val->value[0])} + {htmlspecialchars($val->value[0])} - - {(int)htmlspecialchars($val->value[1])} + {htmlspecialchars($val->value[1])} - - {(int)htmlspecialchars($val->value[2])} + {htmlspecialchars($val->value[2])}   diff --git a/modules/board/skins/xe_board/extra_var_value.html b/modules/board/skins/xe_board/extra_var_value.html index bdcd63980..fd889bab2 100644 --- a/modules/board/skins/xe_board/extra_var_value.html +++ b/modules/board/skins/xe_board/extra_var_value.html @@ -28,11 +28,11 @@ - {(int)htmlspecialchars($val->value[0])} + {htmlspecialchars($val->value[0])} - - {(int)htmlspecialchars($val->value[1])} + {htmlspecialchars($val->value[1])} - - {(int)htmlspecialchars($val->value[2])} + {htmlspecialchars($val->value[2])}   From 90dc8d47995e14db1919bd8fe422c7a8eb6b4e16 Mon Sep 17 00:00:00 2001 From: zero Date: Wed, 21 Nov 2007 07:36:54 +0000 Subject: [PATCH 011/265] =?UTF-8?q?ttimporter=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3034 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/ttimporter/conf/info.xml | 31 -- modules/ttimporter/conf/module.xml | 7 - modules/ttimporter/lang/en.lang.php | 21 -- modules/ttimporter/lang/es.lang.php | 21 -- modules/ttimporter/lang/jp.lang.php | 21 -- modules/ttimporter/lang/ko.lang.php | 21 -- modules/ttimporter/lang/ru.lang.php | 21 -- modules/ttimporter/lang/zh-CN.lang.php | 21 -- modules/ttimporter/tpl/filter/import_tt.xml | 14 - modules/ttimporter/tpl/index.html | 46 --- modules/ttimporter/tpl/js/importer_admin.js | 29 -- .../ttimporter.admin.controller.php | 264 ------------------ modules/ttimporter/ttimporter.admin.view.php | 32 --- modules/ttimporter/ttimporter.class.php | 41 --- 14 files changed, 590 deletions(-) delete mode 100644 modules/ttimporter/conf/info.xml delete mode 100644 modules/ttimporter/conf/module.xml delete mode 100644 modules/ttimporter/lang/en.lang.php delete mode 100644 modules/ttimporter/lang/es.lang.php delete mode 100644 modules/ttimporter/lang/jp.lang.php delete mode 100644 modules/ttimporter/lang/ko.lang.php delete mode 100644 modules/ttimporter/lang/ru.lang.php delete mode 100644 modules/ttimporter/lang/zh-CN.lang.php delete mode 100644 modules/ttimporter/tpl/filter/import_tt.xml delete mode 100644 modules/ttimporter/tpl/index.html delete mode 100644 modules/ttimporter/tpl/js/importer_admin.js delete mode 100644 modules/ttimporter/ttimporter.admin.controller.php delete mode 100644 modules/ttimporter/ttimporter.admin.view.php delete mode 100644 modules/ttimporter/ttimporter.class.php diff --git a/modules/ttimporter/conf/info.xml b/modules/ttimporter/conf/info.xml deleted file mode 100644 index c98f9a60d..000000000 --- a/modules/ttimporter/conf/info.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - TatterTools 데이터 이전 - TatterTools 数据导入 - TTデータ移転 - Transfer data from TatterTools - - 제로 - zero - Zero - Zero - - 태터툴즈의 백업파일을 제로보드XE에 입력을 하는 모듈입니다. - 첨부파일 포함하지 않은 백업파일이 필요합니다. - 첨부파일은 원주소에서 직접 다운로드를 하게 됩니다. - - - 导入TatterTools的备份文件到Zeroboard XE的模块。 - 需要不包含附件的备份文件。 - 附件将在原地址直接下载。 - - - TatterToolsのバックアップファイルをゼロボードXE用にデータの変換を行うモジュールです。添付ファイルを含まないバックアップファイルが必要です。添付ファイルは、元のアドレスからダウンロードします。 - - - Module for inputting TattertTools' backup file to ZeroboardXE. - Backup file without attachment is required. - Attachments will be downloaded from the original address. - - - diff --git a/modules/ttimporter/conf/module.xml b/modules/ttimporter/conf/module.xml deleted file mode 100644 index a0047cc78..000000000 --- a/modules/ttimporter/conf/module.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/modules/ttimporter/lang/en.lang.php b/modules/ttimporter/lang/en.lang.php deleted file mode 100644 index b31110e03..000000000 --- a/modules/ttimporter/lang/en.lang.php +++ /dev/null @@ -1,21 +0,0 @@ -ttimporter = "Import Tetter Tools data"; - $lang->about_tt_importer = "You can input the Tetter Tools data into the module you want.\n The attached file will be directly downloaded via web, so please be sure to enable the original Tetter Tools blog."; - - $lang->target_module = "Target module"; - $lang->target_file = "Target xml file"; - $lang->target_url = "Blog URL"; - - $lang->cmd_continue = 'Continue'; - - $lang->msg_no_xml_file = 'Could not find the XML file! Please check the URL.'; - $lang->msg_invalid_xml_file = 'Invalid XML file type!'; - $lang->msg_importing = 'No. of importing: %d (if stopped long time, please click the "Continue" button.)'; - $lang->msg_import_finished = 'No. of imported: %d (according to condition, some data may not be imported properly.)'; -?> diff --git a/modules/ttimporter/lang/es.lang.php b/modules/ttimporter/lang/es.lang.php deleted file mode 100644 index c28f6f258..000000000 --- a/modules/ttimporter/lang/es.lang.php +++ /dev/null @@ -1,21 +0,0 @@ -ttimporter = "Importar datos de la herramienta Tetter"; - $lang->about_tt_importer = "Usted puede ingresar los datos de la herramienta Tetter dentro del módulo lo que desee.\n El archivo adjunto será directamento descargado vía web, por lo que Usted debe activar el blog original de la herrameienta Tetter."; - - $lang->target_module = "Módulo objetivo"; - $lang->target_file = "Archivo xml objetivo"; - $lang->target_url = "URL del Blog"; - - $lang->cmd_continue = 'Continuar'; - - $lang->msg_no_xml_file = 'No se puede encontrar el archivo XML! Por favor chequee la URL.'; - $lang->msg_invalid_xml_file = 'Tipo de archivo XML inválido!'; - $lang->msg_importing = 'Importando %d datos (si permanece detenido mucho tiempo, por favor presiona el botón "Continuar".)'; - $lang->msg_import_finished = '%d datos importados (dependiendo de la condición, algunos datos pueden no ser importados correctamente.)'; -?> diff --git a/modules/ttimporter/lang/jp.lang.php b/modules/ttimporter/lang/jp.lang.php deleted file mode 100644 index 96c389050..000000000 --- a/modules/ttimporter/lang/jp.lang.php +++ /dev/null @@ -1,21 +0,0 @@ -ttimporter = "TTデータの移転"; - $lang->about_tt_importer = "TatterTools データを希望するモジュールへデータを変換し、入力を行います。添付ファイルは、元のURLから直接ダウンロードするため、元のTatterTools が作動するようにしておいてください。"; - - $lang->target_module = "対象モジュール"; - $lang->target_file = "対象XMLファイル"; - $lang->target_url = "ブログURL"; - - $lang->cmd_continue = '続ける'; - - $lang->msg_no_xml_file = 'XMLファイルが見つかりません。パスを確認してください。'; - $lang->msg_invalid_xml_file = '正しくないフォーマットのXMLファイルです。'; - $lang->msg_importing = '%d個を変換・入力中です。止まっている場合は「続ける」ボタンをクリックしてください。'; - $lang->msg_import_finished = '%d個のデータを変換し、入力が完了しました。正しく変換入力されていないデータがある場合もあります。'; -?> diff --git a/modules/ttimporter/lang/ko.lang.php b/modules/ttimporter/lang/ko.lang.php deleted file mode 100644 index 92eb2b85b..000000000 --- a/modules/ttimporter/lang/ko.lang.php +++ /dev/null @@ -1,21 +0,0 @@ -ttimporter = "태터툴즈 데이터 이전"; - $lang->about_tt_importer = "태터툴즈 데이터를 원하는 모듈에 입력을 할 수 있습니다.\n첨부파일은 웹으로 직접 다운로드를 받으니 꼭 원래 태터툴즈 블로그를 활성화 시켜 주셔야 합니다."; - - $lang->target_module = "대상 모듈"; - $lang->target_file = "대상 xml파일"; - $lang->target_url = "블로그URL"; - - $lang->cmd_continue = '계속진행'; - - $lang->msg_no_xml_file = 'XML파일을 찾을 수 없습니다. 경로를 다시 확인해주세요'; - $lang->msg_invalid_xml_file = '잘못된 형식의 XML파일입니다'; - $lang->msg_importing = '%d개를 입력중입니다. (계속 멈추어 있으면 "계속진행" 버튼을 클릭해주세요)'; - $lang->msg_import_finished = '%d개의 데이터 입력이 완료되었습니다. 상황에 따라 입력되지 못한 데이터가 있을 수 있습니다.'; -?> diff --git a/modules/ttimporter/lang/ru.lang.php b/modules/ttimporter/lang/ru.lang.php deleted file mode 100644 index 1d9ae75b0..000000000 --- a/modules/ttimporter/lang/ru.lang.php +++ /dev/null @@ -1,21 +0,0 @@ - | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; - * @brief Russian basic language pack for Zeroboard XE - **/ - - $lang->ttimporter = "Имортировать данные Tetter Tools"; - $lang->about_tt_importer = "Вы можете ипортировать дынне Tetter Tools в любой модуль.\n Вложенный файл будет напрямую скачан через Веб, поэтому, пожалуйста, убедитесь в том, что оригинальный Tetter Tools работает."; - - $lang->target_module = "Модуль назначения"; - $lang->target_file = "XML файл назначения"; - $lang->target_url = "URL Блога"; - - $lang->cmd_continue = 'Продолжить'; - - $lang->msg_no_xml_file = 'Невозможно найти XML файл! Пожалуйста, проверьте URL.'; - $lang->msg_invalid_xml_file = 'Неверный тип XML файла!'; - $lang->msg_importing = 'Импортирование: %d (если будет задержка, пожалуйста, нажмите кнопку "Продолжить".)'; - $lang->msg_import_finished = 'Импортировано: %d (согласно состоянию, некоторые данные могут быть импортированы неверно.)'; -?> diff --git a/modules/ttimporter/lang/zh-CN.lang.php b/modules/ttimporter/lang/zh-CN.lang.php deleted file mode 100644 index a6361511f..000000000 --- a/modules/ttimporter/lang/zh-CN.lang.php +++ /dev/null @@ -1,21 +0,0 @@ -ttimporter = "TatterTools 数据导入"; - $lang->about_tt_importer = "可以把TatterTools 的数据导入到指定的模块当中。\n因附件要在网站直接下载,所以导入前必须先激活原TatterTools 博客。"; - - $lang->target_module = "对象模块"; - $lang->target_file = "对象xml文件"; - $lang->target_url = "博客URL"; - - $lang->cmd_continue = '继续进行'; - - $lang->msg_no_xml_file = '找不到XML文件。请重新确认路径'; - $lang->msg_invalid_xml_file = '错误的XML文件格式。'; - $lang->msg_importing = '正在输入%d个。(长时间停止响应时请按“继续进行”按钮)'; - $lang->msg_import_finished = '已完成%d个数据导入。根据情况可能会有没有被导入的数据。'; -?> diff --git a/modules/ttimporter/tpl/filter/import_tt.xml b/modules/ttimporter/tpl/filter/import_tt.xml deleted file mode 100644 index cf5182a1c..000000000 --- a/modules/ttimporter/tpl/filter/import_tt.xml +++ /dev/null @@ -1,14 +0,0 @@ - -
    - - - - - - - - - - - -
    diff --git a/modules/ttimporter/tpl/index.html b/modules/ttimporter/tpl/index.html deleted file mode 100644 index 6b18b2eb8..000000000 --- a/modules/ttimporter/tpl/index.html +++ /dev/null @@ -1,46 +0,0 @@ - - - -

    {$lang->ttimporter} {$lang->cmd_management}

    - - -
    {nl2br($lang->about_tt_importer)}
    - -
    - - -
    - - - - - - - - - - - - - - -
    {$lang->target_module} - -
    {$lang->target_file}
    {$lang->target_url}
    - -
    - -
    - - - - diff --git a/modules/ttimporter/tpl/js/importer_admin.js b/modules/ttimporter/tpl/js/importer_admin.js deleted file mode 100644 index cef481fb6..000000000 --- a/modules/ttimporter/tpl/js/importer_admin.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @file modules/ttimporter/js/importer_admin.js - * @author zero (zero@nzeo.com) - * @brief importer에서 사용하는 javascript - **/ - -/* Step Complete Import */ -function completeImport(ret_obj) { - var message = ret_obj['message']; - var is_finished = ret_obj['is_finished']; - var position = ret_obj['position']; - - xGetElementById("import_status").style.display = "block"; - - if(is_finished=='Y') { - alert(ret_obj["message"]); - location.href = location.href; - } else { - var fo_obj = xGetElementById('fo_import'); - fo_obj.position.value = position; - xInnerHtml('import_status', message); - procFilter(fo_obj, import_tt); - } -} - -function doManualProcess() { - var fo_obj = xGetElementById('fo_import'); - procFilter(fo_obj, import_tt); -} diff --git a/modules/ttimporter/ttimporter.admin.controller.php b/modules/ttimporter/ttimporter.admin.controller.php deleted file mode 100644 index f5040ce9b..000000000 --- a/modules/ttimporter/ttimporter.admin.controller.php +++ /dev/null @@ -1,264 +0,0 @@ -module_srl = Context::get('module_srl'); - $xml_file = Context::get('xml_file'); - $this->url = Context::get('url'); - $this->position = (int)Context::get('position'); - if(substr($this->url,-1)!='/') $this->url .= '/'; - - // 파일을 찾을 수 없으면 에러 표시 - if(!file_exists($xml_file)) return new Object(-1,'msg_no_xml_file'); - - $this->oXml = new XmlParser(); - - $oDocumentModel = &getModel('document'); - $tmp_category_list = $oDocumentModel->getCategoryList($this->module_srl); - if(count($tmp_category_list)) { - foreach($tmp_category_list as $key => $val) $this->category_list[$val->title] = $key; - } else { - $this->category_list = array(); - } - - // module_srl이 있으면 module데이터로 판단하여 처리, 아니면 회원정보로.. - $is_finished = $this->importDocument($xml_file); - - if($is_finished) { - $this->add('is_finished', 'Y'); - $this->setMessage( sprintf(Context::getLang('msg_import_finished'), $this->imported_count) ); - } else { - $this->add('position', $this->imported_count); - $this->add('is_finished', 'N'); - $this->setMessage( sprintf(Context::getLang('msg_importing'), $this->imported_count) ); - } - } - - /** - * @brief 게시물정보 import - **/ - function importDocument($xml_file) { - $filesize = filesize($xml_file); - - if($filesize<1) return; - - $this->oDocumentController = &getController('document'); - $this->oFileController = &getController('file'); - $this->oCommentController = &getController('comment'); - $this->oTrackbackController = &getController('trackback'); - - $is_finished = true; - - $fp = @fopen($xml_file, "r"); - if($fp) { - $buff = ''; - while(!feof($fp)) { - $str = fread($fp,1024); - $buff .= $str; - - $buff = preg_replace_callback("!(.*?)<\/category>!is", array($this, '_parseCategoryInfo'), trim($buff)); - $buff = preg_replace_callback("!!is", array($this, '_importDocument'), trim($buff)); - - if($this->position+$this->limit_count <= $this->imported_count) { - $is_finished = false; - break; - } - } - fclose($fp); - } - - return $is_finished; - } - - function _insertAttachment($matches) { - $xml_doc = $this->oXml->parse($matches[0]); - - $filename = $xml_doc->attachment->name->body; - $url = sprintf("%sattach/1/%s", $this->url, $filename); - - $tmp_filename = './files/cache/tmp_uploaded_file'; - if(FileHandler::getRemoteFile($url, $tmp_filename)) { - $file_info['tmp_name'] = $tmp_filename; - $file_info['name'] = $filename; - $this->oFileController->insertFile($file_info, $this->module_srl, $this->document_srl, 0, true); - $this->uploaded_count++; - } - @unlink($tmp_filename); - } - - function _importDocument($matches) { - if($this->position > $this->imported_count) { - $this->imported_count++; - return; - } - - $this->uploaded_count = 0; - - $xml_doc = $this->oXml->parse($matches[0]); - - // 문서 번호와 내용 미리 구해 놓기 - $this->document_srl = $args->document_srl = getNextSequence(); - $args->content = $xml_doc->post->content->body; - - // 첨부파일 미리 등록 - preg_replace_callback("!!is", array($this, '_insertAttachment'), $matches[0]); - - // 컨텐츠의 내용 수정 (이미지 첨부파일 관련) - $args->content = preg_replace("!(\[##\_1)([a-zA-Z]){1}\|([^\|]*)\|([^\|]*)\|([^\]]*)\]!is", sprintf('', $this->module_srl, $args->document_srl), $args->content); - - if($xml_doc->post->comment && !is_array($xml_doc->post->comment)) $xml_doc->post->comment = array($xml_doc->post->comment); - - $logged_info = Context::get('logged_info'); - - // 문서 입력 - $args->module_srl = $this->module_srl; - $args->category_srl = $this->category_list[$xml_doc->post->category->body]; - $args->is_notice = 'N'; - $args->is_secret = 'N'; - $args->title = $xml_doc->post->title->body; - $args->readed_count = 0; - $args->voted_count = 0; - $args->comment_count = count($xml_doc->post->comment); - $args->trackback_count = 0; - $args->uploaded_count = $this->uploaded_count; - $args->password = ''; - $args->nick_name = $logged_info->nick_name; - $args->member_srl = $logged_info->member_srl; - $args->user_id = $logged_info->user_id; - $args->user_name = $logged_info->user_name; - $args->email_address = $logged_info->email_address; - $args->homepage = $logged_info->homepage; - - $tag_list = array(); - $tags = $xml_doc->post->tag; - if($tags && !is_array($tags)) $tags = array($tags); - for($i=0;$ibody; - } - $args->tags = implode(',',$tag_list); - $args->regdate = date("YmdHis", $xml_doc->post->created->body); - $args->ipaddress = ''; - $args->allow_comment = $xml_doc->post->acceptcomment->body?'Y':'N'; - $args->lock_comment = 'N'; - $args->allow_trackback = $xml_doc->post->accepttrackback->body?'Y':'N'; - - $output = $this->oDocumentController->insertDocument($args, true); - - if($output->toBool()) { - - // 코멘트 입력 - $comments = $xml_doc->post->comment; - if(count($comments)) { - foreach($comments as $key => $val) { - unset($comment_args); - $comment_args->document_srl = $args->document_srl; - $comment_args->comment_srl = getNextSequence(); - $comment_args->module_srl = $this->module_srl; - $comment_args->parent_srl = 0; - $comment_args->content = $val->content->body; - $comment_args->password = ''; - $comment_args->nick_name = $val->commenter->name->body; - $comment_args->user_id = ''; - $comment_args->user_name = ''; - $comment_args->member_srl = 0; - $comment_args->email_address = ''; - $comment_args->regdate = date("YmdHis",$val->written->body); - $comment_args->ipaddress = $val->commenter->ip->body; - $this->oCommentController->insertComment($comment_args, true); - - if($val->comment) { - $val = $val->comment; - unset($child_comment_args); - $child_comment_args->document_srl = $args->document_srl; - $child_comment_args->comment_srl = getNextSequence(); - $child_comment_args->module_srl = $this->module_srl; - $child_comment_args->parent_srl = $comment_args->comment_srl; - $child_comment_args->content = $val->content->body; - $child_comment_args->password = ''; - $child_comment_args->nick_name = $val->commenter->name->body; - $child_comment_args->user_id = ''; - $child_comment_args->user_name = ''; - $child_comment_args->member_srl = 0; - $child_comment_args->email_address = ''; - $child_comment_args->regdate = date("YmdHis",$val->written->body); - $child_comment_args->ipaddress = $val->commenter->ip->body; - $this->oCommentController->insertComment($child_comment_args, true); - } - - } - } - - /* - // 트랙백 입력 - $trackbacks = $xml_doc->document->trackbacks->trackback; - if($trackbacks && !is_array($trackbacks)) $trackbacks = array($trackbacks); - if(count($trackbacks)) { - foreach($trackbacks as $key => $val) { - $trackback_args->document_srl = $args->document_srl; - $trackback_args->module_srl = $this->module_srl; - $trackback_args->url = $val->url->body; - $trackback_args->title = $val->title->body; - $trackback_args->blog_name = $val->blog_name->body; - $trackback_args->excerpt = $val->excerpt->body; - $trackback_args->regdate = $val->regdate->body; - $trackback_args->ipaddress = $val->ipaddress->body; - $this->oTrackbackController->insertTrackback($trackback_args, true); - } - } - */ - } - - $this->imported_count ++; - return ''; - } - - /** - * @brief 정보를 읽어서 정보를 구함 - **/ - function _parseCategoryInfo($matches) { - $xml_doc = $this->oXml->parse($matches[0]); - if(!$xml_doc->category->priority) return $matches[0]; - - $title = trim($xml_doc->category->name->body); - if(!$title || $this->category_list[$title]) return; - - $oDocumentController = &getAdminController('document'); - $output = $oDocumentController->insertCategory($this->module_srl, $title); - $this->category_list[$title] = $output->get('category_srl'); - } - } -?> diff --git a/modules/ttimporter/ttimporter.admin.view.php b/modules/ttimporter/ttimporter.admin.view.php deleted file mode 100644 index 921196a25..000000000 --- a/modules/ttimporter/ttimporter.admin.view.php +++ /dev/null @@ -1,32 +0,0 @@ -getMidList(); - Context::set('module_list', $module_list); - - $this->setTemplatePath($this->module_path.'tpl'); - $this->setTemplateFile('index'); - } - - } -?> diff --git a/modules/ttimporter/ttimporter.class.php b/modules/ttimporter/ttimporter.class.php deleted file mode 100644 index 237b83c9a..000000000 --- a/modules/ttimporter/ttimporter.class.php +++ /dev/null @@ -1,41 +0,0 @@ -insertActionForward('ttimporter', 'view', 'dispTtimporterAdminContent'); - - return new Object(); - } - - /** - * @brief 설치가 이상이 없는지 체크하는 method - **/ - function checkUpdate() { - return false; - } - - /** - * @brief 업데이트 실행 - **/ - function moduleUpdate() { - return new Object(); - } - - /** - * @brief 캐시 파일 재생성 - **/ - function recompileCache() { - } - } -?> From 2a34ba2fd10994bdf267460fa5ec4e0d8fdf203e Mon Sep 17 00:00:00 2001 From: zero Date: Wed, 21 Nov 2007 08:42:31 +0000 Subject: [PATCH 012/265] =?UTF-8?q?IE6=20css=20hack=EB=A1=9C=20body?= =?UTF-8?q?=EC=99=80=20=EA=B8=B0=EB=B3=B8=20input=20form=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=B4=20font-size=EB=A5=BC=209pt=EB=A1=9C=20?= =?UTF-8?q?=EC=A7=80=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3035 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- common/css/default.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/css/default.css b/common/css/default.css index bcc6fe48a..057c3fa93 100644 --- a/common/css/default.css +++ b/common/css/default.css @@ -25,7 +25,7 @@ IE7 & IE6 & Below /* default.css - Type Selector Definition */ * { margin:0; padding:0; } html { width:100%; } -body { margin:0; font-size:.75em; font-family:sans-serif;} +body { margin:0; font-size:.75em; _font-size:9pt; font-family:sans-serif;} img { border:none; } label { cursor:pointer; } form { margin:0; padding:0; } @@ -34,10 +34,10 @@ form { margin:0; padding:0; } .zbxe_info { vertical-align:middle; behavior:url(./common/js/iePngFix.htc); } /* Input Style Definition */ -.inputTypeText { border:1px solid; border-color:#a6a6a6 #d8d8d8 #d8d8d8 #a6a6a6; height:1.4em; padding:.2em 0 0 .3em; background:#ffffff; font-size:1em; } +.inputTypeText { border:1px solid; border-color:#a6a6a6 #d8d8d8 #d8d8d8 #a6a6a6; height:1.4em; padding:.2em 0 0 .3em; background:#ffffff; font-size:1em; _font-size:9pt; } .inputTypeText:hover, .inputTypeText:focus { background:#f4f4f4; } -.inputTypeTextArea { border:1px solid !important; border-color:#a6a6a6 #d8d8d8 #d8d8d8 #a6a6a6 !important; background:#ffffff; font-size:1em;} +.inputTypeTextArea { border:1px solid !important; border-color:#a6a6a6 #d8d8d8 #d8d8d8 #a6a6a6 !important; background:#ffffff; font-size:1em; _font-size:9pt;} .w40 { width:40px; } .w60 { width:60px; } From 75a549a787d85a683b5caf678ebb9504bcab9e46 Mon Sep 17 00:00:00 2001 From: zero Date: Wed, 21 Nov 2007 08:45:26 +0000 Subject: [PATCH 013/265] =?UTF-8?q?IE7=EC=97=90=20=EB=8C=80=ED=95=B4?= =?UTF-8?q?=EC=84=9C=EB=8F=84=20body,=20input=20=ED=8F=BC=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=B4=20=ED=8F=B0=ED=8A=B8=20=EC=82=AC=EC=9D=B4?= =?UTF-8?q?=EC=A6=88=EB=A5=BC=209pt=EB=A5=BC=20=EC=A7=80=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3036 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- common/css/default.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/css/default.css b/common/css/default.css index 057c3fa93..7d785c13e 100644 --- a/common/css/default.css +++ b/common/css/default.css @@ -26,6 +26,7 @@ IE7 & IE6 & Below * { margin:0; padding:0; } html { width:100%; } body { margin:0; font-size:.75em; _font-size:9pt; font-family:sans-serif;} +*:first-child+html body { font-size:9pt; } img { border:none; } label { cursor:pointer; } form { margin:0; padding:0; } @@ -35,9 +36,11 @@ form { margin:0; padding:0; } /* Input Style Definition */ .inputTypeText { border:1px solid; border-color:#a6a6a6 #d8d8d8 #d8d8d8 #a6a6a6; height:1.4em; padding:.2em 0 0 .3em; background:#ffffff; font-size:1em; _font-size:9pt; } +*:first-child+html .inputTypeText { font-size:9pt; } .inputTypeText:hover, .inputTypeText:focus { background:#f4f4f4; } .inputTypeTextArea { border:1px solid !important; border-color:#a6a6a6 #d8d8d8 #d8d8d8 #a6a6a6 !important; background:#ffffff; font-size:1em; _font-size:9pt;} +*:first-child+html .inputTypeTextArea { font-size:9pt; } .w40 { width:40px; } .w60 { width:60px; } From 04a1fed23c4ad1d2b6dbe51881b191741c47dde4 Mon Sep 17 00:00:00 2001 From: zero Date: Wed, 21 Nov 2007 08:58:24 +0000 Subject: [PATCH 014/265] =?UTF-8?q?=ED=95=9C=EA=B5=AD=EC=96=B4=20=EC=A0=91?= =?UTF-8?q?=EC=86=8D=EC=9E=90=EC=9D=BC=20=EA=B2=BD=EC=9A=B0=20=EA=B8=B0?= =?UTF-8?q?=EB=B3=B8=EC=9C=BC=EB=A1=9C=20=EB=8F=8B=EC=9B=80=20=ED=8F=B0?= =?UTF-8?q?=ED=8A=B8=EA=B0=80=20=EC=A7=80=EC=A0=95=EB=90=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3037 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- common/tpl/common_layout.html | 5 +++++ layouts/xe_official/css/black.css | 2 +- layouts/xe_official/css/default.css | 2 +- layouts/xe_official/css/white.css | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/common/tpl/common_layout.html b/common/tpl/common_layout.html index 9752cdc73..074f3415d 100644 --- a/common/tpl/common_layout.html +++ b/common/tpl/common_layout.html @@ -18,6 +18,11 @@ var current_mid = "{$mid}"; var wating_message = "{$lang->msg_call_server}"; //]]> + + + {Context::getHtmlHeader()} diff --git a/layouts/xe_official/css/black.css b/layouts/xe_official/css/black.css index d4323907c..8c354875c 100644 --- a/layouts/xe_official/css/black.css +++ b/layouts/xe_official/css/black.css @@ -27,7 +27,7 @@ body { background:#3d3d3d url(../images/black/bgBody.gif) repeat-x;} #gnb { position:absolute; top:82px; left:0; height:38px; overflow:hidden; white-space:nowrap; margin-bottom:10px;} #gnb li { list-style:none; float:left; background:url(../images/black/bgGnbVr.gif) no-repeat left center; padding-left:2px; position:relative; left:-2px; white-space:nowrap;} -#gnb li a { display:block; float:left; padding:13px 15px 0 15px; height:25px; color:#a6a6a6; white-space:nowrap; text-decoration:none; font-family:"돋움", Dotum, "굴림", Gulim, AppleGothic, Sans-serif;} +#gnb li a { display:block; float:left; padding:13px 15px 0 15px; height:25px; color:#a6a6a6; white-space:nowrap; text-decoration:none; } #gnb li a:hover, #gnb li a:focus { color:#ffffff;} #gnb li.on a { font-weight:bold; color:#ffffff; background:url(../images/black/bgGnbOn.gif) no-repeat center top;} diff --git a/layouts/xe_official/css/default.css b/layouts/xe_official/css/default.css index ce6ec33ac..d45f2e13c 100644 --- a/layouts/xe_official/css/default.css +++ b/layouts/xe_official/css/default.css @@ -27,7 +27,7 @@ body { background:#FFFFFF url(../images/default/bgBody.gif) repeat-x left top; } #gnb { position:absolute; top:82px; left:0; height:38px; overflow:hidden; white-space:nowrap; margin-bottom:10px;} #gnb li { float:left; list-style:none; background:url(../images/default/bgGnbVr.gif) no-repeat left center; padding-left:2px; position:relative; left:-2px; white-space:nowrap;} -#gnb li a { display:block; float:left; padding:13px 15px 0 15px; height:25px; color:#e8e8e8; white-space:nowrap; text-decoration:none; font-family:"돋움", Dotum, "굴림", Gulim, AppleGothic, Sans-serif;} +#gnb li a { display:block; float:left; padding:13px 15px 0 15px; height:25px; color:#e8e8e8; white-space:nowrap; text-decoration:none; } #gnb li a:hover, #gnb li a:focus { color:#ffffff;} #gnb li.on a { font-weight:bold; color:#ffffff; background:url(../images/default/bgGnbOn.gif) no-repeat center top;} diff --git a/layouts/xe_official/css/white.css b/layouts/xe_official/css/white.css index 059a803e8..7a6d90b83 100644 --- a/layouts/xe_official/css/white.css +++ b/layouts/xe_official/css/white.css @@ -27,7 +27,7 @@ body { background:#ffffff;} #gnb { position:absolute; top:76px; left:0; height:38px; overflow:hidden; white-space:nowrap; margin-bottom:10px;} #gnb li { list-style:none; float:left; background:url(../images/white/bgGnbVr.gif) no-repeat left center; padding-left:2px; position:relative; left:-2px; white-space:nowrap;} -#gnb li a { display:block; float:left; padding:13px 15px 0 15px; height:25px; color:#727272; white-space:nowrap; text-decoration:none; font-family:"돋움", Dotum, "굴림", Gulim, AppleGothic, Sans-serif;} +#gnb li a { display:block; float:left; padding:13px 15px 0 15px; height:25px; color:#727272; white-space:nowrap; text-decoration:none; } #gnb li a:hover, #gnb li a:focus { color:#000000;} #gnb li.on a { font-weight:bold; color:#3f3f3f; background:url(../images/white/bgGnbOn.gif) no-repeat center top;} From 4a55cfe522d4a9e1e622ae918bb164a3fc3d5a80 Mon Sep 17 00:00:00 2001 From: haneul Date: Wed, 21 Nov 2007 15:22:58 +0000 Subject: [PATCH 015/265] =?UTF-8?q?xquared=20=EC=A0=81=EC=9A=A9=EC=9D=84?= =?UTF-8?q?=20=EC=9C=84=ED=95=9C=20javascript=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3038 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- common/js/xml_handler.js | 2 ++ common/js/xml_js_filter.js | 7 ++++--- modules/blog/skins/xe_blog/write_form.html | 2 +- modules/board/skins/xe_board/write_form.html | 2 +- modules/editor/skins/default/editor.html | 1 + modules/editor/tpl/js/editor.js | 14 ++++++-------- modules/editor/tpl/js/editor_common.js | 7 +++++++ modules/editor/tpl/js/uploader.js | 9 +++++---- modules/guestbook/skins/default/write_form.html | 2 +- 9 files changed, 28 insertions(+), 18 deletions(-) create mode 100644 modules/editor/tpl/js/editor_common.js diff --git a/common/js/xml_handler.js b/common/js/xml_handler.js index 3c628cf00..c3dace935 100644 --- a/common/js/xml_handler.js +++ b/common/js/xml_handler.js @@ -10,6 +10,7 @@ function exec_xml(module, act, params, callback_func, response_tags, callback_fu var oXml = new xml_handler(); oXml.reset(); for(var key in params) { + if(!params.hasOwnProperty(key)) continue; var val = params[key]; oXml.addParam(key, val); } @@ -88,6 +89,7 @@ function xml_handlerRequest(callBackFunc, xmlObj, callBackFunc2, response_tags, + "\n" for (var key in this.params) { + if(!this.params.hasOwnProperty(key)) continue; var val = this.params[key]; rd += "<"+key+">\n"; } diff --git a/common/js/xml_js_filter.js b/common/js/xml_js_filter.js index 7930525ab..77dbc4889 100644 --- a/common/js/xml_js_filter.js +++ b/common/js/xml_js_filter.js @@ -302,9 +302,10 @@ function XmlJsFilterProc(confirm_msg) { function procFilter(fo_obj, filter_func) { // form문 안에 위지윅 에디터가 세팅되어 있을 경우 에디터의 값과 지정된 content field를 sync var editor_sequence = fo_obj.getAttribute('editor_sequence'); - if(typeof(editor_sequence)!='undefined' && editor_sequence && typeof(editorRelKeys)!='undefined' && typeof(editorGetContent)=='function') { - var content = editorGetContent(editor_sequence); - editorRelKeys[editor_sequence]['content'].value = content; + if(typeof(editor_sequence)!='undefined' && editor_sequence && typeof(editorRelKeys)!='undefined') { + if(typeof(editorRelKeys[editor_sequence]['func']) =='function') { + editorRelKeys[editor_sequence]['func'](editor_sequence); + } } filter_func(fo_obj); diff --git a/modules/blog/skins/xe_blog/write_form.html b/modules/blog/skins/xe_blog/write_form.html index 424e7fabd..dc8836973 100644 --- a/modules/blog/skins/xe_blog/write_form.html +++ b/modules/blog/skins/xe_blog/write_form.html @@ -2,7 +2,7 @@
    -
    fileupload)-->enctype="multipart/form-data" class="blogEditor" id="fo_write"> + fileupload)-->enctype="multipart/form-data" class="blogEditor" id="fo_write">
    diff --git a/modules/board/skins/xe_board/write_form.html b/modules/board/skins/xe_board/write_form.html index adc3859f4..a35c15e7e 100644 --- a/modules/board/skins/xe_board/write_form.html +++ b/modules/board/skins/xe_board/write_form.html @@ -2,7 +2,7 @@
    - fileupload)-->enctype="multipart/form-data" class="boardEditor" id="fo_write"> + fileupload)-->enctype="multipart/form-data" class="boardEditor" id="fo_write">
    diff --git a/modules/editor/skins/default/editor.html b/modules/editor/skins/default/editor.html index cb0ce0c67..50a3b2392 100644 --- a/modules/editor/skins/default/editor.html +++ b/modules/editor/skins/default/editor.html @@ -2,6 +2,7 @@ + diff --git a/modules/editor/tpl/js/editor.js b/modules/editor/tpl/js/editor.js index 759745d1b..626bc934f 100755 --- a/modules/editor/tpl/js/editor.js +++ b/modules/editor/tpl/js/editor.js @@ -4,14 +4,6 @@ * @brief 에디터 관련 스크립트 */ -/** - * 에디터에서 사용하기 위한 변수 - **/ -var editorMode = new Array(); ///<< 에디터의 html편집 모드 flag 세팅 변수 (html or null) -var editorAutoSaveObj = {fo_obj:null, editor_sequence:0, title:'', content:'', locked:false} ///< 자동저장을 위한 정보를 가진 object -var editorRelKeys = new Array(); ///< 에디터와 각 모듈과의 연동을 위한 key 값을 보관하는 변수 -var editorDragObj = {isDrag:false, y:0, obj:null, id:'', det:0, source_height:0} - /** * 에디터 사용시 사용되는 이벤트 연결 함수 호출 **/ @@ -33,6 +25,11 @@ function editorGetTextArea(editor_sequence) { return xGetElementById( 'editor_textarea_' + editor_sequence ); } +function editorSync(editor_sequence) { + editorRelKeys[editor_sequence]['content'].value = editorGetContent(editor_sequence); +} + + // editor_sequence에 해당하는 form문 구함 function editorGetForm(editor_sequence) { var iframe_obj = editorGetIFrame(editor_sequence); @@ -112,6 +109,7 @@ function editorStart(editor_sequence, primary_key, content_key, editor_height) { editorRelKeys[editor_sequence] = new Array(); editorRelKeys[editor_sequence]["primary"] = fo_obj[primary_key]; editorRelKeys[editor_sequence]["content"] = fo_obj[content_key]; + editorRelKeys[editor_sequence]["func"] = editorSync; // saved document(자동저장 문서)에 대한 확인 if(typeof(fo_obj._saved_doc_title)!="undefined" ) { ///<< _saved_doc_title field가 없으면 자동저장 하지 않음 diff --git a/modules/editor/tpl/js/editor_common.js b/modules/editor/tpl/js/editor_common.js new file mode 100644 index 000000000..d7f497a70 --- /dev/null +++ b/modules/editor/tpl/js/editor_common.js @@ -0,0 +1,7 @@ +/** + * 에디터에서 사용하기 위한 변수 + **/ +var editorMode = new Array(); ///<< 에디터의 html편집 모드 flag 세팅 변수 (html or null) +var editorAutoSaveObj = {fo_obj:null, editor_sequence:0, title:'', content:'', locked:false} ///< 자동저장을 위한 정보를 가진 object +var editorRelKeys = new Array(); ///< 에디터와 각 모듈과의 연동을 위한 key 값을 보관하는 변수 +var editorDragObj = {isDrag:false, y:0, obj:null, id:'', det:0, source_height:0} diff --git a/modules/editor/tpl/js/uploader.js b/modules/editor/tpl/js/uploader.js index 2912c8477..1cd7a6b01 100755 --- a/modules/editor/tpl/js/uploader.js +++ b/modules/editor/tpl/js/uploader.js @@ -18,8 +18,8 @@ var uploaded_files = new Array(); * 이 함수는 editor.html 에서 파일 업로드 가능할 경우 호출됨 **/ // window.load 이벤트일 경우 && 문서 번호가 가상의 번호가 아니면 기존에 저장되어 있을지도 모르는 파일 목록을 가져옴 -function editor_upload_init(editor_sequence) { - xAddEventListener(window,'load',function() { editor_upload_start(editor_sequence);} ); +function editor_upload_init(editor_sequence, el) { + xAddEventListener(window,'load',function() { editor_upload_start(editor_sequence, el);} ); } function editor_upload_get_target_srl(editor_sequence) { @@ -32,7 +32,7 @@ function editor_upload_get_uploader_name(editor_sequence) { } // 파일 업로드를 위한 기본 준비를 함 -function editor_upload_start(editor_sequence) { +function editor_upload_start(editor_sequence, fo_obj) { // 캐시 삭제 try { document.execCommand('BackgroundImageCache',false,true); } catch(e) { } @@ -58,7 +58,8 @@ function editor_upload_start(editor_sequence) { if(!field_obj) return; // 에디터를 감싸는 form을 구해 submit target을 임시 iframe으로 변경 - var fo_obj = editorGetForm(editor_sequence); + if(!fo_obj) + fo_obj = editorGetForm(editor_sequence); fo_obj.target = 'tmp_upload_iframe'; // SWF uploader 생성 diff --git a/modules/guestbook/skins/default/write_form.html b/modules/guestbook/skins/default/write_form.html index 57da8120b..466c93728 100644 --- a/modules/guestbook/skins/default/write_form.html +++ b/modules/guestbook/skins/default/write_form.html @@ -5,7 +5,7 @@
    - + From 0c99858e7c81060be677b38c71f1f247484de230 Mon Sep 17 00:00:00 2001 From: haneul Date: Wed, 21 Nov 2007 15:33:02 +0000 Subject: [PATCH 016/265] =?UTF-8?q?editor=20skin=EC=97=90=20xquared=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3039 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/editor/skins/xquared/LICENSE | 14 + modules/editor/skins/xquared/README | 9 + modules/editor/skins/xquared/css/default.css | 18 + modules/editor/skins/xquared/doc/api/_01.html | 45 + modules/editor/skins/xquared/doc/api/_02.html | 143 + modules/editor/skins/xquared/doc/api/_03.html | 161 + modules/editor/skins/xquared/doc/api/_04.html | 45 + modules/editor/skins/xquared/doc/api/_05.html | 796 ++ modules/editor/skins/xquared/doc/api/_06.html | 216 + modules/editor/skins/xquared/doc/api/_07.html | 71 + modules/editor/skins/xquared/doc/api/_08.html | 71 + modules/editor/skins/xquared/doc/api/_09.html | 71 + modules/editor/skins/xquared/doc/api/_10.html | 71 + modules/editor/skins/xquared/doc/api/_11.html | 125 + modules/editor/skins/xquared/doc/api/_12.html | 189 + modules/editor/skins/xquared/doc/api/_13.html | 153 + modules/editor/skins/xquared/doc/api/_14.html | 71 + modules/editor/skins/xquared/doc/api/_15.html | 71 + modules/editor/skins/xquared/doc/api/_16.html | 71 + modules/editor/skins/xquared/doc/api/_17.html | 71 + modules/editor/skins/xquared/doc/api/_18.html | 512 ++ modules/editor/skins/xquared/doc/api/_19.html | 45 + .../skins/xquared/doc/api/constructor.gif | Bin 0 -> 363 bytes .../editor/skins/xquared/doc/api/default.css | 116 + modules/editor/skins/xquared/doc/api/file.gif | Bin 0 -> 242 bytes .../skins/xquared/doc/api/file_list.html | 149 + .../editor/skins/xquared/doc/api/function.gif | Bin 0 -> 224 bytes .../editor/skins/xquared/doc/api/index.html | 13 + .../editor/skins/xquared/doc/api/object.gif | Bin 0 -> 585 bytes .../editor/skins/xquared/doc/api/overview.gif | Bin 0 -> 614 bytes .../editor/skins/xquared/doc/api/splash.html | 7 + .../editor/skins/xquared/doc/api/src_01.html | 24 + .../editor/skins/xquared/doc/api/src_02.html | 344 + .../editor/skins/xquared/doc/api/src_03.html | 325 + .../editor/skins/xquared/doc/api/src_04.html | 163 + .../editor/skins/xquared/doc/api/src_05.html | 2216 +++++ .../editor/skins/xquared/doc/api/src_06.html | 2262 ++++++ .../editor/skins/xquared/doc/api/src_07.html | 54 + .../editor/skins/xquared/doc/api/src_08.html | 369 + .../editor/skins/xquared/doc/api/src_09.html | 382 + .../editor/skins/xquared/doc/api/src_10.html | 91 + .../editor/skins/xquared/doc/api/src_11.html | 209 + .../editor/skins/xquared/doc/api/src_12.html | 135 + .../editor/skins/xquared/doc/api/src_13.html | 235 + .../editor/skins/xquared/doc/api/src_14.html | 12 + .../editor/skins/xquared/doc/api/src_15.html | 147 + .../editor/skins/xquared/doc/api/src_16.html | 112 + .../editor/skins/xquared/doc/api/src_17.html | 21 + .../editor/skins/xquared/doc/api/src_18.html | 157 + .../editor/skins/xquared/doc/api/src_19.html | 16 + modules/editor/skins/xquared/editor.html | 78 + .../xquared/examples/css/xq_contents.css | 122 + .../skins/xquared/examples/css/xq_ui.css | 233 + .../skins/xquared/examples/default.html | 77 + .../xquared/examples/extensionpoint.html | 308 + .../xquared/examples/form_and_textarea.html | 30 + .../examples/img/content/blockquote.gif | Bin 0 -> 99 bytes .../xquared/examples/img/content/code.gif | Bin 0 -> 114 bytes .../xquared/examples/img/content/div.gif | Bin 0 -> 108 bytes .../examples/img/toolbar/backgroundColor.gif | Bin 0 -> 68 bytes .../examples/img/toolbar/blockquote.gif | Bin 0 -> 71 bytes .../xquared/examples/img/toolbar/code.gif | Bin 0 -> 86 bytes .../xquared/examples/img/toolbar/division.gif | Bin 0 -> 76 bytes .../xquared/examples/img/toolbar/emphasis.gif | Bin 0 -> 64 bytes .../examples/img/toolbar/foregroundColor.gif | Bin 0 -> 68 bytes .../xquared/examples/img/toolbar/heading1.gif | Bin 0 -> 70 bytes .../xquared/examples/img/toolbar/html.gif | Bin 0 -> 84 bytes .../xquared/examples/img/toolbar/indent.gif | Bin 0 -> 70 bytes .../examples/img/toolbar/justifyBoth.gif | Bin 0 -> 64 bytes .../examples/img/toolbar/justifyCenter.gif | Bin 0 -> 64 bytes .../examples/img/toolbar/justifyLeft.gif | Bin 0 -> 97 bytes .../examples/img/toolbar/justifyRight.gif | Bin 0 -> 64 bytes .../xquared/examples/img/toolbar/link.gif | Bin 0 -> 73 bytes .../examples/img/toolbar/orderedList.gif | Bin 0 -> 71 bytes .../xquared/examples/img/toolbar/outdent.gif | Bin 0 -> 69 bytes .../examples/img/toolbar/paragraph.gif | Bin 0 -> 73 bytes .../xquared/examples/img/toolbar/redo.gif | Bin 0 -> 68 bytes .../examples/img/toolbar/removeFormat.gif | Bin 0 -> 67 bytes .../examples/img/toolbar/separator.gif | Bin 0 -> 58 bytes .../xquared/examples/img/toolbar/strike.gif | Bin 0 -> 69 bytes .../examples/img/toolbar/strongEmphasis.gif | Bin 0 -> 70 bytes .../examples/img/toolbar/subscription.gif | Bin 0 -> 66 bytes .../examples/img/toolbar/superscription.gif | Bin 0 -> 67 bytes .../xquared/examples/img/toolbar/table.gif | Bin 0 -> 74 bytes .../examples/img/toolbar/toolbarBg.gif | Bin 0 -> 172 bytes .../examples/img/toolbar/toolbarButtonBg.gif | Bin 0 -> 46 bytes .../examples/img/toolbar/toolbarSeparator.gif | Bin 0 -> 963 bytes .../examples/img/toolbar/underline.gif | Bin 0 -> 73 bytes .../xquared/examples/img/toolbar/undo.gif | Bin 0 -> 69 bytes .../examples/img/toolbar/unorderedList.gif | Bin 0 -> 66 bytes .../xquared/examples/toolbar_customized1.html | 43 + .../xquared/examples/toolbar_customized2.html | 92 + .../xquared/examples/toolbar_disabled.html | 28 + modules/editor/skins/xquared/js/prototype.js | 4184 ++++++++++ .../editor/skins/xquared/js/xe_interface.js | 95 + .../editor/skins/xquared/js/xquared-min.js | 2646 ++++++ modules/editor/skins/xquared/js/xquared.js | 7139 +++++++++++++++++ modules/editor/skins/xquared/skin.xml | 21 + 98 files changed, 25694 insertions(+) create mode 100644 modules/editor/skins/xquared/LICENSE create mode 100644 modules/editor/skins/xquared/README create mode 100644 modules/editor/skins/xquared/css/default.css create mode 100644 modules/editor/skins/xquared/doc/api/_01.html create mode 100644 modules/editor/skins/xquared/doc/api/_02.html create mode 100644 modules/editor/skins/xquared/doc/api/_03.html create mode 100644 modules/editor/skins/xquared/doc/api/_04.html create mode 100644 modules/editor/skins/xquared/doc/api/_05.html create mode 100644 modules/editor/skins/xquared/doc/api/_06.html create mode 100644 modules/editor/skins/xquared/doc/api/_07.html create mode 100644 modules/editor/skins/xquared/doc/api/_08.html create mode 100644 modules/editor/skins/xquared/doc/api/_09.html create mode 100644 modules/editor/skins/xquared/doc/api/_10.html create mode 100644 modules/editor/skins/xquared/doc/api/_11.html create mode 100644 modules/editor/skins/xquared/doc/api/_12.html create mode 100644 modules/editor/skins/xquared/doc/api/_13.html create mode 100644 modules/editor/skins/xquared/doc/api/_14.html create mode 100644 modules/editor/skins/xquared/doc/api/_15.html create mode 100644 modules/editor/skins/xquared/doc/api/_16.html create mode 100644 modules/editor/skins/xquared/doc/api/_17.html create mode 100644 modules/editor/skins/xquared/doc/api/_18.html create mode 100644 modules/editor/skins/xquared/doc/api/_19.html create mode 100644 modules/editor/skins/xquared/doc/api/constructor.gif create mode 100644 modules/editor/skins/xquared/doc/api/default.css create mode 100644 modules/editor/skins/xquared/doc/api/file.gif create mode 100644 modules/editor/skins/xquared/doc/api/file_list.html create mode 100644 modules/editor/skins/xquared/doc/api/function.gif create mode 100644 modules/editor/skins/xquared/doc/api/index.html create mode 100644 modules/editor/skins/xquared/doc/api/object.gif create mode 100644 modules/editor/skins/xquared/doc/api/overview.gif create mode 100644 modules/editor/skins/xquared/doc/api/splash.html create mode 100644 modules/editor/skins/xquared/doc/api/src_01.html create mode 100644 modules/editor/skins/xquared/doc/api/src_02.html create mode 100644 modules/editor/skins/xquared/doc/api/src_03.html create mode 100644 modules/editor/skins/xquared/doc/api/src_04.html create mode 100644 modules/editor/skins/xquared/doc/api/src_05.html create mode 100644 modules/editor/skins/xquared/doc/api/src_06.html create mode 100644 modules/editor/skins/xquared/doc/api/src_07.html create mode 100644 modules/editor/skins/xquared/doc/api/src_08.html create mode 100644 modules/editor/skins/xquared/doc/api/src_09.html create mode 100644 modules/editor/skins/xquared/doc/api/src_10.html create mode 100644 modules/editor/skins/xquared/doc/api/src_11.html create mode 100644 modules/editor/skins/xquared/doc/api/src_12.html create mode 100644 modules/editor/skins/xquared/doc/api/src_13.html create mode 100644 modules/editor/skins/xquared/doc/api/src_14.html create mode 100644 modules/editor/skins/xquared/doc/api/src_15.html create mode 100644 modules/editor/skins/xquared/doc/api/src_16.html create mode 100644 modules/editor/skins/xquared/doc/api/src_17.html create mode 100644 modules/editor/skins/xquared/doc/api/src_18.html create mode 100644 modules/editor/skins/xquared/doc/api/src_19.html create mode 100644 modules/editor/skins/xquared/editor.html create mode 100644 modules/editor/skins/xquared/examples/css/xq_contents.css create mode 100644 modules/editor/skins/xquared/examples/css/xq_ui.css create mode 100644 modules/editor/skins/xquared/examples/default.html create mode 100644 modules/editor/skins/xquared/examples/extensionpoint.html create mode 100644 modules/editor/skins/xquared/examples/form_and_textarea.html create mode 100644 modules/editor/skins/xquared/examples/img/content/blockquote.gif create mode 100644 modules/editor/skins/xquared/examples/img/content/code.gif create mode 100644 modules/editor/skins/xquared/examples/img/content/div.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/backgroundColor.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/blockquote.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/code.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/division.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/emphasis.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/foregroundColor.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/heading1.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/html.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/indent.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/justifyBoth.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/justifyCenter.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/justifyLeft.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/justifyRight.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/link.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/orderedList.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/outdent.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/paragraph.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/redo.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/removeFormat.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/separator.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/strike.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/strongEmphasis.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/subscription.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/superscription.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/table.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/toolbarBg.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/toolbarButtonBg.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/toolbarSeparator.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/underline.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/undo.gif create mode 100644 modules/editor/skins/xquared/examples/img/toolbar/unorderedList.gif create mode 100644 modules/editor/skins/xquared/examples/toolbar_customized1.html create mode 100644 modules/editor/skins/xquared/examples/toolbar_customized2.html create mode 100644 modules/editor/skins/xquared/examples/toolbar_disabled.html create mode 100644 modules/editor/skins/xquared/js/prototype.js create mode 100644 modules/editor/skins/xquared/js/xe_interface.js create mode 100644 modules/editor/skins/xquared/js/xquared-min.js create mode 100644 modules/editor/skins/xquared/js/xquared.js create mode 100644 modules/editor/skins/xquared/skin.xml diff --git a/modules/editor/skins/xquared/LICENSE b/modules/editor/skins/xquared/LICENSE new file mode 100644 index 000000000..b47e925fd --- /dev/null +++ b/modules/editor/skins/xquared/LICENSE @@ -0,0 +1,14 @@ +Xquared is copyrighted free software by Alan Kang . +You can redistribute and/or modify it under the terms of the LGPL. +(http://www.gnu.org/licenses/lgpl.html) + +Following is a list of dependencies: + * prototype javascript framework + * Homepage: http://prototypejs.org + * License: http://dev.rubyonrails.org/browser/spinoffs/prototype/trunk/LICENSE?format=raw + * jsspec + * Homepage: http://jania.pe.kr/aw/moin.cgi/JSSpec + * License: http://www.gnu.org/licenses/lgpl.html + * yui-compressor + * Homepage: http://developer.yahoo.com/yui/compressor/ + * License: http://developer.yahoo.com/yui/license.html diff --git a/modules/editor/skins/xquared/README b/modules/editor/skins/xquared/README new file mode 100644 index 000000000..dcdd58778 --- /dev/null +++ b/modules/editor/skins/xquared/README @@ -0,0 +1,9 @@ +Xquared is a Javascript based, XHTML complaint, easily extensible +editor module aim to support major modern web browsers. + +This software is licensed under the terms you may find in the file +named "LICENSE" in this directory. + +For more information, see http://labs.openmaru.com/projects/xquared/ + +Thanks for using Xquared. \ No newline at end of file diff --git a/modules/editor/skins/xquared/css/default.css b/modules/editor/skins/xquared/css/default.css new file mode 100644 index 000000000..bd9c47182 --- /dev/null +++ b/modules/editor/skins/xquared/css/default.css @@ -0,0 +1,18 @@ +@charset "utf-8"; + +.xeEditor .fileAttach { position:relative; top:20px; padding:0 1em .5em 1em;} +.xeEditor .fileAttach .preview { padding:5px; width:110px; height:110px; border:1px solid #e1e1dd; background:#fbfbfb; float:left; margin-right:.5em;} +.xeEditor .fileAttach .preview img { width:110px; height:110px; float:left; display:block;} +.xeEditor .fileAttach .fileListArea { float:left; width:50%; margin-right:.7em; padding-bottom:.5em; margin-bottom:1em} +.xeEditor .fileAttach .fileListArea .fileList { overflow:auto; width:100%; height:auto; border:1px solid; border-color:#a6a6a6 #d8d8d8 #d8d8d8 #a6a6a6; margin-bottom:.3em; font-size:11px;} +.xeEditor .fileAttach .fileListArea .fileList option { line-height:100%; padding-left:.5em;} +.xeEditor .fileAttach .fileListArea span.file_attach_info { color:#3f4040; font-size:11px; text-align:left;} +.xeEditor .fileAttach .fileListArea span.file_attach_info strong { color:#ff6600; font-size:11px; font-weight:bold; } +.xeEditor .fileAttach .fileUploadControl { margin-bottom:5px; } + +.xeEditor .fileAttach .fileUploadControl .uploaderButton { display:block; cursor:pointer; background:url(../images/buttonTypeBCenter.gif) repeat-x left center; line-height:100%; overflow:visible; color:#3f4040; margin:0 1px; font-size:.9em; white-space:nowrap;} +.xeEditor .fileAttach .fileUploadControl .uploaderButton:hover { text-decoration:none;} +.xeEditor .fileAttach .fileUploadControl .uploaderButton img { vertical-align:middle;} +.xeEditor .fileAttach .fileUploadControl .uploaderButton .leftCap { width:2px; height:21px; background:url(../images/buttonTypeBLeft.gif) no-repeat; margin:0 .3em 0 0; position:relative; left:-1px;} +.xeEditor .fileAttach .fileUploadControl .uploaderButton .rightCap { width:2px; height:21px; background:url(../images/buttonTypeBRight.gif) no-repeat; margin:0 -1px 0 .4em;} +.xeEditor .fileAttach .fileUploadControl .uploaderButton .icon { margin:0 .2em;} diff --git a/modules/editor/skins/xquared/doc/api/_01.html b/modules/editor/skins/xquared/doc/api/_01.html new file mode 100644 index 000000000..bd7000e14 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/_01.html @@ -0,0 +1,45 @@ + + + + + + JsDoc: Browser.js + + + + +
    +
    + +
    Library: Browser.js
    +
    +
    + Overview +
    +
    +
    +
    + +
    +
    +
    + +
    Constructors
    + + +
    Functions
    + + +
    Objects
    + +
    +
    +
    + Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:20 GMT. +
    + + diff --git a/modules/editor/skins/xquared/doc/api/_02.html b/modules/editor/skins/xquared/doc/api/_02.html new file mode 100644 index 000000000..bc396fa0a --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/_02.html @@ -0,0 +1,143 @@ + + + + + + JsDoc: + + + + +
    +
    + +
    Library: Controls.js
    +
    +
    + Overview +
    +
    +
    xq.controls provides common UI elements such as dialog.
    +
    + +
    +
    +
    + +
    Constructors
    + + + + + + + + +
    Functions
    + + +
    +
    + + + + this.form.onsubmit() + +
    + + + + + + + + + + +
    + + + +
    +
    + + + + cancelButton.onclick() + +
    + + + + + + + + + + +
    + + + +
    +
    + + + + this.param.renderItem(item) + +
    + + + + + + +
    parameters
    + + + + + + + + +
    + + + item + + +
    + + + + + +
    + + + +
    Objects
    + + + + + + + + + + +
    +
    +
    + Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:20 GMT. +
    + + diff --git a/modules/editor/skins/xquared/doc/api/_03.html b/modules/editor/skins/xquared/doc/api/_03.html new file mode 100644 index 000000000..527f10740 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/_03.html @@ -0,0 +1,161 @@ + + + + + + JsDoc: DomTree.js + + + + +
    +
    + +
    Library: DomTree.js
    +
    +
    + Overview +
    +
    +
    +
    + +
    +
    +
    + +
    Constructors
    + + + + + + + + +
    Functions
    + + + + +
    +
    + + + + findLeft(el) + +
    + + + + + + +
    parameters
    + + + + + + + + +
    + + + el + + +
    + + + + + +
    + + + +
    +
    + + + + findRight(el) + +
    + + + + + + +
    parameters
    + + + + + + + + +
    + + + el + + +
    + + + + + +
    + + + +
    Objects
    + + +
    +
    + + + + + xq.DomTree + +
    + + +
    Provide various tree operations. + +TODO: Add specs
    + + + + + +
    + + + + + + + + + +
    +
    +
    + Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:21 GMT. +
    + + diff --git a/modules/editor/skins/xquared/doc/api/_04.html b/modules/editor/skins/xquared/doc/api/_04.html new file mode 100644 index 000000000..080339233 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/_04.html @@ -0,0 +1,45 @@ + + + + + + JsDoc: + + + + +
    +
    + +
    Library: EditHistory.js
    +
    +
    + Overview +
    +
    +
    xq.EditHistory manages editing history and performs UNDO/REDO.
    +
    + +
    +
    +
    + +
    Constructors
    + + +
    Functions
    + + +
    Objects
    + +
    +
    +
    + Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:21 GMT. +
    + + diff --git a/modules/editor/skins/xquared/doc/api/_05.html b/modules/editor/skins/xquared/doc/api/_05.html new file mode 100644 index 000000000..4b8bee6a9 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/_05.html @@ -0,0 +1,796 @@ + + + + + + JsDoc: + + + + +
    +
    + +
    Library: Editor.js
    +
    +
    + Overview +
    +
    +
    xq.Editor manages configurations such as autocompletion and autocorrection, edit mode/normal mode switching, handles editing commands, keyboard shortcuts and other events.
    +
    + +
    +
    +
    + +
    Constructors
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Functions
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + criteria(text) + +
    + + + + + + +
    parameters
    + + + + + + + + +
    + + + text + + +
    + + + + + +
    + + + +
    +
    + + + + criteria(text) + +
    + + + + + + +
    parameters
    + + + + + + + + +
    + + + text + + +
    + + + + + +
    + + + +
    +
    + + + + this.contentElement.form.onsubmit() + +
    + + + + + + + + + + +
    + + + +
    +
    + + + + cancelMousedown(e) + +
    + + + + + + +
    parameters
    + + + + + + + + +
    + + + e + + +
    + + + + + +
    + + + +
    +
    + + + + finder(node) + +
    + + + + + + +
    parameters
    + + + + + + + + +
    + + + node + + +
    + + + + + +
    + + + +
    +
    + + + + exitCondition(node) + +
    + + + + + + +
    parameters
    + + + + + + + + +
    + + + node + + +
    + + + + + +
    + + + +
    Objects
    + + +
    +
    + + + object + + + + this.config + +
    + + +
    Editor's configuration
    + + + + + +
    + + + + +
    +
    + + + Element + + + + this.contentElement + +
    + + +
    Original content element
    + + + + + +
    + + + + +
    +
    + + + Document + + + + this.doc + +
    + + +
    Owner document of content element
    + + + + + +
    + + + + +
    +
    + + + Element + + + + this.body + +
    + + +
    Body of content element
    + + + + + +
    + + + + +
    +
    + + + Object + + + + this.currentEditMode + +
    + + +
    False or 'readonly' means read-only mode, true or 'wysiwyg' means WYSIWYG editing mode, and 'source' means source editing mode.
    + + + + + +
    + + + + +
    +
    + + + xq.RichDom + + + + this.rdom + +
    + + +
    RichDom instance
    + + + + + +
    + + + + +
    +
    + + + xq.Validator + + + + this.validator + +
    + + +
    Validator instance
    + + + + + +
    + + + + +
    +
    + + + Element + + + + this.outmostWrapper + +
    + + +
    Outmost wrapper div
    + + + + + +
    + + + + +
    +
    + + + Element + + + + this.sourceEditorDiv + +
    + + +
    Source editor container
    + + + + + +
    + + + + +
    +
    + + + Element + + + + this.sourceEditorTextarea + +
    + + +
    Source editor textarea
    + + + + + +
    + + + + +
    +
    + + + Element + + + + this.wysiwygEditorDiv + +
    + + +
    WYSIWYG editor container
    + + + + + +
    + + + + +
    +
    + + + IFrame + + + + this.editorFrame + +
    + + +
    Design mode iframe
    + + + + + +
    + + + + +
    +
    + + + Window + + + + this.editorWin + +
    + + +
    Window that contains design mode iframe
    + + + + + +
    + + + + +
    +
    + + + Document + + + + this.editorDoc + +
    + + +
    Document that contained by design mode iframe
    + + + + + +
    + + + + +
    +
    + + + Element + + + + this.editorBody + +
    + + +
    Body that contained by design mode iframe
    + + + + + +
    + + + + +
    +
    + + + Element + + + + this.toolbarContainer + +
    + + +
    Toolbar container
    + + + + + +
    + + + + +
    +
    + + + Array + + + + this.toolbarButtons + +
    + + +
    Toolbar buttons
    + + + + + +
    + + + + +
    +
    + + + xq.EditHistory + + + + this.editHistory + +
    + + +
    Undo/redo manager
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:34 GMT. +
    + + diff --git a/modules/editor/skins/xquared/doc/api/_06.html b/modules/editor/skins/xquared/doc/api/_06.html new file mode 100644 index 000000000..3aa42a640 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/_06.html @@ -0,0 +1,216 @@ + + + + + + JsDoc: RichDom.js + + + + +
    +
    + +
    Library: RichDom.js
    +
    +
    + Overview +
    +
    +
    +
    + +
    +
    +
    + +
    Constructors
    + + + + + + + + + + + + +
    Functions
    + + + + + + +
    +
    + + + + finder(node) + +
    + + + + + + +
    parameters
    + + + + + + + + +
    + + + node + + +
    + + + + + +
    + + + +
    +
    + + + + exitCondition(node) + +
    + + + + + + +
    parameters
    + + + + + + + + +
    + + + node + + +
    + + + + + +
    + + + +
    +
    + + + + xq.RichDom.createInstance() + +
    + + +
    Creates and returns instance of browser specific implementation.
    + + + + + + + + + +
    + + + +
    Objects
    + + +
    +
    + + + + + xq.RichDom + +
    + + +
    Encapsulates browser incompatibility problem and provides rich set of DOM manipulation API. + +RichDom provides basic CRUD + Advanced DOM manipulation API, various query methods and caret/selection management API
    + + + + + +
    + + + + +
    +
    + + + + + this.tree + +
    + + +
    instance of DomTree
    + + + + + +
    + + + + + + + + + + + + +
    +
    +
    + Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:48 GMT. +
    + + diff --git a/modules/editor/skins/xquared/doc/api/_07.html b/modules/editor/skins/xquared/doc/api/_07.html new file mode 100644 index 000000000..58e74f9aa --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/_07.html @@ -0,0 +1,71 @@ + + + + + + JsDoc: RichDomGecko.js + + + + +
    +
    + +
    Library: RichDomGecko.js
    +
    +
    + Overview +
    +
    +
    +
    + +
    +
    +
    + +
    Constructors
    + + + + +
    Functions
    + + + + +
    Objects
    + + +
    +
    + + + + + xq.RichDomGecko + +
    + + +
    RichDom for Gecko
    + + + + + +
    + + + +
    +
    +
    + Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:48 GMT. +
    + + diff --git a/modules/editor/skins/xquared/doc/api/_08.html b/modules/editor/skins/xquared/doc/api/_08.html new file mode 100644 index 000000000..56f0609f3 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/_08.html @@ -0,0 +1,71 @@ + + + + + + JsDoc: RichDomTrident.js + + + + +
    +
    + +
    Library: RichDomTrident.js
    +
    +
    + Overview +
    +
    +
    +
    + +
    +
    +
    + +
    Constructors
    + + + + +
    Functions
    + + + + +
    Objects
    + + +
    +
    + + + + + xq.RichDomTrident + +
    + + +
    RichDom for Internet Explorer 6 and 7
    + + + + + +
    + + + +
    +
    +
    + Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:48 GMT. +
    + + diff --git a/modules/editor/skins/xquared/doc/api/_09.html b/modules/editor/skins/xquared/doc/api/_09.html new file mode 100644 index 000000000..5a3a1fe0f --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/_09.html @@ -0,0 +1,71 @@ + + + + + + JsDoc: RichDomW3.js + + + + +
    +
    + +
    Library: RichDomW3.js
    +
    +
    + Overview +
    +
    +
    +
    + +
    +
    +
    + +
    Constructors
    + + + + +
    Functions
    + + + + +
    Objects
    + + +
    +
    + + + + + xq.RichDomW3 + +
    + + +
    RichDom for W3C Standard Engine
    + + + + + +
    + + + +
    +
    +
    + Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:49 GMT. +
    + + diff --git a/modules/editor/skins/xquared/doc/api/_10.html b/modules/editor/skins/xquared/doc/api/_10.html new file mode 100644 index 000000000..9c4670246 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/_10.html @@ -0,0 +1,71 @@ + + + + + + JsDoc: RichDomWebkit.js + + + + +
    +
    + +
    Library: RichDomWebkit.js
    +
    +
    + Overview +
    +
    +
    +
    + +
    +
    +
    + +
    Constructors
    + + + + +
    Functions
    + + + + +
    Objects
    + + +
    +
    + + + + + xq.RichDomWebkit + +
    + + +
    RichDom for Webkit
    + + + + + +
    + + + +
    +
    +
    + Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:49 GMT. +
    + + diff --git a/modules/editor/skins/xquared/doc/api/_11.html b/modules/editor/skins/xquared/doc/api/_11.html new file mode 100644 index 000000000..c5409a591 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/_11.html @@ -0,0 +1,125 @@ + + + + + + JsDoc: RichTable.js + + + + +
    +
    + +
    Library: RichTable.js
    +
    +
    + Overview +
    +
    +
    +
    + +
    +
    +
    + +
    Constructors
    + + + + +
    Functions
    + + +
    +
    + + + + xq.RichTable.create(rdom, cols, rows, headerPositions) + +
    + + + + + + +
    parameters
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + rdom + + +
    + + + cols + + +
    + + + rows + + +
    + + + headerPositions + + +
    + + + + + +
    + + + +
    Objects
    + + + + +
    +
    +
    + Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:49 GMT. +
    + + diff --git a/modules/editor/skins/xquared/doc/api/_12.html b/modules/editor/skins/xquared/doc/api/_12.html new file mode 100644 index 000000000..2d0bff85a --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/_12.html @@ -0,0 +1,189 @@ + + + + + + JsDoc: Shortcut.js + + + + +
    +
    + +
    Library: Shortcut.js
    +
    +
    + Overview +
    +
    +
    +
    + +
    +
    +
    + +
    Constructors
    + + + + + + + + +
    Functions
    + + +
    +
    + + + + xq.Shortcut.interprete(expression) + +
    + + + + + + +
    parameters
    + + + + + + + + +
    + + + expression + + +
    + + + + + +
    + + + +
    +
    + + + + xq.Shortcut._interpreteModifier(expression, modifierName) + +
    + + + + + + +
    parameters
    + + + + + + + + + + + + + + +
    + + + expression + + +
    + + + modifierName + + +
    + + + + + +
    + + + +
    +
    + + + + xq.Shortcut._interpreteWhich(keyName) + +
    + + + + + + +
    parameters
    + + + + + + + + +
    + + + keyName + + +
    + + + + + +
    + + + +
    Objects
    + + + + + + + + + + +
    +
    +
    + Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:49 GMT. +
    + + diff --git a/modules/editor/skins/xquared/doc/api/_13.html b/modules/editor/skins/xquared/doc/api/_13.html new file mode 100644 index 000000000..46fe53499 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/_13.html @@ -0,0 +1,153 @@ + + + + + + JsDoc: Validator.js + + + + +
    +
    + +
    Library: Validator.js
    +
    +
    + Overview +
    +
    +
    +
    + +
    +
    +
    + +
    Constructors
    + + + + + + +
    Functions
    + + + + +
    +
    + + + + xq.Validator.createInstance(curUrl, urlValidationMode, allowedTags, allowedAttrs) + +
    + + +
    Creates and returns instance of browser specific implementation.
    + + + + + +
    parameters
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + curUrl + + +
    + + + urlValidationMode + + +
    + + + allowedTags + + +
    + + + allowedAttrs + + +
    + + + + + +
    + + + +
    Objects
    + + +
    +
    + + + + + xq.Validator + +
    + + +
    Validates and invalidates designmode contents
    + + + + + +
    + + + + + + +
    +
    +
    + Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:49 GMT. +
    + + diff --git a/modules/editor/skins/xquared/doc/api/_14.html b/modules/editor/skins/xquared/doc/api/_14.html new file mode 100644 index 000000000..3a15872b4 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/_14.html @@ -0,0 +1,71 @@ + + + + + + JsDoc: ValidatorGecko.js + + + + +
    +
    + +
    Library: ValidatorGecko.js
    +
    +
    + Overview +
    +
    +
    +
    + +
    +
    +
    + +
    Constructors
    + + + + +
    Functions
    + + + + +
    Objects
    + + +
    +
    + + + + + xq.ValidatorGecko + +
    + + +
    Validator for Gecko Engine
    + + + + + +
    + + + +
    +
    +
    + Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:49 GMT. +
    + + diff --git a/modules/editor/skins/xquared/doc/api/_15.html b/modules/editor/skins/xquared/doc/api/_15.html new file mode 100644 index 000000000..ee41915a5 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/_15.html @@ -0,0 +1,71 @@ + + + + + + JsDoc: ValidatorTrident.js + + + + +
    +
    + +
    Library: ValidatorTrident.js
    +
    +
    + Overview +
    +
    +
    +
    + +
    +
    +
    + +
    Constructors
    + + + + +
    Functions
    + + + + +
    Objects
    + + +
    +
    + + + + + xq.ValidatorTrident + +
    + + +
    Validator for Internet Explorer 6 and 7
    + + + + + +
    + + + +
    +
    +
    + Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:50 GMT. +
    + + diff --git a/modules/editor/skins/xquared/doc/api/_16.html b/modules/editor/skins/xquared/doc/api/_16.html new file mode 100644 index 000000000..5b7576800 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/_16.html @@ -0,0 +1,71 @@ + + + + + + JsDoc: ValidatorW3.js + + + + +
    +
    + +
    Library: ValidatorW3.js
    +
    +
    + Overview +
    +
    +
    +
    + +
    +
    +
    + +
    Constructors
    + + + + +
    Functions
    + + + + +
    Objects
    + + +
    +
    + + + + + xq.ValidatorW3 + +
    + + +
    Validator for W3C Standard Engine
    + + + + + +
    + + + +
    +
    +
    + Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:50 GMT. +
    + + diff --git a/modules/editor/skins/xquared/doc/api/_17.html b/modules/editor/skins/xquared/doc/api/_17.html new file mode 100644 index 000000000..b4e3818df --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/_17.html @@ -0,0 +1,71 @@ + + + + + + JsDoc: ValidatorWebkit.js + + + + +
    +
    + +
    Library: ValidatorWebkit.js
    +
    +
    + Overview +
    +
    +
    +
    + +
    +
    +
    + +
    Constructors
    + + + + +
    Functions
    + + + + +
    Objects
    + + +
    +
    + + + + + xq.ValidatorWebkit + +
    + + +
    Validator for Webkit
    + + + + + +
    + + + +
    +
    +
    + Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:50 GMT. +
    + + diff --git a/modules/editor/skins/xquared/doc/api/_18.html b/modules/editor/skins/xquared/doc/api/_18.html new file mode 100644 index 000000000..88d060871 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/_18.html @@ -0,0 +1,512 @@ + + + + + + JsDoc: XQuared.js + + + + +
    +
    + +
    Library: XQuared.js
    +
    +
    + Overview +
    +
    +
    +
    + +
    +
    +
    + +
    Constructors
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Functions
    + + + + +
    +
    + + + + xq.asEventSource(object, prefix, events) + +
    + + +
    Make given object as event source
    + + + + + +
    parameters
    + + + + + + + + + + + + + + + + + + + + +
    + Object + + object + + target object +
    + String + + prefix + + prefix for generated functions +
    + Array + + events + + array of string which contains name of events +
    + + + + + +
    + + + +
    +
    + + + Array.indexOf(n) + + +
    + + +
    Returns the index of given element
    + + + + + +
    parameters
    + + + + + + + + +
    + + + n + + +
    + + + +
    returns
    + + + + + + + +
    + Number + + index or -1 +
    + + + +
    + + + +
    +
    + + + + Date.pass(msec) + +
    + + + + + + +
    parameters
    + + + + + + + + +
    + + + msec + + +
    + + + + + +
    + + + +
    +
    + + + + Date.get() + +
    + + + + + + + + + + +
    + + + +
    +
    + + + Date.elapsed(msec) + + +
    + + + + + + +
    parameters
    + + + + + + + + +
    + + + msec + + +
    + + + + + +
    + + + +
    +
    + + + String.merge(data) + + +
    + + + + + + +
    parameters
    + + + + + + + + +
    + + + data + + +
    + + + + + +
    + + + +
    +
    + + + String.parseURL() + + +
    + + + + + + + + + + +
    + + + +
    +
    + + + + xq.findXquaredScript() + +
    + + + + + + + + + + +
    + + + +
    +
    + + + + xq.shouldLoadOthers() + +
    + + + + + + + + + + +
    + + + +
    +
    + + + + xq.loadScript(url) + +
    + + + + + + +
    parameters
    + + + + + + + + +
    + + + url + + +
    + + + + + +
    + + + +
    +
    + + + + xq.loadOthers() + +
    + + + + + + + + + + +
    + + + +
    Objects
    + + +
    +
    + + + + + xq + +
    + + +
    Namespace for entire Xquared classes
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:50 GMT. +
    + + diff --git a/modules/editor/skins/xquared/doc/api/_19.html b/modules/editor/skins/xquared/doc/api/_19.html new file mode 100644 index 000000000..4616b926c --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/_19.html @@ -0,0 +1,45 @@ + + + + + + JsDoc: _ui_templates.js + + + + +
    +
    + +
    Library: _ui_templates.js
    +
    +
    + Overview +
    +
    +
    +
    + +
    +
    +
    + +
    Constructors
    + + +
    Functions
    + + +
    Objects
    + +
    +
    +
    + Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:50 GMT. +
    + + diff --git a/modules/editor/skins/xquared/doc/api/constructor.gif b/modules/editor/skins/xquared/doc/api/constructor.gif new file mode 100644 index 0000000000000000000000000000000000000000..ba779972c2766b1dccbbc6e90f46fb9df4df374e GIT binary patch literal 363 zcmZ?wbhEHb6krfwxN6LB_{hP{n>VlBedfsd`xU)Q)~;Rk?c3K$OZU}G-u(CP-?lkB z_V3&K^6lsM@85m+@P6-!E8o9=zk2t@uV24DeE3k(wP?wb#ZMnUTCi~5mCKi_rfz-r z?(OO|D{Ch%-?ejF)zmFV4j;O5`O=#=uTGsjF?Zgq&!0aRb+4;!ZryU|`i|{eFI~Lw z=Jm_2p7xzPwtx8W?#bgv$BrCQ@M^zv=XOU|>;M1%8HfOiKUo+V7>pToKx#pLVqohy zFtflzM<{vI48sX3r$WvuZdTMj6?JuCjuQ8o3Gp*kq~j{njSjo9Z4}{2d@A5sl;Jct z<%`Da(?Oy}3~p{3MmnCHZafCPYOG4!)lNN3OdJLbMiP?@yNm@5_*q!k4HEVAo16@o pSVZJzIC&_@N3NBTR5f5OHWJ^?&c(IIl|i}LSiSdXi?btxH2^cNq~8Dl literal 0 HcmV?d00001 diff --git a/modules/editor/skins/xquared/doc/api/default.css b/modules/editor/skins/xquared/doc/api/default.css new file mode 100644 index 000000000..cfe837beb --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/default.css @@ -0,0 +1,116 @@ +body,a +{ + color: #000; + font: 12px verdana; +} + +ul +{ + list-style-type: none; + margin-left: 10px; + padding-left: 10px; +} + +.content { } +.docs { } +.signature { font-weight: normal; } +.code { + font: 11px monaco,monospace; + padding: 4px; + margin-left: 18px; + border: 1px dashed #ccc; +} + +.itemTitle +{ + font-size: 12px; + font-weight: bold; + height: 16px; +} + +.item { } + +.sectionHead +{ + font-size: 18px; + font-weight: bold; + background-color: #C0C1DE; + color: #fff; + margin-top: 18px; + padding: 2px 4px 2px 4px; +} + +.section +{ + padding: 8px; + border: 1px #8A92BC solid; + margin: 4px; +} + +.detailHead +{ + border-bottom: 1px #8FB685 dotted; + font-size: 12px; + font-weight: bold; + color: #798E73; + margin-top: 18px; +} + +.desc { padding: 8px; } + +.fileHead +{ + background-image: url(file.gif); + background-repeat: no-repeat; + padding-left: 20px; + font-weight: bold; + font-size: 14px; + line-height: 20px; +} + +.overview .itemTitle +{ + background-image: url(overview.gif); + background-repeat: no-repeat; + padding-left: 20px; +} + +.constructor .itemTitle +{ + background-image: url(constructor.gif); + background-repeat: no-repeat; + padding-left: 20px; +} + +.function .itemTitle +{ + background-image: url(function.gif); + background-repeat: no-repeat; + padding-left: 20px; +} + +.object .itemTitle +{ + background-image: url(object.gif); + background-repeat: no-repeat; + padding-left: 20px; +} + +.type +{ + font-style: italic; + color: #999; + font-weight: normal; +} + +.itemTitle a.type { font-weight: bold; } + +.finePrint +{ + color: #878787; + font-family: verdana; + font-size: 10px; + text-align: right; +} + +.params td { padding-right: 10px; } \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/file.gif b/modules/editor/skins/xquared/doc/api/file.gif new file mode 100644 index 0000000000000000000000000000000000000000..9c7446e41ef97d4b19d23b5a71f23beb27036206 GIT binary patch literal 242 zcmZ?wbhEHb6krfwI3mXI>eZ{GM~{B`^y%%}r#pA+|z#zt;15yIA zlYuoq!KpXJQf``SXwK_RA-lX79^9EE;uyLntiegaK+{je=KiT?CtfP`FIn?QL8|-2 zJ(2G+9*b_xfBdUL;=m~{J*HZddza=PSrK6H?qj6%z8CG`g6?JIwM_M*IeEMS0^Ce( WnfjCLIMk+zuxQSjJ!iHegEat^EN}e) literal 0 HcmV?d00001 diff --git a/modules/editor/skins/xquared/doc/api/file_list.html b/modules/editor/skins/xquared/doc/api/file_list.html new file mode 100644 index 000000000..f6c3a20f5 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/file_list.html @@ -0,0 +1,149 @@ + + + + + JsDoc + + + + +
    File Index
    + + + \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/function.gif b/modules/editor/skins/xquared/doc/api/function.gif new file mode 100644 index 0000000000000000000000000000000000000000..be00b964ba12560f696afdb2dd6d01f89f8c109d GIT binary patch literal 224 zcmZ?wbhEHb6krfwI3mQ*KcV}~nbXr}PM$cqZ^y1JOP4R1JayvnQ-@csUOs=pytV7r z?A^a}(c%RM4(vN~_RPC?Z!TXy-_h0j|Nnmm;(+2$7DfgJAqE|ga*&-2tg#DJ`cg8z z0;{_GZrKG&&%Aiqh3AM1Z_K9&3j~U^w<@qSFl=Zz;;~X@fk1#niB_Pl28Rbz(*pnQ sW*&h?76xnSy&TO?55D|i+IC3kO4z-xw*m}Jn;O(LTeUm8v=tew0ga|o1^@s6 literal 0 HcmV?d00001 diff --git a/modules/editor/skins/xquared/doc/api/index.html b/modules/editor/skins/xquared/doc/api/index.html new file mode 100644 index 000000000..3df8e5bfc --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/index.html @@ -0,0 +1,13 @@ + + + + + JsDoc + + + + + + + \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/object.gif b/modules/editor/skins/xquared/doc/api/object.gif new file mode 100644 index 0000000000000000000000000000000000000000..409b58e334dc59762dd2ccdb6b01f9312851872d GIT binary patch literal 585 zcmZ?wbhEHb6krfwcoxI(;rjXyS5~~gzV7&%#;J*XPcLnnoh3ahOYXzFN3JudZIx;(UEW$?R1Axp_)2j!#-qZG3fI z$=P)^cemGlxVm=Fyxa#zXMVW4`u^_bN2it_Sz0hFm2W~6%ZGC_4=*k}xw`t(^ULoq zFTb(1Zd$U?<9+R)pI=yzCGzOZ%Kj+k$?=@iQpL7U3Vm~S?whmoo^Q*#yCULvkMX5h zZvBx=|NsAIpchd5$->CM5W}DYvJey}4D8DqVw##;TAO&HJG;6&d1CmZRRaXLxmj6d z?UkG~qnY_-l!LgqG+fO5r7YF0LqyCyrCBz!u^Do58u-Zxv-{}kI4~YQtnVdn?Cim= zCuXbVCZR2^Aj!ukDrgey>dtWgJ_iTW6JB2LK<1v;UCc4jrjegMf3b>ginfXR{pYXB v_xH0BBt14H2sA_+Ihu#lxiagE0ujg4KRk_@#Ql2Z;%aCd5CV6X-NIMnZ- literal 0 HcmV?d00001 diff --git a/modules/editor/skins/xquared/doc/api/overview.gif b/modules/editor/skins/xquared/doc/api/overview.gif new file mode 100644 index 0000000000000000000000000000000000000000..241c2574e50ec9d76119ca6729ae08d287c70e56 GIT binary patch literal 614 zcmZ?wbhEHb6krfwcvi%am=c$go|u#x|NZ;-^sJQZ+>Cwu_x}6$FDp0w(W6I&CHa{- z=^Hm~NJ>pOcKm2^TEgu+w;n!xc;N7!_wU~ULI1?w-FtRb)RaDX`namLe8Ieq4|y?gf-mE=#GHR<}TYaLx}KY#vg zYH3)%d38p1>V!%CyZ3K@`t<3v=~Es&ym#}?jYp3j9zAvN-u=6UrFoYwT|9r`+}(S3 z??1R(T~~ST+}Vp)fZRKO|Ngyn zy&YYB?aNjyy>{cu^XJbdPn}TPP<`~|p{dg+-@bGE>eVYbd6^e3oZqr_OIl`1VR7D^ zxwG23nk%ZyE?v2B?AX!u8`hPS7e0LSaMzxlTefV;%t>3cbY9=2?sMnQ*49_&7G~eR zb7RBCb*=5qa~I6MaPfRXa_s;A{~3q_ia%Kx85oKfbU?~Mal*iUxS^=2iM>FUD=1f~ zxu;0mM?BrkK!Z!Tw@EQp$T!MDH^Z-&Es0y+*~2^~JD9bXJHODr(7UP7sj!zZzRLcv07 z{#SB^3Njq-Y=vQry@f?bZZ@d$OjIhY`IG#FiHDJeF(jt*ahqemTS%Nif}=v;OhGk2 kiwu{8-BNmyCQ~METzZJnhgru(QE<6Kr-`EkD-(k?01Uk<1^@s6 literal 0 HcmV?d00001 diff --git a/modules/editor/skins/xquared/doc/api/splash.html b/modules/editor/skins/xquared/doc/api/splash.html new file mode 100644 index 000000000..8c7495195 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/splash.html @@ -0,0 +1,7 @@ + + + JsDoc + + + + \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_01.html b/modules/editor/skins/xquared/doc/api/src_01.html new file mode 100644 index 000000000..4d8272800 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/src_01.html @@ -0,0 +1,24 @@ +
      1 xq.Browser = {
    +  2 	// By Layout Engines
    +  3 	isTrident: navigator.appName == "Microsoft Internet Explorer",
    +  4 	isWebkit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
    +  5 	isGecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
    +  6 	isKHTML: navigator.userAgent.indexOf('KHTML') != -1,
    +  7 	isPresto: navigator.appName == "Opera",
    +  8 	
    +  9 	// By Platforms
    + 10 	isMac: navigator.userAgent.indexOf("Macintosh") != -1,
    + 11 	isUbuntu: navigator.userAgent.indexOf('Ubuntu') != -1,
    + 12 
    + 13 	// By Browsers
    + 14 	isIE: navigator.appName == "Microsoft Internet Explorer",
    + 15 	isIE6: navigator.userAgent.indexOf('MSIE 6') != -1,
    + 16 	isIE7: navigator.userAgent.indexOf('MSIE 7') != -1
    + 17 };
    \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_02.html b/modules/editor/skins/xquared/doc/api/src_02.html new file mode 100644 index 000000000..7d1de91f7 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/src_02.html @@ -0,0 +1,344 @@ +
      1 /**
    +  2  * @fileOverview xq.controls provides common UI elements such as dialog.
    +  3  */
    +  4 xq.controls = {};
    +  5 
    +  6 
    +  7 
    +  8 xq.controls.FormDialog = Class.create({
    +  9 	/**
    + 10      * @constructor
    + 11      *
    + 12      * @param {String} html HTML string which contains FORM
    + 13      * @param {Function} [onLoadHandler] callback function to be called when the form is loaded
    + 14 	 */
    + 15 	initialize: function(xed, html, onLoadHandler, onCloseHandler) {
    + 16 		this.xed = xed;
    + 17 		this.html = html;
    + 18 		this.onLoadHandler = onLoadHandler || function() {};
    + 19 		this.onCloseHandler = onCloseHandler || function() {};
    + 20 		this.form = null;
    + 21 	},
    + 22 	/**
    + 23 	 * Show dialog
    + 24 	 *
    + 25 	 * @param {Object} [options] collection of options
    + 26 	 */
    + 27 	show: function(options) {
    + 28 		options = options || {};
    + 29 		options.position = options.position || 'centerOfWindow';
    + 30 		options.mode = options.mode || 'modal';
    + 31 		options.cancelOnEsc = options.cancelOnEsc || true;
    + 32 		
    + 33 		var self = this;
    + 34 		
    + 35 		// create and append container
    + 36 		var container = $(document.createElement('DIV'));
    + 37 		container.style.display = 'none';
    + 38 		document.body.appendChild(container);
    + 39 		
    + 40 		// initialize form
    + 41 		container.innerHTML = this.html;
    + 42 		this.form = $(container.getElementsByTagName('FORM')[0]);
    + 43 		
    + 44 		this.form.onsubmit = function() {
    + 45 			self.onCloseHandler($(this).serialize(true));
    + 46 			self.close();
    + 47 			return false;
    + 48 		};
    + 49 		
    + 50 		var cancelButton = this.form.getElementsByClassName('cancel')[0];
    + 51 		cancelButton.onclick = function() {
    + 52 			self.onCloseHandler();
    + 53 			self.close();
    + 54 		};
    + 55 		
    + 56 		// append dialog
    + 57 		document.body.appendChild(this.form);
    + 58 		container.parentNode.removeChild(container);
    + 59 		
    + 60 		// place dialog to center of window
    + 61 		this.setPosition(options.position);
    + 62 		
    + 63 		// give focus
    + 64 		var elementToFocus = this.form.getElementsByClassName('initialFocus');
    + 65 		if(elementToFocus.length > 0) elementToFocus[0].focus();
    + 66 		
    + 67 		// handle cancelOnEsc option
    + 68 		if(options.cancelOnEsc) {
    + 69 			Event.observe(this.form, 'keydown', function(e) {
    + 70 				if(e.keyCode == 27) {
    + 71 					this.onCloseHandler();
    + 72 					this.close();
    + 73 				}
    + 74 				return false;
    + 75 			}.bind(this));
    + 76 		}
    + 77 		
    + 78 		this.onLoadHandler(this);
    + 79 	},
    + 80 	close: function() {
    + 81 		this.form.parentNode.removeChild(this.form);
    + 82 	},
    + 83 	setPosition: function(target) {
    + 84 		var targetElement;
    + 85 		
    + 86 		if(target == 'centerOfWindow') {
    + 87 			targetElement = document.documentElement;
    + 88 		} else if(target == 'centerOfEditor') {
    + 89 			targetElement = this.xed.getDoc()[xq.Browser.isTrident ? "body" : "documentElement"];
    + 90 		} else if(target == 'nearbyCaret') {
    + 91 			throw "Not implemented yet";
    + 92 		} else {
    + 93 			throw "Invalid argument: " + target;
    + 94 		}
    + 95 		
    + 96 		var targetWidth = targetElement.clientWidth;
    + 97 		var targetHeight = targetElement.clientHeight;
    + 98 		var dialogWidth = this.form.clientWidth;
    + 99 		var dialogHeight = this.form.clientHeight;
    +100 		
    +101 		var x = parseInt((targetWidth - dialogWidth) / 2);
    +102 		var y = parseInt((targetHeight - dialogHeight) / 2);
    +103 		
    +104 		this.form.style.left = x + "px";
    +105 		this.form.style.top = y + "px";
    +106 	}
    +107 })
    +108 
    +109 
    +110 
    +111 xq.controls.QuickSearchDialog = Class.create({
    +112 	/**
    +113      * @constructor
    +114 	 */
    +115 	initialize: function(xed, param) {
    +116 		this.xed = xed;
    +117 		
    +118 		this.rdom = xq.RichDom.createInstance();
    +119 		this.rdom.setRoot(document.body);
    +120 		
    +121 		this.param = param;
    +122 		if(!this.param.renderItem) this.param.renderItem = function(item) {
    +123 			return this.rdom.getInnerText(item);
    +124 		}.bind(this);
    +125 		
    +126 		this.container = null;
    +127 	},
    +128 	
    +129 	getQuery: function() {
    +130 		if(!this.container) return "";
    +131 		return this._getInputField().value;
    +132 	},
    +133 	
    +134 	onSubmit: function(e) {
    +135 		if(this.matchCount() > 0) {
    +136 			this.param.onSelect(this.xed, this.list[this._getSelectedIndex()]);
    +137 		}
    +138 		
    +139 		this.close();
    +140 		Event.stop(e);
    +141 		return false;
    +142 	},
    +143 	
    +144 	onCancel: function(e) {
    +145 		if(this.param.onCancel) this.param.onCancel(this.xed);
    +146 		this.close();
    +147 	},
    +148 	
    +149 	onBlur: function(e) {
    +150 		// TODO: Ugly
    +151 		setTimeout(function() {this.onCancel(e)}.bind(this), 400);
    +152 	},
    +153 	
    +154 	onKey: function(e) {
    +155 		var esc = new xq.Shortcut("ESC");
    +156 		var enter = new xq.Shortcut("ENTER");
    +157 		var up = new xq.Shortcut("UP");
    +158 		var down = new xq.Shortcut("DOWN");
    +159 		
    +160 		if(esc.matches(e)) {
    +161 			this.onCancel(e);
    +162 		} else if(enter.matches(e)) {
    +163 			this.onSubmit(e);
    +164 		} else if(up.matches(e)) {
    +165 			this._moveSelectionUp();
    +166 		} else if(down.matches(e)) {
    +167 			this._moveSelectionDown();
    +168 		} else {
    +169 			this.updateList();
    +170 		}
    +171 	},
    +172 	
    +173 	onClick: function(e) {
    +174 		var target = e.srcElement || e.target;
    +175 		if(target.nodeName == "LI") {
    +176 			
    +177 			var index = this._getIndexOfLI(target);
    +178 			this.param.onSelect(this.xed, this.list[index]);
    +179 		}
    +180 	},
    +181 	
    +182 	onList: function(list) {
    +183 		this.list = list;
    +184 		this.renderList(list);
    +185 	},
    +186 	
    +187 	updateList: function() {
    +188 		window.setTimeout(function() {
    +189 			this.param.listProvider(this.getQuery(), this.xed, this.onList.bind(this));
    +190 		}.bind(this), 0);
    +191 	},
    +192 	
    +193 	renderList: function(list) 
    +194 	{
    +195 		var ol = this._getListContainer();
    +196 		ol.innerHTML = "";
    +197 		
    +198 		for(var i = 0; i < list.length; i++) {
    +199 			var li = this.rdom.createElement('LI');
    +200 			li.innerHTML = this.param.renderItem(list[i]);
    +201 			ol.appendChild(li);
    +202 		}
    +203 		
    +204 		if(ol.hasChildNodes()) {
    +205 			ol.firstChild.className = "selected";
    +206 		}
    +207 	},
    +208 	
    +209 	show: function() {
    +210 		if(!this.container) this.container = this._create();
    +211 		
    +212 		var dialog = this.rdom.insertNodeAt(this.container, this.rdom.getRoot(), "end");
    +213 		this.setPosition('centerOfEditor');
    +214 		this.updateList();
    +215 		this.focus();
    +216 	},
    +217 	
    +218 	close: function() {
    +219 		this.rdom.deleteNode(this.container);
    +220 	},
    +221 	
    +222 	focus: function() {
    +223 		this._getInputField().focus();
    +224 	},
    +225 	
    +226 	setPosition: function(target) {
    +227 		var targetElement;
    +228 		
    +229 		if(target == 'centerOfWindow') {
    +230 			targetElement = document.documentElement;
    +231 		} else if(target == 'centerOfEditor') {
    +232 			targetElement = this.xed.getDoc().documentElement;
    +233 		} else if(target == 'nearbyCaret') {
    +234 			throw "Not implemented yet";
    +235 		} else {
    +236 			throw "Invalid argument: " + target;
    +237 		}
    +238 		
    +239 		var targetWidth = targetElement.clientWidth;
    +240 		var targetHeight = targetElement.clientHeight;
    +241 		var dialogWidth = this.container.clientWidth;
    +242 		var dialogHeight = this.container.clientHeight;
    +243 		
    +244 		var x = parseInt((targetWidth - dialogWidth) / 2);
    +245 		var y = parseInt((targetHeight - dialogHeight) / 2);
    +246 		this.container.style.left = x + "px";
    +247 		this.container.style.top = y + "px";
    +248 	},
    +249 	
    +250 	matchCount: function() {
    +251 		return this.list ? this.list.length : 0;
    +252 	},
    +253 	
    +254 	_create: function() {
    +255 		// make container
    +256 		var container = this.rdom.createElement("DIV");
    +257 		container.className = "xqQuickSearch";
    +258 		
    +259 		// make title
    +260 		if(this.param.title) {
    +261 			var title = this.rdom.createElement("H1");
    +262 			title.innerHTML = this.param.title;
    +263 			container.appendChild(title);
    +264 		}
    +265 		
    +266 		// make input field
    +267 		var inputWrapper = this.rdom.createElement("DIV");
    +268 		inputWrapper.className = "input";
    +269 		var form = this.rdom.createElement("FORM");
    +270 		var input = this.rdom.createElement("INPUT");
    +271 		input.type = "text";
    +272 		input.value = "";
    +273     	form.appendChild(input);
    +274 		inputWrapper.appendChild(form);
    +275 		container.appendChild(inputWrapper);
    +276 		
    +277 		// make list
    +278 		var list = this.rdom.createElement("OL");
    +279 
    +280 	    Event.observe(input, 'blur', this.onBlur.bindAsEventListener(this));
    +281     	Event.observe(input, 'keypress', this.onKey.bindAsEventListener(this));
    +282     	Event.observe(list, 'click', this.onClick.bindAsEventListener(this), true);
    +283     	Event.observe(form, 'submit', this.onSubmit.bindAsEventListener(this));
    +284     	Event.observe(form, 'reset', this.onCancel.bindAsEventListener(this));
    +285 
    +286 		container.appendChild(list);
    +287 		return container;
    +288 	},
    +289 	
    +290 	_getInputField: function() {
    +291 		return this.container.getElementsByTagName('INPUT')[0];
    +292 	},
    +293 	
    +294 	_getListContainer: function() {
    +295 		return this.container.getElementsByTagName('OL')[0];
    +296 	},
    +297 	
    +298 	_getSelectedIndex: function() {
    +299 		var ol = this._getListContainer();
    +300 		for(var i = 0; i < ol.childNodes.length; i++) {
    +301 			if(ol.childNodes[i].className == 'selected') return i;
    +302 		}
    +303 	},
    +304 	
    +305 	_getIndexOfLI: function(li) {
    +306 		var ol = this._getListContainer();
    +307 		for(var i = 0; i < ol.childNodes.length; i++) {
    +308 			if(ol.childNodes[i] == li) return i;
    +309 		}
    +310 	},
    +311 	
    +312 	_moveSelectionUp: function() {
    +313 		var count = this.matchCount();
    +314 		if(count == 0) return;
    +315 		var index = this._getSelectedIndex();
    +316 		var ol = this._getListContainer();
    +317 		ol.childNodes[index].className = "";
    +318 		
    +319 		index--;
    +320 		if(index < 0) index = count - 1;
    +321 
    +322 		ol.childNodes[index].className = "selected";
    +323 	},
    +324 	
    +325 	_moveSelectionDown: function() {
    +326 		var count = this.matchCount();
    +327 		if(count == 0) return;
    +328 		var index = this._getSelectedIndex();
    +329 		var ol = this._getListContainer();
    +330 		ol.childNodes[index].className = "";
    +331 
    +332 		index++;
    +333 		if(index >= count) index = 0;
    +334 		
    +335 		ol.childNodes[index].className = "selected";
    +336 	}
    +337 });
    \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_03.html b/modules/editor/skins/xquared/doc/api/src_03.html new file mode 100644 index 000000000..076de09f1 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/src_03.html @@ -0,0 +1,325 @@ +
      1 /**
    +  2  * Provide various tree operations.
    +  3  *
    +  4  * TODO: Add specs
    +  5  */
    +  6 xq.DomTree = Class.create({
    +  7 	initialize: function() {
    +  8 		this._blockTags = ["DIV", "DD", "LI", "ADDRESS", "CAPTION", "DT", "H1", "H2", "H3", "H4", "H5", "H6", "HR", "P", "BODY", "BLOCKQUOTE", "PRE", "PARAM", "DL", "OL", "UL", "TABLE", "THEAD", "TBODY", "TR", "TH", "TD"];
    +  9 		this._blockContainerTags = ["DIV", "DD", "LI", "BODY", "BLOCKQUOTE", "UL", "OL", "DL", "TABLE", "THEAD", "TBODY", "TR", "TH", "TD"];
    + 10 		this._listContainerTags = ["OL", "UL", "DL"];
    + 11 		this._tableCellTags = ["TH", "TD"];
    + 12 		this._blockOnlyContainerTags = ["BODY", "BLOCKQUOTE", "UL", "OL", "DL", "TABLE", "THEAD", "TBODY", "TR"];
    + 13 		this._atomicTags = ["IMG", "OBJECT", "BR", "HR"];
    + 14 	},
    + 15 	
    + 16 	getBlockTags: function() {
    + 17 		return this._blockTags;
    + 18 	},
    + 19 	
    + 20 	/**
    + 21 	 * Find common ancestor(parent) and his immediate children(left and right).
    + 22 	 *
    + 23 	 * A --- B -+- C -+- D -+- E
    + 24 	 *          |
    + 25 	 *          +- F -+- G
    + 26 	 *
    + 27 	 * For example:
    + 28 	 * > findCommonAncestorAndImmediateChildrenOf("E", "G")
    + 29 	 *
    + 30 	 * will return
    + 31 	 *
    + 32 	 * > {parent:"B", left:"C", right:"F"}
    + 33 	 */
    + 34 	findCommonAncestorAndImmediateChildrenOf: function(left, right) {
    + 35 		if(left.parentNode == right.parentNode) {
    + 36 			return {
    + 37 				left:left,
    + 38 				right:right,
    + 39 				parent:left.parentNode
    + 40 			};
    + 41 		} else {
    + 42 			var parentsOfLeft = this.collectParentsOf(left, true);
    + 43 			var parentsOfRight = this.collectParentsOf(right, true);
    + 44 			var ca = this.getCommonAncestor(parentsOfLeft, parentsOfRight);
    + 45 	
    + 46 			var leftAncestor = parentsOfLeft.find(function(node) {return node.parentNode == ca});
    + 47 			var rightAncestor = parentsOfRight.find(function(node) {return node.parentNode == ca});
    + 48 			
    + 49 			return {
    + 50 				left:leftAncestor,
    + 51 				right:rightAncestor,
    + 52 				parent:ca
    + 53 			};
    + 54 		}
    + 55 	},
    + 56 	
    + 57 	/**
    + 58 	 * Find leaves at edge.
    + 59 	 *
    + 60 	 * A --- B -+- C -+- D -+- E
    + 61 	 *          |
    + 62 	 *          +- F -+- G
    + 63 	 *
    + 64 	 * For example:
    + 65 	 * > getLeavesAtEdge("A")
    + 66 	 *
    + 67 	 * will return
    + 68 	 *
    + 69 	 * > ["E", "G"]
    + 70 	 */
    + 71 	getLeavesAtEdge: function(element) {
    + 72 		if(!element.hasChildNodes()) return [null, null];
    + 73 		
    + 74 		var findLeft = function(el) {
    + 75 			for (var i = 0; i < el.childNodes.length; i++) {
    + 76 				if (el.childNodes[i].nodeType == 1 && this.isBlock(el.childNodes[i])) return findLeft(el.childNodes[i]);
    + 77 			}
    + 78 			return el;
    + 79 		}.bind(this);
    + 80 		
    + 81 		var findRight=function(el) {
    + 82 			for (var i = el.childNodes.length; i--;) {
    + 83 				if (el.childNodes[i].nodeType == 1 && this.isBlock(el.childNodes[i])) return findRight(el.childNodes[i]);
    + 84 			}
    + 85 			return el;
    + 86 		}.bind(this);
    + 87 		
    + 88 		var left = findLeft(element);
    + 89 		var right = findRight(element);
    + 90 		return [left == element ? null : left, right == element ? null : right];
    + 91 	},
    + 92 	
    + 93 	getCommonAncestor: function(parents1, parents2) {
    + 94 		for(var i = 0; i < parents1.length; i++) {
    + 95 			for(var j = 0; j < parents2.length; j++) {
    + 96 				if(parents1[i] == parents2[j]) return parents1[i];
    + 97 			}
    + 98 		}
    + 99 	},
    +100 	
    +101 	collectParentsOf: function(node, includeSelf, exitCondition) {
    +102 		var parents = [];
    +103 		if(includeSelf) parents.push(node);
    +104 		
    +105 		while((node = node.parentNode) && (node.nodeName != "HTML") && !(typeof exitCondition == "function" && exitCondition(node))) parents.push(node);
    +106 		return parents;
    +107 	},
    +108 	
    +109 	isDescendantOf: function(parent, child) {
    +110 		if(parent.length > 0) {
    +111 			for(var i = 0; i < parent.length; i++) {
    +112 				if(this.isDescendantOf(parent[i], child)) return true;
    +113 			}
    +114 			return false;
    +115 		}
    +116 		
    +117 		if(parent == child) return false;
    +118 		
    +119 	    while (child = child.parentNode)
    +120 	      if (child == parent) return true;
    +121 	    return false;
    +122 	},
    +123 	
    +124 	/**
    +125 	 * Perform tree walking (foreward)
    +126 	 */
    +127 	walkForward: function(node) {
    +128 		if(node.hasChildNodes()) return node.firstChild;
    +129 		if(node.nextSibling) return node.nextSibling;
    +130 		
    +131 		while(node = node.parentNode) {
    +132 			if(node.nextSibling) return node.nextSibling;
    +133 		}
    +134 		
    +135 		return null;
    +136 	},
    +137 	
    +138 	/**
    +139 	 * Perform tree walking (backward)
    +140 	 */
    +141 	walkBackward: function(node) {
    +142 		if(node.previousSibling) {
    +143 			node = node.previousSibling;
    +144 			while(node.hasChildNodes()) {node = node.lastChild;}
    +145 			return node;
    +146 		}
    +147 		
    +148 		return node.parentNode;
    +149 	},
    +150 	
    +151 	/**
    +152 	 * Perform tree walking (to next siblings)
    +153 	 */
    +154 	walkNext: function(node) {return node.nextSibling},
    +155 	
    +156 	/**
    +157 	 * Perform tree walking (to next siblings)
    +158 	 */
    +159 	walkPrev: function(node) {return node.previousSibling},
    +160 	
    +161 	/**
    +162 	 * Returns true if target is followed by start
    +163 	 */
    +164 	checkTargetForward: function(start, target) {
    +165 		return this._check(start, this.walkForward, target);
    +166 	},
    +167 
    +168 	/**
    +169 	 * Returns true if start is followed by target
    +170 	 */
    +171 	checkTargetBackward: function(start, target) {
    +172 		return this._check(start, this.walkBackward, target);
    +173 	},
    +174 	
    +175 	findForward: function(start, condition, exitCondition) {
    +176 		return this._find(start, this.walkForward, condition, exitCondition);
    +177 	},
    +178 	
    +179 	findBackward: function(start, condition, exitCondition) {
    +180 		return this._find(start, this.walkBackward, condition, exitCondition);
    +181 	},
    +182 	
    +183 	/** @private */
    +184 	_check: function(start, direction, target) {
    +185 		if(start == target) return false;
    +186 		
    +187 		while(start = direction(start)) {
    +188 			if(start == target) return true;
    +189 		}
    +190 		return false;
    +191 	},
    +192 	
    +193 	/** @private */
    +194 	_find: function(start, direction, condition, exitCondition) {
    +195 		while(start = direction(start)) {
    +196 			if(exitCondition && exitCondition(start)) return null;
    +197 			if(condition(start)) return start;
    +198 		}
    +199 		return null;
    +200 	},
    +201 
    +202 	/**
    +203 	 * Walks Forward through DOM tree from start to end, and collects all nodes that matches with a filter.
    +204 	 * If no filter provided, it just collects all nodes.
    +205 	 *
    +206 	 * @param function filter a filter function
    +207 	 */
    +208 	collectNodesBetween: function(start, end, filter) {
    +209 		if(start == end) return [start, end].findAll(filter || function() {return true});
    +210 		
    +211 		var nodes = this.collectForward(start, function(node) {return node == end}, filter);
    +212 		if(
    +213 			start != end &&
    +214 			typeof filter == "function" &&
    +215 			filter(end)
    +216 		) nodes.push(end);
    +217 		
    +218 		return nodes;
    +219 	},
    +220 
    +221 	collectForward: function(start, exitCondition, filter) {
    +222 		return this.collect(start, this.walkForward, exitCondition, filter);
    +223 	},
    +224 	
    +225 	collectBackward: function(start, exitCondition, filter) {
    +226 		return this.collect(start, this.walkBackward, exitCondition, filter);
    +227 	},
    +228 	
    +229 	collectNext: function(start, exitCondition, filter) {
    +230 		return this.collect(start, this.walkNext, exitCondition, filter);
    +231 	},
    +232 	
    +233 	collectPrev: function(start, exitCondition, filter) {
    +234 		return this.collect(start, this.walkPrev, exitCondition, filter);
    +235 	},
    +236 	
    +237 	collect: function(start, next, exitCondition, filter) {
    +238 		var nodes = [start];
    +239 
    +240 		while(true) {
    +241 			start = next(start);
    +242 			if(
    +243 				(start == null) ||
    +244 				(typeof exitCondition == "function" && exitCondition(start))
    +245 			) break;
    +246 			
    +247 			nodes.push(start);
    +248 		}
    +249 
    +250 		return (typeof filter == "function") ? nodes.findAll(filter) : nodes;
    +251 	},
    +252 
    +253 
    +254 	hasBlocks: function(element) {
    +255 		var nodes = element.childNodes;
    +256 		for(var i = 0; i < nodes.length; i++) {
    +257 			if(this.isBlock(nodes[i])) return true;
    +258 		}
    +259 		return false;
    +260 	},
    +261 	
    +262 	hasMixedContents: function(element) {
    +263 		if(!this.isBlock(element)) return false;
    +264 		if(!this.isBlockContainer(element)) return false;
    +265 		
    +266 		var hasTextOrInline = false;
    +267 		var hasBlock = false;
    +268 		for(var i = 0; i < element.childNodes.length; i++) {
    +269 			var node = element.childNodes[i];
    +270 			if(!hasTextOrInline && this.isTextOrInlineNode(node)) hasTextOrInline = true;
    +271 			if(!hasBlock && this.isBlock(node)) hasBlock = true;
    +272 			
    +273 			if(hasTextOrInline && hasBlock) break;
    +274 		}
    +275 		if(!hasTextOrInline || !hasBlock) return false;
    +276 		
    +277 		return true;
    +278 	},
    +279 	
    +280 	isBlockOnlyContainer: function(element) {
    +281 		if(!element) return false;
    +282 		return this._blockOnlyContainerTags.include(typeof element == 'string' ? element : element.nodeName);
    +283 	},
    +284 	
    +285 	isTableCell: function(element) {
    +286 		if(!element) return false;
    +287 		return this._tableCellTags.include(typeof element == 'string' ? element : element.nodeName);
    +288 	},
    +289 	
    +290 	isBlockContainer: function(element) {
    +291 		if(!element) return false;
    +292 		return this._blockContainerTags.include(typeof element == 'string' ? element : element.nodeName);
    +293 	},
    +294 	
    +295 	isHeading: function(element) {
    +296 		if(!element) return false;
    +297 		return (typeof element == 'string' ? element : element.nodeName).match(/H\d/);
    +298 	},
    +299 	
    +300 	isBlock: function(element) {
    +301 		if(!element) return false;
    +302 		return this._blockTags.include(typeof element == 'string' ? element : element.nodeName);
    +303 	},
    +304 	
    +305 	isAtomic: function(element) {
    +306 		if(!element) return false;
    +307 		return this._atomicTags.include(typeof element == 'string' ? element : element.nodeName);
    +308 	},
    +309 	
    +310 	isListContainer: function(element) {
    +311 		if(!element) return false;
    +312 		return this._listContainerTags.include(typeof element == 'string' ? element : element.nodeName);
    +313 	},
    +314 	
    +315 	isTextOrInlineNode: function(node) {
    +316 		return node && (node.nodeType == 3 || !this.isBlock(node));
    +317 	}
    +318 });
    \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_04.html b/modules/editor/skins/xquared/doc/api/src_04.html new file mode 100644 index 000000000..50db4821a --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/src_04.html @@ -0,0 +1,163 @@ +
      1 /**
    +  2  * @fileOverview xq.EditHistory manages editing history and performs UNDO/REDO.
    +  3  */
    +  4 xq.EditHistory = Class.create({
    +  5     /**
    +  6 	 * Initializer
    +  7 	 *
    +  8      * @constructor
    +  9 	 * @param {xq.RichDom} rdom RichDom instance
    + 10 	 * @param {Number} [max] maximum UNDO buffer size(default value is 100).
    + 11 	 */
    + 12 	initialize: function(rdom, max) {
    + 13 		if (!rdom) throw "IllegalArgumentException";
    + 14 
    + 15 		this.disabled = false;
    + 16 		this.max = max || 100;
    + 17 		this.rdom = rdom;
    + 18 		this.root = rdom.getRoot();
    + 19 		this.clear();
    + 20 		
    + 21 		this.lastModified = Date.get();
    + 22 	},
    + 23 	getLastModifiedDate: function() {
    + 24 		return this.lastModified;
    + 25 	},
    + 26 	isUndoable: function() {
    + 27 		return this.queue.length > 0 && this.index > 0;
    + 28 	},
    + 29 	isRedoable: function() {
    + 30 		return this.queue.length > 0 && this.index < this.queue.length - 1;
    + 31 	},
    + 32 	disable: function() {
    + 33 		this.disabled = true;
    + 34 	},
    + 35 	enable: function() {
    + 36 		this.disabled = false;
    + 37 	},
    + 38 	undo: function() {
    + 39 		this.pushContent();
    + 40 		
    + 41 		if (this.isUndoable()) {
    + 42 			this.index--;
    + 43 			this.popContent();
    + 44 			return true;
    + 45 		} else {
    + 46 			return false;
    + 47 		}
    + 48 	},
    + 49 	redo: function() {
    + 50 		if (this.isRedoable()) {
    + 51 			this.index++;
    + 52 			this.popContent();
    + 53 			return true;
    + 54 		} else {
    + 55 			return false;
    + 56 		}
    + 57 	},
    + 58 	onCommand: function() {
    + 59 		this.lastModified = Date.get();
    + 60 		if(this.disabled) return false;
    + 61 
    + 62 		return this.pushContent();
    + 63 	},
    + 64 	onEvent: function(event) {
    + 65 		this.lastModified = Date.get();
    + 66 		if(this.disabled) return false;
    + 67 
    + 68 		// ignore normal keys
    + 69 		if('keydown' == event.type && !(event.ctrlKey || event.metaKey)) return false;
    + 70 		if(['keydown', 'keyup', 'keypress'].include(event.type) && !event.ctrlKey && !event.altKey && !event.metaKey && ![33,34,35,36,37,38,39,40].include(event.keyCode)) return false;
    + 71 		if(['keydown', 'keyup', 'keypress'].include(event.type) && (event.ctrlKey || event.metaKey) && [89,90].include(event.keyCode)) return false;
    + 72 		
    + 73 		// ignore ctrl/shift/alt/meta keys
    + 74 		if([16,17,18,224].include(event.keyCode)) return false;
    + 75 		
    + 76 		return this.pushContent();
    + 77 	},
    + 78 	popContent: function() {
    + 79 		this.lastModified = Date.get();
    + 80 		var entry = this.queue[this.index];
    + 81 		if (entry.caret > 0) {
    + 82 			var html=entry.html.substring(0, entry.caret) + '<span id="caret_marker_00700"></span>' + entry.html.substring(entry.caret);
    + 83 			this.root.innerHTML = html;
    + 84 		} else {
    + 85 			this.root.innerHTML = entry.html;
    + 86 		}
    + 87 		this.restoreCaret();
    + 88 	},
    + 89 	pushContent: function(ignoreCaret) {
    + 90 		if(xq.Browser.isTrident && !ignoreCaret && !this.rdom.hasFocus()) return false;
    + 91 		if(!this.rdom.getCurrentElement()) return false;
    + 92 		
    + 93 		var html = this.root.innerHTML;
    + 94 		if(html == (this.queue[this.index] ? this.queue[this.index].html : null)) return false;
    + 95 		var caret = ignoreCaret ? -1 : this.saveCaret();
    + 96 		
    + 97 		if(this.queue.length >= this.max) {
    + 98 			this.queue.shift();
    + 99 		} else {
    +100 			this.index++;
    +101 		}
    +102 		
    +103 		this.queue.splice(this.index, this.queue.length - this.index, {html:html, caret:caret});
    +104 		return true;
    +105 	},
    +106 	clear: function() {
    +107 		this.index = -1;
    +108 		this.queue = [];
    +109 		this.pushContent(true);
    +110 	},
    +111 	saveCaret: function() {
    +112 		if(this.rdom.hasSelection()) return null;
    +113 
    +114 		// FF on Mac has a caret problem with these lines. --2007/11/19
    +115 		var marker = this.rdom.pushMarker();
    +116 		var str = xq.Browser.isTrident ? '<SPAN class='+marker.className : '<span class="'+marker.className+'"';
    +117 		var caret = this.rdom.getRoot().innerHTML.indexOf(str);
    +118 		this.rdom.popMarker(true);
    +119 
    +120 		return caret;
    +121 
    +122 /*
    +123 		// This is old code. It also has same problem.
    +124 		
    +125 		if(this.rdom.hasSelection()) return null;
    +126 		
    +127 		var bookmark = this.rdom.saveSelection();
    +128 		var marker = this.rdom.pushMarker();
    +129 		
    +130 		var str = xq.Browser.isTrident ? '<SPAN class='+marker.className : '<span class="'+marker.className+'"';
    +131 		var caret = this.rdom.getRoot().innerHTML.indexOf(str);
    +132 		
    +133 		this.rdom.popMarker();
    +134 		this.rdom.restoreSelection(bookmark);
    +135 		
    +136 		return caret;
    +137 */
    +138 	},
    +139 	restoreCaret: function() {
    +140 		var marker = this.rdom.$('caret_marker_00700');
    +141 		
    +142 		if(marker) {
    +143 			this.rdom.selectElement(marker, true);
    +144 			this.rdom.collapseSelection(false);
    +145 			this.rdom.deleteNode(marker);
    +146 		} else {
    +147 			var node = this.rdom.tree.findForward(this.rdom.getRoot(), function(node) {
    +148 				return this.isBlock(node) && !this.hasBlocks(node);
    +149 			}.bind(this.rdom.tree));
    +150 			this.rdom.selectElement(node, false);
    +151 			this.rdom.collapseSelection(false);
    +152 			
    +153 		}
    +154 	}
    +155 });
    +156 
    \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_05.html b/modules/editor/skins/xquared/doc/api/src_05.html new file mode 100644 index 000000000..c8bbff96a --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/src_05.html @@ -0,0 +1,2216 @@ +
      1 /**
    +  2  * @fileOverview xq.Editor manages configurations such as autocompletion and autocorrection, edit mode/normal mode switching, handles editing commands, keyboard shortcuts and other events.
    +  3  */
    +  4 xq.Editor = Class.create({
    +  5 	/**
    +  6 	 * Initialize editor but it doesn't automatically start designMode. setEditMode should be called after initialization.
    +  7 	 *
    +  8      * @constructor
    +  9 	 * @param {Element} contentElement HTML element(TEXTAREA or normal block element such as DIV) to be replaced with editable area
    + 10 	 * @param {Element} toolbarContainer HTML element which contains toolbar icons
    + 11 	 */
    + 12 	initialize: function(contentElement, toolbarContainer) {
    + 13 		if(!contentElement) throw "[contentElement] is null";
    + 14 		if(contentElement.nodeType != 1) throw "[contentElement] is not an element";
    + 15 		
    + 16 		xq.asEventSource(this, "Editor", ["ElementChanged", "BeforeEvent", "AfterEvent", "CurrentContentChanged", "StaticContentChanged", "CurrentEditModeChanged"]);
    + 17 		
    + 18 		/**
    + 19 		 * Editor's configuration
    + 20 		 * @type object
    + 21 		 */
    + 22 		this.config = {};
    + 23 		this.config.enableLinkClick = false;
    + 24 		this.config.changeCursorOnLink = false;
    + 25 		this.config.generateDefaultToolbar = true;
    + 26 		this.config.defaultToolbarButtonMap = [
    + 27 			[
    + 28 				{className:"foregroundColor", title:"Foreground color", handler:"xed.handleForegroundColor()"},
    + 29 				{className:"backgroundColor", title:"Background color", handler:"xed.handleBackgroundColor()"}
    + 30 			],
    + 31 			[
    + 32 				{className:"link", title:"Link", handler:"xed.handleLink()"},
    + 33 				{className:"strongEmphasis", title:"Strong emphasis", handler:"xed.handleStrongEmphasis()"},
    + 34 				{className:"emphasis", title:"Emphasis", handler:"xed.handleEmphasis()"},
    + 35 				{className:"underline", title:"Underline", handler:"xed.handleUnderline()"},
    + 36 				{className:"strike", title:"Strike", handler:"xed.handleStrike()"},
    + 37 				{className:"superscription", title:"Superscription", handler:"xed.handleSuperscription()"},
    + 38 				{className:"subscription", title:"Subscription", handler:"xed.handleSubscription()"}
    + 39 			],
    + 40 			[
    + 41 				{className:"removeFormat", title:"Remove format", handler:"xed.handleRemoveFormat()"}
    + 42 			],
    + 43 			[
    + 44 				{className:"justifyLeft", title:"Justify left", handler:"xed.handleJustify('left')"},
    + 45 				{className:"justifyCenter", title:"Justify center", handler:"xed.handleJustify('center')"},
    + 46 				{className:"justifyRight", title:"Justify right", handler:"xed.handleJustify('right')"},
    + 47 				{className:"justifyBoth", title:"Justify both", handler:"xed.handleJustify('both')"}
    + 48 			],
    + 49 			[
    + 50 				{className:"indent", title:"Indent", handler:"xed.handleIndent()"},
    + 51 				{className:"outdent", title:"Outdent", handler:"xed.handleOutdent()"}
    + 52 			],
    + 53 			[
    + 54 				{className:"unorderedList", title:"Unordered list", handler:"xed.handleList('UL')"},
    + 55 				{className:"orderedList", title:"Ordered list", handler:"xed.handleList('OL')"}
    + 56 			],
    + 57 			[
    + 58 				{className:"paragraph", title:"Paragraph", handler:"xed.handleApplyBlock('P')"},
    + 59 				{className:"heading1", title:"Heading 1", handler:"xed.handleApplyBlock('H1')"},
    + 60 				{className:"blockquote", title:"Blockquote", handler:"xed.handleApplyBlock('BLOCKQUOTE')"},
    + 61 				{className:"code", title:"Code", handler:"xed.handleList('CODE')"},
    + 62 				{className:"division", title:"Division", handler:"xed.handleApplyBlock('DIV')"}
    + 63 			],
    + 64 			[
    + 65 				{className:"table", title:"Table", handler:"xed.handleTable(3,3,'tl')"},
    + 66 				{className:"separator", title:"Separator", handler:"xed.handleSeparator()"}
    + 67 			],
    + 68 			[
    + 69 				{className:"html", title:"Edit source", handler:"xed.toggleSourceAndWysiwygMode()"}
    + 70 			],
    + 71 			[
    + 72 				{className:"undo", title:"Undo", handler:"xed.handleUndo()"},
    + 73 				{className:"redo", title:"Redo", handler:"xed.handleRedo()"}
    + 74 			]
    + 75 		];
    + 76 		
    + 77 		this.config.imagePathForDefaultToobar = 'img/toolbar/';
    + 78 		
    + 79 		// relative | host_relative | absolute | browser_default
    + 80 		this.config.urlValidationMode = 'absolute';
    + 81 		
    + 82 		this.config.automaticallyHookSubmitEvent = true;
    + 83 		
    + 84 		this.config.allowedTags = ['a', 'abbr', 'acronym', 'address', 'blockquote', 'br', 'caption', 'cite', 'code', 'dd', 'dfn', 'div', 'dl', 'dt', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'img', 'kbd', 'li', 'ol', 'p', 'pre', 'q', 'samp', 'span', 'sup', 'sub', 'strong', 'table', 'thead', 'tbody', 'td', 'th', 'tr', 'ul', 'var'];
    + 85 		this.config.allowedAttributes = ['alt', 'cite', 'class', 'datetime', 'height', 'href', 'id', 'rel', 'rev', 'src', 'style', 'title', 'width'];
    + 86 		
    + 87 		this.config.shortcuts = {};
    + 88 		this.config.autocorrections = {};
    + 89 		this.config.autocompletions = {};
    + 90 		this.config.templateProcessors = {};
    + 91 		this.config.contextMenuHandlers = {};
    + 92 		
    + 93 		/**
    + 94 		 * Original content element
    + 95 		 * @type Element
    + 96 		 */
    + 97 		this.contentElement = contentElement;
    + 98 		
    + 99 		/**
    +100 		 * Owner document of content element
    +101 		 * @type Document
    +102 		 */
    +103 		this.doc = this.contentElement.ownerDocument;
    +104 		
    +105 		/**
    +106 		 * Body of content element
    +107 		 * @type Element
    +108 		 */
    +109 		this.body = this.doc.body;
    +110 		
    +111 		/**
    +112 		 * False or 'readonly' means read-only mode, true or 'wysiwyg' means WYSIWYG editing mode, and 'source' means source editing mode.
    +113 		 * @type Object
    +114 		 */
    +115 		this.currentEditMode = 'readonly';
    +116 		
    +117 		/**
    +118 		 * RichDom instance
    +119 		 * @type xq.RichDom
    +120 		 */
    +121 		this.rdom = xq.RichDom.createInstance();
    +122 		
    +123 		/**
    +124 		 * Validator instance
    +125 		 * @type xq.Validator
    +126 		 */
    +127 		this.validator = null;
    +128 		
    +129 		/**
    +130 		 * Outmost wrapper div
    +131 		 * @type Element
    +132 		 */
    +133 		this.outmostWrapper = null;
    +134 		
    +135 		/**
    +136 		 * Source editor container
    +137 		 * @type Element
    +138 		 */
    +139 		this.sourceEditorDiv = null;
    +140 		
    +141 		/**
    +142 		 * Source editor textarea
    +143 		 * @type Element
    +144 		 */
    +145 		this.sourceEditorTextarea = null;
    +146 		
    +147 		/**
    +148 		 * WYSIWYG editor container
    +149 		 * @type Element
    +150 		 */
    +151 		this.wysiwygEditorDiv = null;
    +152 		
    +153 		/**
    +154 		 * Design mode iframe
    +155 		 * @type IFrame
    +156 		 */
    +157 		this.editorFrame = null;
    +158 		
    +159 		/**
    +160 		 * Window that contains design mode iframe
    +161 		 * @type Window
    +162 		 */
    +163 		this.editorWin = null;
    +164 		
    +165 		/**
    +166 		 * Document that contained by design mode iframe
    +167 		 * @type Document
    +168 		 */
    +169 		this.editorDoc = null;
    +170 		
    +171 		/**
    +172 		 * Body that contained by design mode iframe
    +173 		 * @type Element
    +174 		 */
    +175 		this.editorBody = null;
    +176 		
    +177 		/**
    +178 		 * Toolbar container
    +179 		 * @type Element
    +180 		 */
    +181 		this.toolbarContainer = toolbarContainer;
    +182 		
    +183 		/**
    +184 		 * Toolbar buttons
    +185 		 * @type Array
    +186 		 */
    +187 		this.toolbarButtons = null;
    +188 		
    +189 		/**
    +190 		 * Undo/redo manager
    +191 		 * @type xq.EditHistory
    +192 		 */
    +193 		this.editHistory = null;
    +194 		
    +195 		this._contextMenuContainer = null;
    +196 		this._contextMenuItems = null;
    +197 		
    +198 		this._validContentCache = null;
    +199 		this._lastModified = null;
    +200 		
    +201 		this.addShortcuts(this._getDefaultShortcuts());
    +202 		this.addTemplateProcessors(this._getDefaultTemplateProcessors());
    +203 		
    +204 		this.addListener({
    +205 			onEditorCurrentContentChanged: function(xed) {
    +206 				var curFocusElement = xed.rdom.getCurrentElement();
    +207 				if(!curFocusElement) return;
    +208 				
    +209 				if(xed._lastFocusElement != curFocusElement) {
    +210 					if(!xed.rdom.tree.isBlockOnlyContainer(xed._lastFocusElement) && xed.rdom.tree.isBlock(xed._lastFocusElement)) {
    +211 						xed.rdom.removeTrailingWhitespace(xed._lastFocusElement);
    +212 					}
    +213 					xed._fireOnElementChanged(xed._lastFocusElement, curFocusElement);
    +214 					xed._lastFocusElement = curFocusElement;
    +215 				}
    +216 
    +217 				xed.updateAllToolbarButtonsStatus(curFocusElement);
    +218 			}
    +219 		});
    +220 	},
    +221 	
    +222 	
    +223 	
    +224 	/////////////////////////////////////////////
    +225 	// Configuration Management
    +226 	
    +227 	_getDefaultShortcuts: function() {
    +228 		if(xq.Browser.isMac) {
    +229 			// Mac FF & Safari
    +230 			return [
    +231 				{event:"Ctrl+Shift+SPACE", handler:"this.handleAutocompletion(); stop = true;"},
    +232 				{event:"ENTER", handler:"this.handleEnter(false, false)"},
    +233 				{event:"Ctrl+ENTER", handler:"this.handleEnter(true, false)"},
    +234 				{event:"Ctrl+Shift+ENTER", handler:"this.handleEnter(true, true)"},
    +235 				{event:"TAB", handler:"this.handleTab()"},
    +236 				{event:"Shift+TAB", handler:"this.handleShiftTab()"},
    +237 				{event:"DELETE", handler:"this.handleDelete()"},
    +238 				{event:"BACKSPACE", handler:"this.handleBackspace()"},
    +239 				
    +240 				{event:"Ctrl+B", handler:"this.handleStrongEmphasis()"},
    +241 				{event:"Ctrl+I", handler:"this.handleEmphasis()"},
    +242 				{event:"Ctrl+U", handler:"this.handleUnderline()"},
    +243 				{event:"Ctrl+K", handler:"this.handleStrike()"},
    +244 				{event:"Meta+Z", handler:"this.handleUndo()"},
    +245 				{event:"Meta+Shift+Z", handler:"this.handleRedo()"},
    +246 				{event:"Meta+Y", handler:"this.handleRedo()"}
    +247 			];
    +248 		} else if(xq.Browser.isUbuntu) {
    +249 			//  Ubunto FF
    +250 			return [
    +251 				{event:"Ctrl+SPACE", handler:"this.handleAutocompletion(); stop = true;"},
    +252 				{event:"ENTER", handler:"this.handleEnter(false, false)"},
    +253 				{event:"Ctrl+ENTER", handler:"this.handleEnter(true, false)"},
    +254 				{event:"Ctrl+Shift+ENTER", handler:"this.handleEnter(true, true)"},
    +255 				{event:"TAB", handler:"this.handleTab()"},
    +256 				{event:"Shift+TAB", handler:"this.handleShiftTab()"},
    +257 				{event:"DELETE", handler:"this.handleDelete()"},
    +258 				{event:"BACKSPACE", handler:"this.handleBackspace()"},
    +259 			
    +260 				{event:"Ctrl+B", handler:"this.handleStrongEmphasis()"},
    +261 				{event:"Ctrl+I", handler:"this.handleEmphasis()"},
    +262 				{event:"Ctrl+U", handler:"this.handleUnderline()"},
    +263 				{event:"Ctrl+K", handler:"this.handleStrike()"},
    +264 				{event:"Ctrl+Z", handler:"this.handleUndo()"},
    +265 				{event:"Ctrl+Y", handler:"this.handleRedo()"}
    +266 			];
    +267 		} else {
    +268 			// Win IE & FF
    +269 			return [
    +270 				{event:"Ctrl+SPACE", handler:"this.handleAutocompletion(); stop = true;"},
    +271 				{event:"ENTER", handler:"this.handleEnter(false, false)"},
    +272 				{event:"Ctrl+ENTER", handler:"this.handleEnter(true, false)"},
    +273 				{event:"Ctrl+Shift+ENTER", handler:"this.handleEnter(true, true)"},
    +274 				{event:"TAB", handler:"this.handleTab()"},
    +275 				{event:"Shift+TAB", handler:"this.handleShiftTab()"},
    +276 				{event:"DELETE", handler:"this.handleDelete()"},
    +277 				{event:"BACKSPACE", handler:"this.handleBackspace()"},
    +278 			
    +279 				{event:"Ctrl+B", handler:"this.handleStrongEmphasis()"},
    +280 				{event:"Ctrl+I", handler:"this.handleEmphasis()"},
    +281 				{event:"Ctrl+U", handler:"this.handleUnderline()"},
    +282 				{event:"Ctrl+K", handler:"this.handleStrike()"},
    +283 				{event:"Ctrl+Z", handler:"this.handleUndo()"},
    +284 				{event:"Ctrl+Y", handler:"this.handleRedo()"}
    +285 			];
    +286 		}
    +287 	},
    +288 	
    +289 	_getDefaultTemplateProcessors: function() {
    +290 		return [
    +291 			{
    +292 				id:"predefinedKeywordProcessor",
    +293 				handler:function(html) {
    +294 					var today = Date.get();
    +295 					var keywords = {
    +296 						year: today.getFullYear(),
    +297 						month: today.getMonth() + 1,
    +298 						date: today.getDate(),
    +299 						hour: today.getHours(),
    +300 						min: today.getMinutes(),
    +301 						sec: today.getSeconds()
    +302 					};
    +303 					
    +304 					return html.replace(/\{xq:(year|month|date|hour|min|sec)\}/img, function(text, keyword) {
    +305 						return keywords[keyword] || keyword;
    +306 					});
    +307 				}
    +308 			}
    +309 		];
    +310 	},
    +311 	
    +312 	/**
    +313 	 * Adds or replaces keyboard shortcut.
    +314 	 *
    +315 	 * @param {String} shortcut keymap expression like "CTRL+Space"
    +316 	 * @param {Object} handler string or function to be evaluated or called
    +317 	 */
    +318 	addShortcut: function(shortcut, handler) {
    +319 		this.config.shortcuts[shortcut] = {"event":new xq.Shortcut(shortcut), "handler":handler};
    +320 	},
    +321 	
    +322 	/**
    +323 	 * Adds several keyboard shortcuts at once.
    +324 	 *
    +325 	 * @param {Array} list of shortcuts. each element should have following structure: {event:"keymap expression", handler:handler}
    +326 	 */
    +327 	addShortcuts: function(list) {
    +328 		list.each(function(shortcut) {
    +329 			this.addShortcut(shortcut.event, shortcut.handler);
    +330 		}.bind(this));
    +331 	},
    +332 
    +333 	/**
    +334 	 * Returns keyboard shortcut matches with given keymap expression.
    +335 	 *
    +336 	 * @param {String} shortcut keymap expression like "CTRL+Space"
    +337 	 */
    +338 	getShortcut: function(shortcut) {return this.config.shortcuts[shortcut];},
    +339 
    +340 	/**
    +341 	 * Returns entire keyboard shortcuts' map
    +342 	 */
    +343 	getShortcuts: function() {return this.config.shortcuts;},
    +344 	
    +345 	/**
    +346 	 * Remove keyboard shortcut matches with given keymap expression.
    +347 	 *
    +348 	 * @param {String} shortcut keymap expression like "CTRL+Space"
    +349 	 */
    +350 	removeShortcut: function(shortcut) {delete this.config.shortcuts[shortcut];},
    +351 	
    +352 	/**
    +353 	 * Adds or replaces autocorrection handler.
    +354 	 *
    +355 	 * @param {String} id unique identifier
    +356 	 * @param {Object} criteria regex pattern or function to be used as a criterion for match
    +357 	 * @param {Object} handler string or function to be evaluated or called when criteria met
    +358 	 */
    +359 	addAutocorrection: function(id, criteria, handler) {
    +360 		if(criteria.exec) {
    +361 			var pattern = criteria;
    +362 			criteria = function(text) {return text.match(pattern)};
    +363 		}
    +364 		this.config.autocorrections[id] = {"criteria":criteria, "handler":handler};
    +365 	},
    +366 	
    +367 	/**
    +368 	 * Adds several autocorrection handlers at once.
    +369 	 *
    +370 	 * @param {Array} list of autocorrection. each element should have following structure: {id:"identifier", criteria:criteria, handler:handler}
    +371 	 */
    +372 	addAutocorrections: function(list) {
    +373 		list.each(function(ac) {
    +374 			this.addAutocorrection(ac.id, ac.criteria, ac.handler);
    +375 		}.bind(this));
    +376 	},
    +377 	
    +378 	/**
    +379 	 * Returns autocorrection handler matches with given id
    +380 	 *
    +381 	 * @param {String} id unique identifier
    +382 	 */
    +383 	getAutocorrection: function(id) {return this.config.autocorrection[id];},
    +384 	
    +385 	/**
    +386 	 * Returns entire autocorrections' map
    +387 	 */
    +388 	getAutocorrections: function() {return this.config.autocorrections;},
    +389 	
    +390 	/**
    +391 	 * Removes autocorrection handler matches with given id
    +392 	 *
    +393 	 * @param {String} id unique identifier
    +394 	 */
    +395 	removeAutocorrection: function(id) {delete this.config.autocorrections[id];},
    +396 	
    +397 	/**
    +398 	 * Adds or replaces autocompletion handler.
    +399 	 *
    +400 	 * @param {String} id unique identifier
    +401 	 * @param {Object} criteria regex pattern or function to be used as a criterion for match
    +402 	 * @param {Object} handler string or function to be evaluated or called when criteria met
    +403 	 */
    +404 	addAutocompletion: function(id, criteria, handler) {
    +405 		if(criteria.exec) {
    +406 			var pattern = criteria;
    +407 			criteria = function(text) {
    +408 				var m = pattern.exec(text);
    +409 				return m ? m.index : -1;
    +410 			};
    +411 		}
    +412 		this.config.autocompletions[id] = {"criteria":criteria, "handler":handler};
    +413 	},
    +414 	
    +415 	/**
    +416 	 * Adds several autocompletion handlers at once.
    +417 	 *
    +418 	 * @param {Array} list of autocompletion. each element should have following structure: {id:"identifier", criteria:criteria, handler:handler}
    +419 	 */
    +420 	addAutocompletions: function(list) {
    +421 		list.each(function(ac) {
    +422 			this.addAutocompletion(ac.id, ac.criteria, ac.handler);
    +423 		}.bind(this));
    +424 	},
    +425 	
    +426 	/**
    +427 	 * Returns autocompletion handler matches with given id
    +428 	 *
    +429 	 * @param {String} id unique identifier
    +430 	 */
    +431 	getAutocompletion: function(id) {return this.config.autocompletions[id];},
    +432 	
    +433 	/**
    +434 	 * Returns entire autocompletions' map
    +435 	 */
    +436 	getAutocompletions: function() {return this.config.autocompletions;},
    +437 	
    +438 	/**
    +439 	 * Removes autocompletion handler matches with given id
    +440 	 *
    +441 	 * @param {String} id unique identifier
    +442 	 */
    +443 	removeAutocompletion: function(id) {delete this.config.autocompletions[id];},
    +444 	
    +445 	/**
    +446 	 * Adds or replaces template processor.
    +447 	 *
    +448 	 * @param {String} id unique identifier
    +449 	 * @param {Object} handler string or function to be evaluated or called when template inserted
    +450 	 */
    +451 	addTemplateProcessor: function(id, handler) {
    +452 		this.config.templateProcessors[id] = {"handler":handler};
    +453 	},
    +454 	
    +455 	/**
    +456 	 * Adds several template processors at once.
    +457 	 *
    +458 	 * @param {Array} list of template processors. Each element should have following structure: {id:"identifier", handler:handler}
    +459 	 */
    +460 	addTemplateProcessors: function(list) {
    +461 		list.each(function(tp) {
    +462 			this.addTemplateProcessor(tp.id, tp.handler);
    +463 		}.bind(this));
    +464 	},
    +465 	
    +466 	/**
    +467 	 * Returns template processor matches with given id
    +468 	 *
    +469 	 * @param {String} id unique identifier
    +470 	 */
    +471 	getTemplateProcessor: function(id) {return this.config.templateProcessors[id];},
    +472 
    +473 	/**
    +474 	 * Returns entire template processors' map
    +475 	 */
    +476 	getTemplateProcessors: function() {return this.config.templateProcessors;},
    +477 
    +478 	/**
    +479 	 * Removes template processor matches with given id
    +480 	 *
    +481 	 * @param {String} id unique identifier
    +482 	 */
    +483 	removeTemplateProcessor: function(id) {delete this.config.templateProcessors[id];},
    +484 
    +485 
    +486 
    +487 	/**
    +488 	 * Adds or replaces context menu handler.
    +489 	 *
    +490 	 * @param {String} id unique identifier
    +491 	 * @param {Object} handler string or function to be evaluated or called when onContextMenu occured
    +492 	 */
    +493 	addContextMenuHandler: function(id, handler) {
    +494 		this.config.contextMenuHandlers[id] = {"handler":handler};
    +495 	},
    +496 	
    +497 	/**
    +498 	 * Adds several context menu handlers at once.
    +499 	 *
    +500 	 * @param {Array} list of handlers. Each element should have following structure: {id:"identifier", handler:handler}
    +501 	 */
    +502 	addContextMenuHandlers: function(list) {
    +503 		list.each(function(mh) {
    +504 			this.addContextMenuHandler(mh.id, mh.handler);
    +505 		}.bind(this));
    +506 	},
    +507 	
    +508 	/**
    +509 	 * Returns context menu handler matches with given id
    +510 	 *
    +511 	 * @param {String} id unique identifier
    +512 	 */
    +513 	getContextMenuHandler: function(id) {return this.config.contextMenuHandlers[id];},
    +514 
    +515 	/**
    +516 	 * Returns entire context menu handlers' map
    +517 	 */
    +518 	getContextMenuHandlers: function() {return this.config.contextMenuHandlers;},
    +519 
    +520 	/**
    +521 	 * Removes context menu handler matches with given id
    +522 	 *
    +523 	 * @param {String} id unique identifier
    +524 	 */
    +525 	removeContextMenuHandler: function(id) {delete this.config.contextMenuHandlers[id];},
    +526 	
    +527 	
    +528 	
    +529 	/////////////////////////////////////////////
    +530 	// Edit mode management
    +531 	
    +532 	/**
    +533 	 * Returns current edit mode - readonly, wysiwyg, source
    +534 	 */
    +535 	getCurrentEditMode: function() {
    +536 		return this.currentEditMode;
    +537 	},
    +538 	
    +539 	toggleSourceAndWysiwygMode: function() {
    +540 		var mode = this.getCurrentEditMode();
    +541 		if(mode == 'readonly') return;
    +542 		this.setEditMode(mode == 'wysiwyg' ? 'source' : 'wysiwyg');
    +543 		
    +544 		return true;
    +545 	},
    +546 	
    +547 	/**
    +548 	 * Switches between edit-mode/normal mode.
    +549 	 *
    +550 	 * @param {Object} mode false or 'readonly' means read-only mode, true or 'wysiwyg' means WYSIWYG editing mode, and 'source' means source editing mode.
    +551 	 */
    +552 	setEditMode: function(mode) {
    +553 		if(this.currentEditMode == mode) return;
    +554 		
    +555 		var firstCall = mode != false && mode != 'readonly' && !this.outmostWrapper;
    +556 		if(firstCall) {
    +557 			// Create editor element if needed
    +558 			this._createEditorFrame();
    +559 			this._registerEventHandlers();
    +560 			
    +561 			this.loadCurrentContentFromStaticContent();
    +562 			this.editHistory = new xq.EditHistory(this.rdom);
    +563 		}
    +564 		
    +565 		if(mode == 'wysiwyg') {
    +566 			// Update contents
    +567 			if(this.currentEditMode == 'source') this.setStaticContent(this.getSourceContent());
    +568 			this.loadCurrentContentFromStaticContent();
    +569 			
    +570 			// Make static content invisible
    +571 			this.contentElement.style.display = "none";
    +572 			
    +573 			// Make WYSIWYG editor visible
    +574 			this.sourceEditorDiv.style.display = "none";
    +575 			this.wysiwygEditorDiv.style.display = "block";
    +576 			this.outmostWrapper.style.display = "block";
    +577 			
    +578 			this.currentEditMode = mode;
    +579 			
    +580 			if(!xq.Browser.isTrident) {
    +581 				window.setTimeout(function() {
    +582 					if(this.getDoc().designMode == 'On') return;
    +583 					
    +584 					// Without it, Firefox doesn't display embedded SWF
    +585 					this.getDoc().designMode = 'On';
    +586 					
    +587 					// turn off Firefox's table editing feature
    +588 					try {this.getDoc().execCommand("enableInlineTableEditing", false, "false")} catch(ignored) {}
    +589 				}.bind(this), 0);
    +590 			}
    +591 			
    +592 			this.enableToolbarButtons();
    +593 			if(!firstCall) this.focus();
    +594 		} else if(mode == 'source') {
    +595 			// Update contents
    +596 			if(this.currentEditMode == 'wysiwyg') this.setStaticContent(this.getWysiwygContent());
    +597 			this.loadCurrentContentFromStaticContent();
    +598 			
    +599 			// Make static content invisible
    +600 			this.contentElement.style.display = "none";
    +601 			
    +602 			// Make source editor visible
    +603 			this.sourceEditorDiv.style.display = "block";
    +604 			this.wysiwygEditorDiv.style.display = "none";
    +605 			this.outmostWrapper.style.display = "block";
    +606 			
    +607 			this.currentEditMode = mode;
    +608 
    +609 			this.disableToolbarButtons(['html']);
    +610 			if(!firstCall) this.focus();
    +611 		} else {
    +612 			// Update contents
    +613 			this.setStaticContent(this.getCurrentContent());
    +614 			this.loadCurrentContentFromStaticContent();
    +615 
    +616 			// Make editor and toolbar invisible
    +617 			this.outmostWrapper.style.display = "none";
    +618 			
    +619 			// Make static content visible
    +620 			this.contentElement.style.display = "block";
    +621 			
    +622 			this.currentEditMode = mode;
    +623 		}
    +624 		
    +625 		this._fireOnCurrentEditModeChanged(this, mode);
    +626 	},
    +627 	
    +628 	/**
    +629 	 * Load CSS into editing-mode document
    +630 	 *
    +631 	 * @param {string} path URL
    +632 	 */
    +633 	loadStylesheet: function(path) {
    +634 		var head = this.editorDoc.getElementsByTagName("HEAD")[0];
    +635 		var link = this.editorDoc.createElement("LINK");
    +636 		link.rel = "Stylesheet";
    +637 		link.type = "text/css";
    +638 		link.href = path;
    +639 		head.appendChild(link);
    +640 	},
    +641 	
    +642 	/**
    +643 	 * Sets editor's dynamic content from static content
    +644 	 */
    +645 	loadCurrentContentFromStaticContent: function() {
    +646 		// update WYSIWYG editor
    +647 		var html = this.validator.invalidate(this.getStaticContentAsDOM());
    +648 		html = this.removeUnnecessarySpaces(html);
    +649 		
    +650 		if(html.blank()) {
    +651 			this.rdom.clearRoot();
    +652 		} else {
    +653 			this.rdom.getRoot().innerHTML = html;
    +654 		}
    +655 		this.rdom.wrapAllInlineOrTextNodesAs("P", this.rdom.getRoot(), true);
    +656 		
    +657 		// update source editor
    +658 		var source = this.getWysiwygContent(true, true);
    +659 		
    +660 		this.sourceEditorTextarea.value = source;
    +661 		if(xq.Browser.isWebkit) {
    +662 			this.sourceEditorTextarea.innerHTML = source;
    +663 		}
    +664 		
    +665 		this._fireOnCurrentContentChanged(this);
    +666 	},
    +667 	
    +668 	/**
    +669 	 * Enables all toolbar buttons
    +670 	 *
    +671 	 * @param {Array} [exceptions] array of string containing classnames to exclude
    +672 	 */
    +673 	enableToolbarButtons: function(exceptions) {
    +674 		if(!this.toolbarContainer) return;
    +675 		
    +676 		this._execForAllToolbarButtons(exceptions, function(li, exception) {
    +677 			li.firstChild.className = !exception ? '' : 'disabled';
    +678 		});
    +679 		
    +680 		// Toolbar image icon disappears without following code:
    +681 		if(xq.Browser.isIE6) {
    +682 			this.toolbarContainer.style.display = 'none';
    +683 			setTimeout(function() {this.toolbarContainer.style.display = 'block';}.bind(this), 0);
    +684 		}
    +685 	},
    +686 	
    +687 	/**
    +688 	 * Disables all toolbar buttons
    +689 	 *
    +690 	 * @param {Array} [exceptions] array of string containing classnames to exclude
    +691 	 */
    +692 	disableToolbarButtons: function(exceptions) {
    +693 		this._execForAllToolbarButtons(exceptions, function(li, exception) {
    +694 			li.firstChild.className = exception ? '' : 'disabled';
    +695 		});
    +696 	},
    +697 	
    +698 	_execForAllToolbarButtons: function(exceptions, exec) {
    +699 		if(!this.toolbarContainer) return;
    +700 		exceptions = exceptions || [];
    +701 		
    +702 		$(this.toolbarContainer).select('li').each(function(li) {
    +703 			var buttonsClassName = li.classNames().find(function(name) {return name != 'xq_separator'});
    +704 			var exception = exceptions.include(buttonsClassName);
    +705 			exec(li, exception);
    +706 		});
    +707 	},
    +708 
    +709 	_updateToolbarButtonStatus: function(buttonClassName, selected) {
    +710 		var button = this.toolbarButtons.get(buttonClassName);
    +711 		if(button) button.firstChild.firstChild.className = selected ? 'selected' : '';
    +712 	},
    +713 	
    +714 	updateAllToolbarButtonsStatus: function(element) {
    +715 		if(!this.toolbarContainer) return;
    +716 		if(!this.toolbarButtons) {
    +717 			var classNames = [
    +718 				"emphasis", "strongEmphasis", "underline", "strike", "superscription", "subscription",
    +719 				"justifyLeft", "justifyCenter", "justifyRight", "justifyBoth",
    +720 				"unorderedList", "orderedList", "code",
    +721 				"paragraph", "heading1", "heading2", "heading3", "heading4", "heading5", "heading6"
    +722 			];
    +723 			
    +724 			this.toolbarButtons = $H({});
    +725 			
    +726 			classNames.each(function(className) {
    +727 				var found = $(this.toolbarContainer).getElementsBySelector("." + className);
    +728 				var button = found && found.length > 0 ? found[0] : null;
    +729 				if(button) this.toolbarButtons.set(className, button);
    +730 			}.bind(this));
    +731 		}
    +732 		
    +733 		var buttons = this.toolbarButtons;
    +734 		
    +735 		var info = this.rdom.collectStructureAndStyle(element);
    +736 		
    +737 		this._updateToolbarButtonStatus('emphasis', info.em);
    +738 		this._updateToolbarButtonStatus('strongEmphasis', info.strong);
    +739 		this._updateToolbarButtonStatus('underline', info.underline);
    +740 		this._updateToolbarButtonStatus('strike', info.strike);
    +741 		this._updateToolbarButtonStatus('superscription', info.superscription);
    +742 		this._updateToolbarButtonStatus('subscription', info.subscription);
    +743 		
    +744 		this._updateToolbarButtonStatus('justifyLeft', info.justification == 'left');
    +745 		this._updateToolbarButtonStatus('justifyCenter', info.justification == 'center');
    +746 		this._updateToolbarButtonStatus('justifyRight', info.justification == 'right');
    +747 		this._updateToolbarButtonStatus('justifyBoth', info.justification == 'justify');
    +748 		
    +749 		this._updateToolbarButtonStatus('orderedList', info.list == 'OL');
    +750 		this._updateToolbarButtonStatus('unorderedList', info.list == 'UL');
    +751 		this._updateToolbarButtonStatus('code', info.list == 'CODE');
    +752 		
    +753 		this._updateToolbarButtonStatus('paragraph', info.block == 'P');
    +754 		this._updateToolbarButtonStatus('heading1', info.block == 'H1');
    +755 		this._updateToolbarButtonStatus('heading2', info.block == 'H2');
    +756 		this._updateToolbarButtonStatus('heading3', info.block == 'H3');
    +757 		this._updateToolbarButtonStatus('heading4', info.block == 'H4');
    +758 		this._updateToolbarButtonStatus('heading5', info.block == 'H5');
    +759 		this._updateToolbarButtonStatus('heading6', info.block == 'H6');
    +760 	},
    +761 	
    +762 	removeUnnecessarySpaces: function(html) {
    +763 		var blocks = this.rdom.tree.getBlockTags().join("|");
    +764 		var regex = new RegExp("\\s*<(/?)(" + blocks + ")>\\s*", "img");
    +765 		return html.replace(regex, '<$1$2>');
    +766 	},
    +767 	
    +768 	/**
    +769 	 * Gets editor's dynamic content from current editor(source or WYSIWYG)
    +770 	 * 
    +771 	 * @return {Object} HTML String
    +772 	 */
    +773 	getCurrentContent: function(performFullValidation) {
    +774 		if(this.getCurrentEditMode() == 'source') {
    +775 			return this.getSourceContent(performFullValidation);
    +776 		} else {
    +777 			return this.getWysiwygContent(performFullValidation);
    +778 		}
    +779 	},
    +780 	
    +781 	/**
    +782 	 * Gets editor's dynamic content from WYSIWYG editor
    +783 	 * 
    +784 	 * @return {Object} HTML String
    +785 	 */
    +786 	getWysiwygContent: function(performFullValidation, dontUseCache) {
    +787 		if(dontUseCache || !performFullValidation) return this.validator.validate(this.rdom.getRoot(), performFullValidation);
    +788 		
    +789 		var lastModified = this.editHistory.getLastModifiedDate();
    +790 		if(this._lastModified != lastModified) {
    +791 			this._validContentCache = this.validator.validate(this.rdom.getRoot(), performFullValidation);
    +792 			this._lastModified = lastModified;
    +793 		}
    +794 		return this._validContentCache;
    +795 	},
    +796 	
    +797 	/**
    +798 	 * Gets editor's dynamic content from source editor
    +799 	 * 
    +800 	 * @return {Object} HTML String
    +801 	 */
    +802 	getSourceContent: function(performFullValidation) {
    +803 		var raw = this.sourceEditorTextarea[xq.Browser.isWebkit ? 'innerHTML' : 'value'];
    +804 		var tempDiv = document.createElement('div');
    +805 		tempDiv.innerHTML = this.removeUnnecessarySpaces(raw);
    +806 
    +807 		var rdom = xq.RichDom.createInstance();
    +808 		rdom.setRoot(document.body);
    +809 		rdom.wrapAllInlineOrTextNodesAs("P", tempDiv, true);
    +810 		
    +811 		return this.validator.validate(tempDiv, performFullValidation);
    +812 	},
    +813 	
    +814 	/**
    +815 	 * Sets editor's original content
    +816 	 *
    +817 	 * @param {Object} content HTML String
    +818 	 */
    +819 	setStaticContent: function(content) {
    +820 		if(this.contentElement.nodeName == 'TEXTAREA') {
    +821 			this.contentElement.value = content;
    +822 			if(xq.Browser.isWebkit) {
    +823 				this.contentElement.innerHTML = content;
    +824 			}
    +825 		} else {
    +826 			this.contentElement.innerHTML = content;
    +827 		}
    +828 		this._fireOnStaticContentChanged(this, content);
    +829 	},
    +830 	
    +831 	/**
    +832 	 * Gets editor's original content
    +833 	 *
    +834 	 * @return {Object} HTML String
    +835 	 */
    +836 	getStaticContent: function() {
    +837 		var content;
    +838 		if(this.contentElement.nodeName == 'TEXTAREA') {
    +839 			content = this.contentElement[xq.Browser.isWebkit ? 'innerHTML' : 'value'];
    +840 		} else {
    +841 			content = this.contentElement.innerHTML;
    +842 		}
    +843 		return content;
    +844 	},
    +845 	
    +846 	/**
    +847 	 * Gets editor's original content as DOM node
    +848 	 *
    +849 	 * @return {Object} HTML String
    +850 	 */
    +851 	getStaticContentAsDOM: function() {
    +852 		if(this.contentElement.nodeName == 'TEXTAREA') {
    +853 			var div = this.doc.createElement('DIV');
    +854 			div.innerHTML = this.contentElement[xq.Browser.isWebkit ? 'innerHTML' : 'value'];
    +855 			return div;
    +856 		} else {
    +857 			return this.contentElement;
    +858 		}
    +859 	},
    +860 	
    +861 	/**
    +862 	 * Gives focus to editor
    +863 	 */
    +864 	focus: function() {
    +865 		if(this.getCurrentEditMode() == 'wysiwyg') {
    +866 			this.rdom.focus();
    +867 			window.setTimeout(function() {
    +868 				this.updateAllToolbarButtonsStatus(this.rdom.getCurrentElement());
    +869 			}.bind(this), 0);
    +870 		} else if(this.getCurrentEditMode() == 'source') {
    +871 			this.sourceEditorTextarea.focus();
    +872 		}
    +873 	},
    +874 	
    +875 	/**
    +876 	 * Returns designmode iframe object
    +877 	 */
    +878 	getFrame: function() {
    +879 		return this.editorFrame;
    +880 	},
    +881 	
    +882 	/**
    +883 	 * Returns designmode window object
    +884 	 */
    +885 	getWin: function() {
    +886 		return this.editorWin;
    +887 	},
    +888 	
    +889 	/**
    +890 	 * Returns designmode document object
    +891 	 */
    +892 	getDoc: function() {
    +893 		return this.editorDoc;
    +894 	},
    +895 	
    +896 	/**
    +897 	 * Returns outmost wrapper element
    +898 	 */
    +899 	getOutmostWrapper: function() {
    +900 		return this.outmostWrapper;
    +901 	},
    +902 	
    +903 	/**
    +904 	 * Returns designmode body object
    +905 	 */
    +906 	getBody: function() {
    +907 		return this.editorBody;
    +908 	},
    +909 	
    +910 	_createEditorFrame: function() {
    +911 		// create outer DIV
    +912 		this.outmostWrapper = this.doc.createElement('div');
    +913 		this.outmostWrapper.className = "xquared";
    +914 		
    +915 		this.contentElement.parentNode.insertBefore(this.outmostWrapper, this.contentElement);
    +916 		
    +917 		// create toolbar is needed
    +918 		if(!this.toolbarContainer && this.config.generateDefaultToolbar) {
    +919 			this.toolbarContainer = this._generateDefaultToolbar();
    +920 			this.outmostWrapper.appendChild(this.toolbarContainer);
    +921 		}
    +922 		
    +923 		// create source editor div
    +924 		this.sourceEditorDiv = this.doc.createElement('div');
    +925 		this.sourceEditorDiv.className = "editor source_editor"; //TODO: remove editor
    +926 		this.sourceEditorDiv.style.display = "none";
    +927 		this.outmostWrapper.appendChild(this.sourceEditorDiv);
    +928 		
    +929 		// create TEXTAREA for source editor
    +930 		this.sourceEditorTextarea = this.doc.createElement('textarea');
    +931 		this.sourceEditorDiv.appendChild(this.sourceEditorTextarea);
    +932 		
    +933 		// create WYSIWYG editor div
    +934 		this.wysiwygEditorDiv = this.doc.createElement('div');
    +935 		this.wysiwygEditorDiv.className = "editor wysiwyg_editor"; //TODO: remove editor
    +936 		this.wysiwygEditorDiv.style.display = "none";
    +937 		this.outmostWrapper.appendChild(this.wysiwygEditorDiv);
    +938 		
    +939 		// create designmode iframe for WYSIWYG editor
    +940 		this.editorFrame = this.doc.createElement('iframe');
    +941 		this.rdom.setAttributes(this.editorFrame, {
    +942 			"frameBorder": "0",
    +943 			"marginWidth": "0",
    +944 			"marginHeight": "0",
    +945 			"leftMargin": "0",
    +946 			"topMargin": "0",
    +947 			"allowTransparency": "true"
    +948 		});
    +949 		this.wysiwygEditorDiv.appendChild(this.editorFrame);
    +950 		
    +951 		var doc = this.editorFrame.contentWindow.document;
    +952 		if(xq.Browser.isTrident) doc.designMode = 'On';
    +953 		
    +954 		doc.open();
    +955 		doc.write('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">');
    +956 		doc.write('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ko">');
    +957 		doc.write('<head>');
    +958 		
    +959 		// it is needed to force href of pasted content to be an absolute url
    +960 		if(!xq.Browser.isTrident) doc.write('<base href="./" />');
    +961 		
    +962 		doc.write('<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />');
    +963 		doc.write('<title>XQuared</title>');
    +964 		if(this.config.changeCursorOnLink) doc.write('<style>.xed a {cursor: pointer !important;}</style>');
    +965 		doc.write('</head>');
    +966 		doc.write('<body><p>' + this.rdom.makePlaceHolderString() + '</p></body>');
    +967 		doc.write('</html>');
    +968 		doc.close();
    +969 		
    +970 		this.editorWin = this.editorFrame.contentWindow;
    +971 		this.editorDoc = this.editorWin.document;
    +972 		this.editorBody = this.editorDoc.body;
    +973 		this.editorBody.className = "xed";
    +974 		
    +975 		// it is needed to fix IE6 horizontal scrollbar problem
    +976 		if(xq.Browser.isIE6) {
    +977 			this.editorDoc.documentElement.style.overflowY='auto';
    +978 			this.editorDoc.documentElement.style.overflowX='hidden';
    +979 		}
    +980 		
    +981 		this.rdom.setWin(this.editorWin);
    +982 		this.rdom.setRoot(this.editorBody);
    +983 		this.validator = xq.Validator.createInstance(this.doc.location.href, this.config.urlValidationMode, this.config.allowedTags, this.config.allowedAttributes);
    +984 		
    +985 		// hook onsubmit of form
    +986 		if(this.config.automaticallyHookSubmitEvent && this.contentElement.nodeName == 'TEXTAREA' && this.contentElement.form) {
    +987 			var original = this.contentElement.form.onsubmit;
    +988 			
    +989 			this.contentElement.form.onsubmit = function() {
    +990 				this.contentElement.value = this.getCurrentContent(true);
    +991 				if(original) {
    +992 					return original();
    +993 				} else {
    +994 					return true;
    +995 				}
    +996 			}.bind(this);
    +997 		}
    +998 	},
    +999 	
    +1000 	_addStyleRule: function(selector, rule) {
    +1001 		if(!this.dynamicStyle) {
    +1002 			if(xq.Browser.isTrident) {
    +1003 			    this.dynamicStyle = this.doc.createStyleSheet();
    +1004 			} else {
    +1005 	    		var style = this.doc.createElement('style');
    +1006 	    		this.doc.body.appendChild(style);
    +1007 		    	this.dynamicStyle = $A(this.doc.styleSheets).last();
    +1008 			}
    +1009 		}
    +1010 		
    +1011 		if(xq.Browser.isTrident) {
    +1012 			this.dynamicStyle.addRule(selector, rule);
    +1013 		} else {
    +1014 	    	this.dynamicStyle.insertRule(selector + " {" + rule + "}", this.dynamicStyle.cssRules.length);
    +1015     	}
    +1016 	},
    +1017 	
    +1018 	_generateDefaultToolbar: function() {
    +1019 		// override image path
    +1020 		this._addStyleRule(".xquared div.toolbar", "background-image: url(" + this.config.imagePathForDefaultToobar + "toolbarBg.gif)");
    +1021 		this._addStyleRule(".xquared ul.buttons li", "background-image: url(" + this.config.imagePathForDefaultToobar + "toolbarButtonBg.gif)");
    +1022 		this._addStyleRule(".xquared ul.buttons li.xq_separator", "background-image: url(" + this.config.imagePathForDefaultToobar + "toolbarSeparator.gif)");
    +1023 		
    +1024 		// outmost container
    +1025 		var container = this.doc.createElement('div');
    +1026 		container.className = 'toolbar';
    +1027 		
    +1028 		// button container
    +1029 		var buttons = this.doc.createElement('ul');
    +1030 		buttons.className = 'buttons';
    +1031 		container.appendChild(buttons);
    +1032 		
    +1033 		// Generate buttons from map and append it to button container
    +1034 		var cancelMousedown = function(e) {Event.stop(e); return false};
    +1035 		var map = this.config.defaultToolbarButtonMap;
    +1036 		for(var i = 0; i < map.length; i++) {
    +1037 			for(var j = 0; j < map[i].length; j++) {
    +1038 				var buttonConfig = map[i][j];
    +1039 
    +1040 				var li = this.doc.createElement('li');
    +1041 				buttons.appendChild(li);
    +1042 				li.className = buttonConfig.className;
    +1043 				
    +1044 				var span = this.doc.createElement('span');
    +1045 				li.appendChild(span);
    +1046 				
    +1047 				var a = this.doc.createElement('a');
    +1048 				span.appendChild(a);
    +1049 				a.href = '#';
    +1050 				a.title = buttonConfig.title;
    +1051 				a.handler = buttonConfig.handler;
    +1052 				a.xed = this;
    +1053 				Event.observe(a, 'mousedown', cancelMousedown);
    +1054 				Event.observe(a, 'click', function(e) {
    +1055 					var xed = this.xed;
    +1056 					
    +1057 					if($(this.parentNode).hasClassName('disabled') || xed.toolbarContainer.hasClassName('disabled')) {
    +1058 						Event.stop(e);
    +1059 						return false;
    +1060 					}
    +1061 					
    +1062 					if(xq.Browser.isTrident) xed.focus();
    +1063 					
    +1064 					var handler = this.handler;
    +1065 					var stop = (typeof handler == "function") ? handler(xed) : eval(handler);
    +1066 					if(stop) {
    +1067 						Event.stop(e);
    +1068 						return false;
    +1069 					} else {
    +1070 						return true;
    +1071 					}
    +1072 				}.bind(a));
    +1073 				
    +1074 				var img = this.doc.createElement('img');
    +1075 				a.appendChild(img);
    +1076 				img.src = this.config.imagePathForDefaultToobar + buttonConfig.className + '.gif';
    +1077 
    +1078 				if(j == 0 && i != 0) li.className += ' xq_separator';
    +1079 			}
    +1080 		}
    +1081 		
    +1082 		return container;
    +1083 	},
    +1084 	
    +1085 	
    +1086 	
    +1087 	/////////////////////////////////////////////
    +1088 	// Event Management
    +1089 	
    +1090 	_registerEventHandlers: function() {
    +1091 		var events = ['keydown', 'click', 'keyup', 'mouseup', 'contextmenu', 'scroll'];
    +1092 		
    +1093 		if(xq.Browser.isTrident && this.config.changeCursorOnLink) events.push('mousemove');
    +1094 		if(xq.Browser.isMac && xq.Browser.isGecko) events.push('keypress');
    +1095 		
    +1096 		for(var i = 0; i < events.length; i++) {
    +1097 			Event.observe(this.getDoc(), events[i], this._handleEvent.bindAsEventListener(this));
    +1098 		}
    +1099 	},
    +1100 	
    +1101 	_handleEvent: function(e) {
    +1102 		this._fireOnBeforeEvent(this, e);
    +1103 		
    +1104 		var stop = false;
    +1105 		
    +1106 		var modifiedByCorrection = false;
    +1107 		
    +1108 		if(e.type == 'mousemove' && this.config.changeCursorOnLink) {
    +1109 			// Trident only
    +1110 			var link = !!this.rdom.getParentElementOf(e.srcElement, ["A"]);
    +1111 			if(this.editorBody.contentEditable != link && !this.rdom.hasSelection()) this.editorBody.contentEditable = !link;
    +1112 		} else if(e.type == 'click' && e.button == 0 && this.config.enableLinkClick) {
    +1113 			var a = this.rdom.getParentElementOf(e.target || e.srcElement, ["A"]);
    +1114 			if(a) stop = this.handleClick(e, a);
    +1115 		} else if(e.type == (xq.Browser.isMac && xq.Browser.isGecko ? "keypress" : "keydown")) {
    +1116 			var undoPerformed = false;
    +1117 			
    +1118 			modifiedByCorrection = this.rdom.correctParagraph();
    +1119 			for(var key in this.config.shortcuts) {
    +1120 				if(!this.config.shortcuts[key].event.matches(e)) continue;
    +1121 				
    +1122 				var handler = this.config.shortcuts[key].handler;
    +1123 				var xed = this;
    +1124 				stop = (typeof handler == "function") ? handler(this) : eval(handler);
    +1125 				
    +1126 				if(key == "undo") undoPerformed = true;
    +1127 			}
    +1128 		} else if(["mouseup", "keyup"].include(e.type)) {
    +1129 			modifiedByCorrection = this.rdom.correctParagraph();
    +1130 		} else if(["contextmenu"].include(e.type)) {
    +1131 			this._handleContextMenu(e);
    +1132 		}
    +1133 		
    +1134 		if(stop) Event.stop(e);
    +1135 		
    +1136 		this._fireOnCurrentContentChanged(this);
    +1137 		this._fireOnAfterEvent(this, e);
    +1138 		
    +1139 		if(!undoPerformed && !modifiedByCorrection) this.editHistory.onEvent(e);
    +1140 		
    +1141 		return !stop;
    +1142 	},
    +1143 
    +1144 	/**
    +1145 	 * TODO: remove dup with handleAutocompletion
    +1146 	 */
    +1147 	handleAutocorrection: function() {
    +1148 		var block = this.rdom.getCurrentBlockElement();
    +1149 		
    +1150 		// TODO: use complete unescape algorithm
    +1151 		var text = this.rdom.getInnerText(block).replace(/ /gi, " ");
    +1152 		
    +1153 		var acs = this.config.autocorrections;
    +1154 		var performed = false;
    +1155 		
    +1156 		var stop = false;
    +1157 		for(var key in acs) {
    +1158 			var ac = acs[key];
    +1159 			if(ac.criteria(text)) {
    +1160 				try {
    +1161 					this.editHistory.onCommand();
    +1162 					this.editHistory.disable();
    +1163 					if(typeof ac.handler == "String") {
    +1164 						var xed = this;
    +1165 						var rdom = this.rdom;
    +1166 						eval(ac.handler);
    +1167 					} else {
    +1168 						stop = ac.handler(this, this.rdom, block, text);
    +1169 					}
    +1170 					this.editHistory.enable();
    +1171 				} catch(ignored) {}
    +1172 				
    +1173 				block = this.rdom.getCurrentBlockElement();
    +1174 				text = this.rdom.getInnerText(block);
    +1175 				
    +1176 				performed = true;
    +1177 				if(stop) break;
    +1178 			}
    +1179 		}
    +1180 		
    +1181 		return stop;
    +1182 	},
    +1183 	
    +1184 	/**
    +1185 	 * TODO: remove dup with handleAutocorrection
    +1186 	 */
    +1187 	handleAutocompletion: function() {
    +1188 		var acs = $H(this.config.autocompletions);
    +1189 		if(acs.size() == 0) return;
    +1190 
    +1191 		if(this.rdom.hasSelection()) {
    +1192 			var text = this.rdom.getSelectionAsText();
    +1193 			this.rdom.deleteSelection();
    +1194 			var wrapper = this.rdom.insertNode(this.rdom.createElement("SPAN"));
    +1195 			wrapper.innerHTML = text;
    +1196 			
    +1197 			var marker = this.rdom.pushMarker();
    +1198 
    +1199 			var filtered = 
    +1200 				acs.map(function(pair) {
    +1201 					return [pair.key, pair.value.criteria(text)];
    +1202 				}.bind(this)).findAll(function(elem) {
    +1203 					return elem[1] != -1;
    +1204 				}).sortBy(function(elem) {
    +1205 					return elem[1];
    +1206 				});
    +1207 			
    +1208 			if(filtered.length == 0) {
    +1209 				this.rdom.popMarker(true);
    +1210 				return;
    +1211 			}
    +1212 			var ac = acs.get(filtered[0][0]);
    +1213 			
    +1214 			this.editHistory.disable();
    +1215 		} else {
    +1216 			var marker = this.rdom.pushMarker();
    +1217 			
    +1218 			var filtered = 
    +1219 				acs.map(function(pair) {
    +1220 					return [pair.key, this.rdom.testSmartWrap(marker, pair.value.criteria).textIndex];
    +1221 				}.bind(this)).findAll(function(elem) {
    +1222 					return elem[1] != -1;
    +1223 				}).sortBy(function(elem) {
    +1224 					return elem[1];
    +1225 				});
    +1226 			
    +1227 			if(filtered.length == 0) {
    +1228 				this.rdom.popMarker(true);
    +1229 				return;
    +1230 			}
    +1231 			
    +1232 			var ac = acs.get(filtered[0][0]);
    +1233 			
    +1234 			this.editHistory.disable();
    +1235 			
    +1236 			var wrapper = this.rdom.smartWrap(marker, "SPAN", ac.criteria);
    +1237 		}
    +1238 		
    +1239 		var block = this.rdom.getCurrentBlockElement();
    +1240 		
    +1241 		// TODO: use complete unescape algorithm
    +1242 		var text = this.rdom.getInnerText(wrapper).replace(/ /gi, " ");
    +1243 		
    +1244 		try {
    +1245 			// call handler
    +1246 			if(typeof ac.handler == "String") {
    +1247 				var xed = this;
    +1248 				var rdom = this.rdom;
    +1249 				eval(ac.handler);
    +1250 			} else {
    +1251 				ac.handler(this, this.rdom, block, wrapper, text);
    +1252 			}
    +1253 		} catch(ignored) {}
    +1254 		
    +1255 		try {
    +1256 			this.rdom.unwrapElement(wrapper);
    +1257 		} catch(ignored) {}
    +1258 
    +1259 		
    +1260 		if(this.rdom.isEmptyBlock(block)) this.rdom.correctEmptyElement(block);
    +1261 		
    +1262 		this.editHistory.enable();
    +1263 		this.editHistory.onCommand();
    +1264 		
    +1265 		this.rdom.popMarker(true);
    +1266 	},
    +1267 
    +1268 	/**
    +1269 	 * Handles click event
    +1270 	 *
    +1271 	 * @param {Event} e click event
    +1272 	 * @param {Element} target target element(usually has A tag)
    +1273 	 */
    +1274 	handleClick: function(e, target) {
    +1275 		var href = decodeURI(target.href);
    +1276 		if(!xq.Browser.isTrident) {
    +1277 			if(!e.ctrlKey && !e.shiftKey && e.button != 1) {
    +1278 				window.location.href = href;
    +1279 				return true;
    +1280 			}
    +1281 		} else {
    +1282 			if(e.shiftKey) {
    +1283 				window.open(href, "_blank");
    +1284 			} else {
    +1285 				window.location.href = href;
    +1286 			}
    +1287 			return true;
    +1288 		}
    +1289 		
    +1290 		return false;
    +1291 	},
    +1292 
    +1293 	/**
    +1294 	 * Show link dialog
    +1295 	 *
    +1296 	 * TODO: should support modify/unlink
    +1297 	 */
    +1298 	handleLink: function() {
    +1299 		var text = this.rdom.getSelectionAsText() || '';
    +1300 		var dialog = new xq.controls.FormDialog(
    +1301 			this,
    +1302 			xq.ui_templates.basicLinkDialog,
    +1303 			function(dialog) {
    +1304 				if(text) {
    +1305 					dialog.form.text.value = text;
    +1306 					dialog.form.url.focus();
    +1307 					dialog.form.url.select();
    +1308 				}
    +1309 			},
    +1310 			function(data) {
    +1311 				this.focus();
    +1312 				
    +1313 				if(xq.Browser.isTrident) {
    +1314 					var rng = this.rdom.rng();
    +1315 					rng.moveToBookmark(bm);
    +1316 					rng.select();
    +1317 				}
    +1318 				
    +1319 				if(!data) return;
    +1320 				this.handleInsertLink(false, data.url, data.text, data.text);
    +1321 			}.bind(this)
    +1322 		);
    +1323 		
    +1324 		if(xq.Browser.isTrident) var bm = this.rdom.rng().getBookmark();
    +1325 		
    +1326 		dialog.show({position: 'centerOfEditor'});
    +1327 		
    +1328 		return true;
    +1329 	},
    +1330 	
    +1331 	/**
    +1332 	 * Inserts link or apply link into selected area
    +1333 	 * 
    +1334 	 * @param {boolean} autoSelection if set true and there's no selection, automatically select word to link(if possible)
    +1335 	 * @param {String} url url
    +1336 	 * @param {String} title title of link
    +1337 	 * @param {String} text text of link. If there's a selection(manually or automatically), it will be replaced with this text
    +1338 	 *
    +1339 	 * @returns {Element} created element
    +1340 	 */
    +1341 	handleInsertLink: function(autoSelection, url, title, text) {
    +1342 		if(autoSelection && !this.rdom.hasSelection()) {
    +1343 			var marker = this.rdom.pushMarker();
    +1344 			var a = this.rdom.smartWrap(marker, "A", function(text) {
    +1345 				var index = text.lastIndexOf(" ");
    +1346 				return index == -1 ? index : index + 1;
    +1347 			});
    +1348 			a.href = url;
    +1349 			a.title = title;
    +1350 			if(text) {
    +1351 				a.innerHTML = ""
    +1352 				a.appendChild(this.rdom.createTextNode(text));
    +1353 			} else if(!a.hasChildNodes()) {
    +1354 				this.rdom.deleteNode(a);
    +1355 			}
    +1356 			this.rdom.popMarker(true);
    +1357 		} else {
    +1358 			text = text || (this.rdom.hasSelection() ? this.rdom.getSelectionAsText() : null);
    +1359 			if(!text) return;
    +1360 			
    +1361 			this.rdom.deleteSelection();
    +1362 			
    +1363 			var a = this.rdom.createElement('A');
    +1364 			a.href = url;
    +1365 			a.title = title;
    +1366 			a.appendChild(this.rdom.createTextNode(text));
    +1367 			this.rdom.insertNode(a);
    +1368 		}
    +1369 		
    +1370 		var historyAdded = this.editHistory.onCommand();
    +1371 		this._fireOnCurrentContentChanged(this);
    +1372 		
    +1373 		return true;
    +1374 	},
    +1375 	
    +1376 	/**
    +1377 	 * Called when enter key pressed.
    +1378 	 *
    +1379 	 * @param {boolean} skipAutocorrection if set true, skips autocorrection
    +1380 	 * @param {boolean} forceInsertParagraph if set true, inserts paragraph
    +1381 	 */
    +1382 	handleEnter: function(skipAutocorrection, forceInsertParagraph) {
    +1383 		// If it has selection, perform default action.
    +1384 		if(this.rdom.hasSelection()) return false;
    +1385 		
    +1386 		// Perform autocorrection
    +1387 		if(!skipAutocorrection && this.handleAutocorrection()) return true;
    +1388 		
    +1389 		var atEmptyBlock = this.rdom.isCaretAtEmptyBlock();
    +1390 		var atStart = atEmptyBlock || this.rdom.isCaretAtBlockStart();
    +1391 		var atEnd = atEmptyBlock || (!atStart && this.rdom.isCaretAtBlockEnd());
    +1392 		var atEdge = atEmptyBlock || atStart || atEnd;
    +1393 		
    +1394 		if(!atEdge) {
    +1395 			var block = this.rdom.getCurrentBlockElement();
    +1396 			var marker = this.rdom.pushMarker();
    +1397 			
    +1398 			if(this.rdom.isFirstLiWithNestedList(block) && !forceInsertParagraph) {
    +1399 				var parent = block.parentNode;
    +1400 				this.rdom.unwrapElement(block);
    +1401 				block = parent;
    +1402 			} else if(block.nodeName != "LI" && this.rdom.tree.isBlockContainer(block)) {
    +1403 				block = this.rdom.wrapAllInlineOrTextNodesAs("P", block, true).first();
    +1404 			}
    +1405 			this.rdom.splitElementUpto(marker, block);
    +1406 			
    +1407 			this.rdom.popMarker(true);
    +1408 		} else if(atEmptyBlock) {
    +1409 			this._handleEnterAtEmptyBlock();
    +1410 		} else {
    +1411 			this._handleEnterAtEdge(atStart, forceInsertParagraph);
    +1412 		}
    +1413 		
    +1414 		return true;
    +1415 	},
    +1416 	
    +1417 	/**
    +1418 	 * Moves current block upward or downward
    +1419 	 *
    +1420 	 * @param {boolean} up moves current block upward
    +1421 	 */
    +1422 	handleMoveBlock: function(up) {
    +1423 		var block = this.rdom.moveBlock(this.rdom.getCurrentBlockElement(), up);
    +1424 		if(block) {
    +1425 			this.rdom.selectElement(block, false);
    +1426 			block.scrollIntoView(false);
    +1427 			
    +1428 			var historyAdded = this.editHistory.onCommand();
    +1429 			this._fireOnCurrentContentChanged(this);
    +1430 		}
    +1431 		return true;
    +1432 	},
    +1433 	
    +1434 	/**
    +1435 	 * Called when tab key pressed
    +1436 	 */
    +1437 	handleTab: function() {
    +1438 		var hasSelection = this.rdom.hasSelection();
    +1439 		var table = this.rdom.getParentElementOf(this.rdom.getCurrentBlockElement(), ["TABLE"]);
    +1440 		
    +1441 		if(hasSelection) {
    +1442 			this.handleIndent();
    +1443 		} else if (table && table.className == "datatable") {
    +1444 			this.handleMoveToNextCell();
    +1445 		} else if (this.rdom.isCaretAtBlockStart()) {
    +1446 			this.handleIndent();
    +1447 		} else {
    +1448 			this.handleInsertTab();
    +1449 		}
    +1450 
    +1451 		return true;
    +1452 	},
    +1453 	
    +1454 	/**
    +1455 	 * Called when shift+tab key pressed
    +1456 	 */
    +1457 	handleShiftTab: function() {
    +1458 		var hasSelection = this.rdom.hasSelection();
    +1459 		var table = this.rdom.getParentElementOf(this.rdom.getCurrentBlockElement(), ["TABLE"]);
    +1460 		
    +1461 		if(hasSelection) {
    +1462 			this.handleOutdent();
    +1463 		} else if (table && table.className == "datatable") {
    +1464 			this.handleMoveToPreviousCell();
    +1465 		} else {
    +1466 			this.handleOutdent();
    +1467 		}
    +1468 		
    +1469 		return true;
    +1470 	},
    +1471 	
    +1472 	/**
    +1473 	 * Inserts three non-breaking spaces
    +1474 	 */
    +1475 	handleInsertTab: function() {
    +1476 		this.rdom.insertHtml(' ');
    +1477 		this.rdom.insertHtml(' ');
    +1478 		this.rdom.insertHtml(' ');
    +1479 		
    +1480 		return true;
    +1481 	},
    +1482 	
    +1483 	/**
    +1484 	 * Called when delete key pressed
    +1485 	 */
    +1486 	handleDelete: function() {
    +1487 		if(this.rdom.hasSelection() || !this.rdom.isCaretAtBlockEnd()) return false;
    +1488 		return this._handleMerge(true);
    +1489 	},
    +1490 	
    +1491 	/**
    +1492 	 * Called when backspace key pressed
    +1493 	 */
    +1494 	handleBackspace: function() {
    +1495 		if(this.rdom.hasSelection() || !this.rdom.isCaretAtBlockStart()) return false;
    +1496 		return this._handleMerge(false);
    +1497 	},
    +1498 	
    +1499 	_handleMerge: function(withNext) {
    +1500 		var block = this.rdom.getCurrentBlockElement();
    +1501 		
    +1502 		// save caret position;
    +1503 		var marker = this.rdom.pushMarker();
    +1504 		
    +1505 		// perform merge
    +1506 		var merged = this.rdom.mergeElement(block, withNext, withNext);
    +1507 		if(!merged && !withNext) this.rdom.extractOutElementFromParent(block);
    +1508 		
    +1509 		// restore caret position
    +1510 		this.rdom.popMarker(true);
    +1511 		if(merged) this.rdom.correctEmptyElement(merged);
    +1512 		
    +1513 		var historyAdded = this.editHistory.onCommand();
    +1514 		this._fireOnCurrentContentChanged(this);
    +1515 		
    +1516 		return !!merged;
    +1517 	},
    +1518 	
    +1519 	/**
    +1520 	 * (in table) Moves caret to the next cell
    +1521 	 */
    +1522 	handleMoveToNextCell: function() {
    +1523 		this._handleMoveToCell("next");
    +1524 	},
    +1525 
    +1526 	/**
    +1527 	 * (in table) Moves caret to the previous cell
    +1528 	 */
    +1529 	handleMoveToPreviousCell: function() {
    +1530 		this._handleMoveToCell("prev");
    +1531 	},
    +1532 
    +1533 	/**
    +1534 	 * (in table) Moves caret to the above cell
    +1535 	 */
    +1536 	handleMoveToAboveCell: function() {
    +1537 		this._handleMoveToCell("above");
    +1538 	},
    +1539 
    +1540 	/**
    +1541 	 * (in table) Moves caret to the below cell
    +1542 	 */
    +1543 	handleMoveToBelowCell: function() {
    +1544 		this._handleMoveToCell("below");
    +1545 	},
    +1546 
    +1547 	_handleMoveToCell: function(dir) {
    +1548 		var block = this.rdom.getCurrentBlockElement();
    +1549 		var cell = this.rdom.getParentElementOf(block, ["TD", "TH"]);
    +1550 		var table = this.rdom.getParentElementOf(cell, ["TABLE"]);
    +1551 		var rtable = new xq.RichTable(this.rdom, table);
    +1552 		var target = null;
    +1553 		
    +1554 		if(["next", "prev"].include(dir)) {
    +1555 			var toNext = dir == "next";
    +1556 			target = toNext ? rtable.getNextCellOf(cell) : rtable.getPreviousCellOf(cell);
    +1557 		} else {
    +1558 			var toBelow = dir == "below";
    +1559 			target = toBelow ? rtable.getBelowCellOf(cell) : rtable.getAboveCellOf(cell);
    +1560 		}
    +1561 
    +1562 		if(!target) {
    +1563 			var finder = function(node) {return !['TD', 'TH'].include(node.nodeName) && this.tree.isBlock(node) && !this.tree.hasBlocks(node);}.bind(this.rdom);
    +1564 			var exitCondition = function(node) {return this.tree.isBlock(node) && !this.tree.isDescendantOf(this.getRoot(), node)}.bind(this.rdom);
    +1565 			
    +1566 			target = (toNext || toBelow) ? 
    +1567 				this.rdom.tree.findForward(cell, finder, exitCondition) :
    +1568 				this.rdom.tree.findBackward(table, finder, exitCondition);
    +1569 		}
    +1570 		
    +1571 		if(target) this.rdom.placeCaretAtStartOf(target);
    +1572 	},
    +1573 	
    +1574 	/**
    +1575 	 * Applies STRONG tag
    +1576 	 */
    +1577 	handleStrongEmphasis: function() {
    +1578 		this.rdom.applyStrongEmphasis();
    +1579 		
    +1580 		var historyAdded = this.editHistory.onCommand();
    +1581 		this._fireOnCurrentContentChanged(this);
    +1582 		
    +1583 		return true;
    +1584 	},
    +1585 	
    +1586 	/**
    +1587 	 * Applies EM tag
    +1588 	 */
    +1589 	handleEmphasis: function() {
    +1590 		this.rdom.applyEmphasis();
    +1591 		
    +1592 		var historyAdded = this.editHistory.onCommand();
    +1593 		this._fireOnCurrentContentChanged(this);
    +1594 		
    +1595 		return true;
    +1596 	},
    +1597 	
    +1598 	/**
    +1599 	 * Applies EM.underline tag
    +1600 	 */
    +1601 	handleUnderline: function() {
    +1602 		this.rdom.applyUnderline();
    +1603 		
    +1604 		var historyAdded = this.editHistory.onCommand();
    +1605 		this._fireOnCurrentContentChanged(this);
    +1606 		
    +1607 		return true;
    +1608 	},
    +1609 	
    +1610 	/**
    +1611 	 * Applies SPAN.strike tag
    +1612 	 */
    +1613 	handleStrike: function() {
    +1614 		this.rdom.applyStrike();
    +1615 
    +1616 		var historyAdded = this.editHistory.onCommand();
    +1617 		this._fireOnCurrentContentChanged(this);
    +1618 
    +1619 		return true;
    +1620 	},
    +1621 	
    +1622 	/**
    +1623 	 * Removes all style
    +1624 	 */
    +1625 	handleRemoveFormat: function() {
    +1626 		this.rdom.applyRemoveFormat();
    +1627 
    +1628 		var historyAdded = this.editHistory.onCommand();
    +1629 		this._fireOnCurrentContentChanged(this);
    +1630 
    +1631 		return true;
    +1632 	},
    +1633 	
    +1634 	/**
    +1635 	 * Inserts table
    +1636 	 *
    +1637 	 * @param {Number} cols number of columns
    +1638 	 * @param {Number} rows number of rows
    +1639 	 * @param {String} headerPosition position of THs. "T" or "L" or "TL". "T" means top, "L" means left.
    +1640 	 */
    +1641 	handleTable: function(cols, rows, headerPositions) {
    +1642 		var cur = this.rdom.getCurrentBlockElement();
    +1643 		if(this.rdom.getParentElementOf(cur, ["TABLE"])) return true;
    +1644 		
    +1645 		var rtable = xq.RichTable.create(this.rdom, cols, rows, headerPositions);
    +1646 		if(this.rdom.tree.isBlockContainer(cur)) {
    +1647 			var wrappers = this.rdom.wrapAllInlineOrTextNodesAs("P", cur, true);
    +1648 			cur = wrappers.last();
    +1649 		}
    +1650 		var tableDom = this.rdom.insertNodeAt(rtable.getDom(), cur, "after");
    +1651 		this.rdom.placeCaretAtStartOf(rtable.getCellAt(0, 0));
    +1652 		
    +1653 		if(this.rdom.isEmptyBlock(cur)) this.rdom.deleteNode(cur, true);
    +1654 		
    +1655 		var historyAdded = this.editHistory.onCommand();
    +1656 		this._fireOnCurrentContentChanged(this);
    +1657 		
    +1658 		return true;
    +1659 	},
    +1660 	
    +1661 	handleInsertNewRowAt: function(where) {
    +1662 		var cur = this.rdom.getCurrentBlockElement();
    +1663 		var tr = this.rdom.getParentElementOf(cur, ["TR"]);
    +1664 		if(!tr) return true;
    +1665 		
    +1666 		var table = this.rdom.getParentElementOf(tr, ["TABLE"]);
    +1667 		var rtable = new xq.RichTable(this.rdom, table);
    +1668 		var row = rtable.insertNewRowAt(tr, where);
    +1669 		
    +1670 		this.rdom.placeCaretAtStartOf(row.cells[0]);
    +1671 		return true;
    +1672 	},
    +1673 	handleInsertNewColumnAt: function(where) {
    +1674 		var cur = this.rdom.getCurrentBlockElement();
    +1675 		var td = this.rdom.getParentElementOf(cur, ["TD"], true);
    +1676 		if(!td) return true;
    +1677 		
    +1678 		var table = this.rdom.getParentElementOf(td, ["TABLE"]);
    +1679 		var rtable = new xq.RichTable(this.rdom, table);
    +1680 		rtable.insertNewCellAt(td, where);
    +1681 		
    +1682 		this.rdom.placeCaretAtStartOf(cur);
    +1683 		return true;
    +1684 	},
    +1685 	
    +1686 	handleDeleteRow: function() {
    +1687 		var cur = this.rdom.getCurrentBlockElement();
    +1688 		var tr = this.rdom.getParentElementOf(cur, ["TR"]);
    +1689 		if(!tr) return true;
    +1690 
    +1691 		var table = this.rdom.getParentElementOf(tr, ["TABLE"]);
    +1692 		var rtable = new xq.RichTable(this.rdom, table);
    +1693 		var blockToMove = rtable.deleteRow(tr);
    +1694 		
    +1695 		this.rdom.placeCaretAtStartOf(blockToMove);
    +1696 		return true;
    +1697 	},
    +1698 	
    +1699 	handleDeleteColumn: function() {
    +1700 		var cur = this.rdom.getCurrentBlockElement();
    +1701 		var td = this.rdom.getParentElementOf(cur, ["TD"], true);
    +1702 		if(!td) return true;
    +1703 
    +1704 		var table = this.rdom.getParentElementOf(td, ["TABLE"]);
    +1705 		var rtable = new xq.RichTable(this.rdom, table);
    +1706 		rtable.deleteCell(td);
    +1707 
    +1708 		return true;
    +1709 	},
    +1710 	
    +1711 	/**
    +1712 	 * Performs block indentation
    +1713 	 */
    +1714 	handleIndent: function() {
    +1715 		if(this.rdom.hasSelection()) {
    +1716 			var blocks = this.rdom.getBlockElementsAtSelectionEdge(true, true);
    +1717 			if(blocks.first() != blocks.last()) {
    +1718 				var affected = this.rdom.indentElements(blocks.first(), blocks.last());
    +1719 				this.rdom.selectBlocksBetween(affected.first(), affected.last());
    +1720 				
    +1721 				var historyAdded = this.editHistory.onCommand();
    +1722 				this._fireOnCurrentContentChanged(this);
    +1723 				
    +1724 				return true;
    +1725 			}
    +1726 		}
    +1727 		
    +1728 		var block = this.rdom.getCurrentBlockElement();
    +1729 		var affected = this.rdom.indentElement(block);
    +1730 		
    +1731 		if(affected) {
    +1732 			this.rdom.placeCaretAtStartOf(affected);
    +1733 			
    +1734 			var historyAdded = this.editHistory.onCommand();
    +1735 			this._fireOnCurrentContentChanged(this);
    +1736 		}
    +1737 		
    +1738 		return true;
    +1739 	},
    +1740 
    +1741 	/**
    +1742 	 * Performs block outdentation
    +1743 	 */
    +1744 	handleOutdent: function() {
    +1745 		if(this.rdom.hasSelection()) {
    +1746 			var blocks = this.rdom.getBlockElementsAtSelectionEdge(true, true);
    +1747 			if(blocks.first() != blocks.last()) {
    +1748 				var affected = this.rdom.outdentElements(blocks.first(), blocks.last());
    +1749 				this.rdom.selectBlocksBetween(affected.first(), affected.last());
    +1750 				
    +1751 				var historyAdded = this.editHistory.onCommand();
    +1752 				this._fireOnCurrentContentChanged(this);
    +1753 				
    +1754 				return true;
    +1755 			}
    +1756 		}
    +1757 		
    +1758 		var block = this.rdom.getCurrentBlockElement();
    +1759 		var affected = this.rdom.outdentElement(block);
    +1760 		
    +1761 		if(affected) {
    +1762 			this.rdom.placeCaretAtStartOf(affected);
    +1763 
    +1764 			var historyAdded = this.editHistory.onCommand();
    +1765 			this._fireOnCurrentContentChanged(this);
    +1766 		}
    +1767 		
    +1768 		return true;
    +1769 	},
    +1770 	
    +1771 	/**
    +1772 	 * Applies list.
    +1773 	 *
    +1774 	 * @param {String} type "UL" or "OL" or "CODE". CODE generates OL.code
    +1775 	 */
    +1776 	handleList: function(type) {
    +1777 		if(this.rdom.hasSelection()) {
    +1778 			var blocks = this.rdom.getBlockElementsAtSelectionEdge(true, true);
    +1779 			if(blocks.first() != blocks.last()) {
    +1780 				blocks = this.rdom.applyLists(blocks.first(), blocks.last(), type);
    +1781 			} else {
    +1782 				blocks[0] = blocks[1] = this.rdom.applyList(blocks.first(), type);
    +1783 			}
    +1784 			this.rdom.selectBlocksBetween(blocks.first(), blocks.last());
    +1785 		} else {
    +1786 			var block = this.rdom.applyList(this.rdom.getCurrentBlockElement(), type);
    +1787 			this.rdom.placeCaretAtStartOf(block);
    +1788 		}
    +1789 		var historyAdded = this.editHistory.onCommand();
    +1790 		this._fireOnCurrentContentChanged(this);
    +1791 		
    +1792 		return true;
    +1793 	},
    +1794 	
    +1795 	/**
    +1796 	 * Applies justification
    +1797 	 *
    +1798 	 * @param {String} dir "left", "center", "right" or "both"
    +1799 	 */
    +1800 	handleJustify: function(dir) {
    +1801 		var block = this.rdom.getCurrentBlockElement();
    +1802 		var dir = (dir == "left" || dir == "both") && (block.style.textAlign == "left" || block.style.textAlign == "") ? "both" : dir;
    +1803 		
    +1804 		if(this.rdom.hasSelection()) {
    +1805 			var blocks = this.rdom.getSelectedBlockElements();
    +1806 			this.rdom.justifyBlocks(blocks, dir);
    +1807 			this.rdom.selectBlocksBetween(blocks.first(), blocks.last());
    +1808 		} else {
    +1809 			this.rdom.justifyBlock(block, dir);
    +1810 		}
    +1811 		var historyAdded = this.editHistory.onCommand();
    +1812 		this._fireOnCurrentContentChanged(this);
    +1813 		
    +1814 		return true;
    +1815 	},
    +1816 	
    +1817 	/**
    +1818 	 * Removes current block element
    +1819 	 */
    +1820 	handleRemoveBlock: function() {
    +1821 		var block = this.rdom.getCurrentBlockElement();
    +1822 		var blockToMove = this.rdom.removeBlock(block);
    +1823 		this.rdom.placeCaretAtStartOf(blockToMove);
    +1824 		blockToMove.scrollIntoView(false);
    +1825 	},
    +1826 	
    +1827 	/**
    +1828 	 * Applies background color
    +1829 	 *
    +1830 	 * @param {String} color CSS color string
    +1831 	 */
    +1832 	handleBackgroundColor: function(color) {
    +1833 		if(color) {
    +1834 			this.rdom.applyBackgroundColor(color);
    +1835 
    +1836 			var historyAdded = this.editHistory.onCommand();
    +1837 			this._fireOnCurrentContentChanged(this);
    +1838 		} else {
    +1839 			var dialog = new xq.controls.FormDialog(
    +1840 				this,
    +1841 				xq.ui_templates.basicColorPickerDialog,
    +1842 				function(dialog) {},
    +1843 				function(data) {
    +1844 					this.focus();
    +1845 					
    +1846 					if(xq.Browser.isTrident) {
    +1847 						var rng = this.rdom.rng();
    +1848 						rng.moveToBookmark(bm);
    +1849 						rng.select();
    +1850 					}
    +1851 					
    +1852 					if(!data) return;
    +1853 					
    +1854 					this.handleBackgroundColor(data.color);
    +1855 				}.bind(this)
    +1856 			);
    +1857 			
    +1858 			if(xq.Browser.isTrident) var bm = this.rdom.rng().getBookmark();
    +1859 			
    +1860 			dialog.show({position: 'centerOfEditor'});
    +1861 		}
    +1862 		return true;
    +1863 	},
    +1864 	
    +1865 	/**
    +1866 	 * Applies foreground color
    +1867 	 *
    +1868 	 * @param {String} color CSS color string
    +1869 	 */
    +1870 	handleForegroundColor: function(color) {
    +1871 		if(color) {
    +1872 			this.rdom.applyForegroundColor(color);
    +1873 
    +1874 			var historyAdded = this.editHistory.onCommand();
    +1875 			this._fireOnCurrentContentChanged(this);
    +1876 		} else {
    +1877 			var dialog = new xq.controls.FormDialog(
    +1878 				this,
    +1879 				xq.ui_templates.basicColorPickerDialog,
    +1880 				function(dialog) {},
    +1881 				function(data) {
    +1882 					this.focus();
    +1883 					
    +1884 					if(xq.Browser.isTrident) {
    +1885 						var rng = this.rdom.rng();
    +1886 						rng.moveToBookmark(bm);
    +1887 						rng.select();
    +1888 					}
    +1889 					
    +1890 					if(!data) return;
    +1891 					
    +1892 					this.handleForegroundColor(data.color);
    +1893 				}.bind(this)
    +1894 			);
    +1895 			
    +1896 			if(xq.Browser.isTrident) var bm = this.rdom.rng().getBookmark();
    +1897 			
    +1898 			dialog.show({position: 'centerOfEditor'});
    +1899 		}
    +1900 		return true;
    +1901 	},
    +1902 
    +1903 	/**
    +1904 	 * Applies superscription
    +1905 	 */	
    +1906 	handleSuperscription: function() {
    +1907 		this.rdom.applySuperscription();
    +1908 
    +1909 		var historyAdded = this.editHistory.onCommand();
    +1910 		this._fireOnCurrentContentChanged(this);
    +1911 
    +1912 		return true;
    +1913 	},
    +1914 	
    +1915 	/**
    +1916 	 * Applies subscription
    +1917 	 */	
    +1918 	handleSubscription: function() {
    +1919 		this.rdom.applySubscription();
    +1920 
    +1921 		var historyAdded = this.editHistory.onCommand();
    +1922 		this._fireOnCurrentContentChanged(this);
    +1923 
    +1924 		return true;
    +1925 	},
    +1926 	
    +1927 	/**
    +1928 	 * Change of wrap current block's tag
    +1929 	 */	
    +1930 	handleApplyBlock: function(tagName) {
    +1931 		if(this.rdom.hasSelection()) {
    +1932 			var blocks = this.rdom.getBlockElementsAtSelectionEdge(true, true);
    +1933 			if(blocks.first() != blocks.last()) {
    +1934 				var applied = this.rdom.applyTagIntoElements(tagName, blocks.first(), blocks.last());
    +1935 				this.rdom.selectBlocksBetween(applied.first(), applied.last());
    +1936 				
    +1937 				var historyAdded = this.editHistory.onCommand();
    +1938 				this._fireOnCurrentContentChanged(this);
    +1939 				
    +1940 				return true;
    +1941 			}
    +1942 		}
    +1943 		
    +1944 		var block = this.rdom.getCurrentBlockElement();
    +1945 		this.rdom.pushMarker();
    +1946 		var applied =
    +1947 			this.rdom.applyTagIntoElement(tagName, block) ||
    +1948 			block;
    +1949 		this.rdom.popMarker(true);
    +1950 
    +1951 		if(this.rdom.isEmptyBlock(applied)) {
    +1952 			this.rdom.correctEmptyElement(applied);
    +1953 			this.rdom.placeCaretAtStartOf(applied);
    +1954 		}
    +1955 		
    +1956 		var historyAdded = this.editHistory.onCommand();
    +1957 		this._fireOnCurrentContentChanged(this);
    +1958 		
    +1959 		return true;
    +1960 	},
    +1961 
    +1962 	/**
    +1963 	 * Inserts seperator (HR)
    +1964 	 */
    +1965 	handleSeparator: function() {
    +1966 		this.rdom.collapseSelection();
    +1967 		
    +1968 		var curBlock = this.rdom.getCurrentBlockElement();
    +1969 		var atStart = this.rdom.isCaretAtBlockStart();
    +1970 		if(this.rdom.tree.isBlockContainer(curBlock)) curBlock = this.rdom.wrapAllInlineOrTextNodesAs("P", curBlock, true)[0];
    +1971 		
    +1972 		this.rdom.insertNodeAt(this.rdom.createElement("HR"), curBlock, atStart ? "before" : "after");
    +1973 		this.rdom.placeCaretAtStartOf(curBlock);
    +1974 
    +1975 		// add undo history
    +1976 		var historyAdded = this.editHistory.onCommand();
    +1977 		this._fireOnCurrentContentChanged(this);
    +1978 		
    +1979 		return true;
    +1980 	},
    +1981 	
    +1982 	/**
    +1983 	 * Performs UNDO
    +1984 	 */
    +1985 	handleUndo: function() {
    +1986 		var performed = this.editHistory.undo();
    +1987 		this._fireOnCurrentContentChanged(this);
    +1988 		
    +1989 		var curBlock = this.rdom.getCurrentBlockElement();
    +1990 		if(!xq.Browser.isTrident && curBlock) {
    +1991 			curBlock.scrollIntoView(false);
    +1992 		}
    +1993 		return true;
    +1994 	},
    +1995 	
    +1996 	/**
    +1997 	 * Performs REDO
    +1998 	 */
    +1999 	handleRedo: function() {
    +2000 		var performed = this.editHistory.redo();
    +2001 		this._fireOnCurrentContentChanged(this);
    +2002 		
    +2003 		var curBlock = this.rdom.getCurrentBlockElement();
    +2004 		if(!xq.Browser.isTrident && curBlock) {
    +2005 			curBlock.scrollIntoView(false);
    +2006 		}
    +2007 		return true;
    +2008 	},
    +2009 	
    +2010 	
    +2011 	
    +2012 	_handleContextMenu: function(e) {
    +2013 		if (xq.Browser.isWebkit) {
    +2014 			if (e.metaKey || Event.isLeftClick(e)) return false;
    +2015 		} else if (e.shiftKey || e.ctrlKey || e.altKey) {
    +2016 			return false;
    +2017 		}
    +2018 		
    +2019 		var x=Event.pointerX(e);
    +2020 		var y=Event.pointerY(e);
    +2021 		var pos=Position.cumulativeOffset(this.getFrame());
    +2022 		x+=pos[0];
    +2023 		y+=pos[1];
    +2024 		this._contextMenuTargetElement = e.target || e.srcElement;
    +2025 		
    +2026 		//TODO: Safari on Windows doesn't work with context key(app key)
    +2027 		if (!x || !y || xq.Browser.isTrident) {
    +2028 			var pos = Position.cumulativeOffset(this._contextMenuTargetElement);
    +2029 			var posFrame = Position.cumulativeOffset(this.getFrame());
    +2030 			x = pos[0] + posFrame[0] - this.getDoc().documentElement.scrollLeft;
    +2031 			y = pos[1] + posFrame[1] - this.getDoc().documentElement.scrollTop;
    +2032 		}
    +2033 		
    +2034 		if (!xq.Browser.isTrident) {
    +2035 			var doc = this.getDoc();
    +2036 			var body = this.getBody();
    +2037 			
    +2038 			x -= doc.documentElement.scrollLeft;
    +2039 			y -= doc.documentElement.scrollTop;
    +2040 			
    +2041 			if (doc != body) {
    +2042 				x -= body.scrollLeft;
    +2043 				y -= body.scrollTop;
    +2044 			}
    +2045 		}
    +2046 		
    +2047 		for(var cmh in this.config.contextMenuHandlers) {
    +2048 			var stop = this.config.contextMenuHandlers[cmh].handler(this, this._contextMenuTargetElement, x, y);
    +2049 			if(stop) {
    +2050 				Event.stop(e);
    +2051 				return true;
    +2052 			}
    +2053 		}
    +2054 		
    +2055 		return false;
    +2056 	},
    +2057 	
    +2058 	showContextMenu: function(menuItems, x, y) {
    +2059 		if (!menuItems || menuItems.length <= 0) return;
    +2060 		
    +2061 		if (!this._contextMenuContainer) {
    +2062 			this._contextMenuContainer = this.doc.createElement('UL');
    +2063 			this._contextMenuContainer.className = 'xqContextMenu';
    +2064 			this._contextMenuContainer.style.display='none';
    +2065 			
    +2066 			Event.observe(this.doc, 'click', this._contextMenuClicked.bindAsEventListener(this));
    +2067 			Event.observe(this.rdom.getDoc(), 'click', this.hideContextMenu.bindAsEventListener(this));
    +2068 			
    +2069 			this.body.appendChild(this._contextMenuContainer);
    +2070 		} else {
    +2071 			while (this._contextMenuContainer.childNodes.length > 0)
    +2072 				this._contextMenuContainer.removeChild(this._contextMenuContainer.childNodes[0]);
    +2073 		}
    +2074 		
    +2075 		for (var i=0; i < menuItems.length; i++) {
    +2076 			menuItems[i]._node = this._addContextMenuItem(menuItems[i]);
    +2077 		}
    +2078 
    +2079 		this._contextMenuContainer.style.display='block';
    +2080 		this._contextMenuContainer.style.left=Math.min(Math.max(this.doc.body.scrollWidth, this.doc.documentElement.clientWidth)-this._contextMenuContainer.offsetWidth, x)+'px';
    +2081 		this._contextMenuContainer.style.top=Math.min(Math.max(this.doc.body.scrollHeight, this.doc.documentElement.clientHeight)-this._contextMenuContainer.offsetHeight, y)+'px';
    +2082 
    +2083 		this._contextMenuItems = menuItems;
    +2084 	},
    +2085 	
    +2086 	hideContextMenu: function() {
    +2087 		if (this._contextMenuContainer)
    +2088 			this._contextMenuContainer.style.display='none';
    +2089 	},
    +2090 	
    +2091 	_addContextMenuItem: function(item) {
    +2092 		if (!this._contextMenuContainer) throw "No conext menu container exists";
    +2093 		
    +2094 		var node = this.doc.createElement('LI');
    +2095 		if (item.disabled) node.className += ' disabled'; 
    +2096 		
    +2097 		if (item.title == '----') {
    +2098 			node.innerHTML = ' ';
    +2099 			node.className = 'separator';
    +2100 		} else {
    +2101 			if(item.handler) {
    +2102 				node.innerHTML = '<a href="javascript:;" onclick="return false;">'+(item.title.toString().escapeHTML())+'</a>';
    +2103 			} else {
    +2104 				node.innerHTML = (item.title.toString().escapeHTML());
    +2105 			}
    +2106 		}
    +2107 		
    +2108 		if(item.className) node.className = item.className;
    +2109 		
    +2110 		this._contextMenuContainer.appendChild(node);
    +2111 		
    +2112 		return node;
    +2113 	},
    +2114 	
    +2115 	_contextMenuClicked: function(e) {
    +2116 		this.hideContextMenu();
    +2117 		
    +2118 		if (!this._contextMenuContainer) return;
    +2119 		
    +2120 		var node = Event.findElement(e, 'LI');
    +2121 		if (!node || !this.rdom.tree.isDescendantOf(this._contextMenuContainer, node)) return;
    +2122 
    +2123 		for (var i=0; i < this._contextMenuItems.length; i++) {
    +2124 			if (this._contextMenuItems[i]._node == node) {
    +2125 				var handler = this._contextMenuItems[i].handler;
    +2126 				if (!this._contextMenuItems[i].disabled && handler) {
    +2127 					var xed = this;
    +2128 					var element = this._contextMenuTargetElement;
    +2129 					if(typeof handler == "function") {
    +2130 						handler(xed, element);
    +2131 					} else {
    +2132 						eval(handler);
    +2133 					}
    +2134 				}
    +2135 				break;
    +2136 			}
    +2137 		}
    +2138 	},
    +2139 	
    +2140 	/**
    +2141 	 * Inserts HTML template
    +2142 	 *
    +2143 	 * @param {String} html Template string. It should have single root element
    +2144 	 * @returns {Element} inserted element
    +2145 	 */
    +2146 	insertTemplate: function(html) {
    +2147 		return this.rdom.insertHtml(this._processTemplate(html));
    +2148 	},
    +2149 	
    +2150 	/**
    +2151 	 * Places given HTML template nearby target.
    +2152 	 *
    +2153 	 * @param {String} html Template string. It should have single root element
    +2154 	 * @param {Node} target Target node.
    +2155 	 * @param {String} where Possible values: "before", "start", "end", "after"
    +2156 	 *
    +2157 	 * @returns {Element} Inserted element.
    +2158 	 */
    +2159 	insertTemplateAt: function(html, target, where) {
    +2160 		return this.rdom.insertHtmlAt(this._processTemplate(html), target, where);
    +2161 	},
    +2162 	
    +2163 	_processTemplate: function(html) {
    +2164 		// apply template processors
    +2165 		var tps = $H(this.getTemplateProcessors()).values();
    +2166 		for(var i = 0; i < tps.length; i++) {
    +2167 			html = tps[i].handler(html);
    +2168 		}
    +2169 		
    +2170 		// remove all whitespace characters between block tags
    +2171 		return html = this.removeUnnecessarySpaces(html);
    +2172 	},
    +2173 	
    +2174 	
    +2175 	
    +2176 	/** @private */
    +2177 	_handleEnterAtEmptyBlock: function() {
    +2178 		var block = this.rdom.getCurrentBlockElement();
    +2179 		if(this.rdom.tree.isTableCell(block) && this.rdom.isFirstBlockOfBody(block)) {
    +2180 			block = this.rdom.insertNodeAt(this.rdom.makeEmptyParagraph(), this.rdom.getRoot(), "start");
    +2181 		} else {
    +2182 			block = 
    +2183 				this.rdom.outdentElement(block) ||
    +2184 				this.rdom.extractOutElementFromParent(block) ||
    +2185 				this.rdom.replaceTag("P", block) ||
    +2186 				this.rdom.insertNewBlockAround(block);
    +2187 		}
    +2188 		
    +2189 		this.rdom.placeCaretAtStartOf(block);
    +2190 		if(!xq.Browser.isTrident) block.scrollIntoView(false);
    +2191 	},
    +2192 	
    +2193 	/** @private */
    +2194 	_handleEnterAtEdge: function(atStart, forceInsertParagraph) {
    +2195 		var block = this.rdom.getCurrentBlockElement();
    +2196 		var blockToPlaceCaret;
    +2197 		
    +2198 		if(atStart && this.rdom.isFirstBlockOfBody(block)) {
    +2199 			blockToPlaceCaret = this.rdom.insertNodeAt(this.rdom.makeEmptyParagraph(), this.rdom.getRoot(), "start");
    +2200 		} else {
    +2201 			if(this.rdom.tree.isTableCell(block)) forceInsertParagraph = true;
    +2202 			var newBlock = this.rdom.insertNewBlockAround(block, atStart, forceInsertParagraph ? "P" : null);
    +2203 			blockToPlaceCaret = !atStart ? newBlock : newBlock.nextSibling;
    +2204 		}
    +2205 		
    +2206 		this.rdom.placeCaretAtStartOf(blockToPlaceCaret);
    +2207 		if(!xq.Browser.isTrident) blockToPlaceCaret.scrollIntoView(false);
    +2208 	}
    +2209 });
    \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_06.html b/modules/editor/skins/xquared/doc/api/src_06.html new file mode 100644 index 000000000..32b20a15b --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/src_06.html @@ -0,0 +1,2262 @@ +
      1 /**
    +  2  * Encapsulates browser incompatibility problem and provides rich set of DOM manipulation API.
    +  3  *
    +  4  * RichDom provides basic CRUD + Advanced DOM manipulation API, various query methods and caret/selection management API
    +  5  */
    +  6 xq.RichDom = Class.create({
    +  7 	/**
    +  8 	 * Initialize RichDom. Target window and root element should be set after initialization. See setWin and setRoot.
    +  9 	 *
    + 10      * @constructor
    + 11 	 */
    + 12 	initialize: function() {
    + 13 		/**
    + 14 		 * {xq.DomTree} instance of DomTree
    + 15 		 */
    + 16 		this.tree = new xq.DomTree();
    + 17 		
    + 18 		this._lastMarkerId = 0;
    + 19 	},
    + 20 	
    + 21 	
    + 22 	
    + 23 	/**
    + 24 	 * @param {Window} win Browser's window object
    + 25 	 */
    + 26 	setWin: function(win) {
    + 27 		if(!win) throw "[win] is null";
    + 28 		this.win = win;
    + 29 	},
    + 30 	
    + 31 	/**
    + 32 	 * @param {Element} root Root element
    + 33 	 */
    + 34 	setRoot: function(root) {
    + 35 		if(!root) throw "[root] is null";
    + 36 		if(this.win && (root.ownerDocument != this.win.document)) throw "root.ownerDocument != this.win.document";
    + 37 		this.root = root;
    + 38 		this.doc = this.root.ownerDocument;
    + 39 	},
    + 40 	
    + 41 	/**
    + 42 	 * @returns Browser's window object.
    + 43 	 */
    + 44 	getWin: function() {return this.win},
    + 45 	
    + 46 	/**
    + 47 	 * @returns Document object of root element.
    + 48 	 */
    + 49 	getDoc: function() {return this.doc},
    + 50 	
    + 51 	/**
    + 52 	 * @returns Root element.
    + 53 	 */
    + 54 	getRoot: function() {return this.root},
    + 55 	
    + 56 	
    + 57 	
    + 58 	/////////////////////////////////////////////
    + 59 	// CRUDs
    + 60 	
    + 61 	clearRoot: function() {
    + 62 		this.root.innerHTML = "";
    + 63 		this.root.appendChild(this.makeEmptyParagraph());
    + 64 	},
    + 65 	
    + 66 	/**
    + 67 	 * Removes place holders and empty text nodes of given element.
    + 68 	 *
    + 69 	 * @param {Element} element target element
    + 70 	 */
    + 71 	removePlaceHoldersAndEmptyNodes: function(element) {
    + 72 		var children = element.childNodes;
    + 73 		if(!children) return;
    + 74 		var stopAt = this.getBottommostLastChild(element);
    + 75 		if(!stopAt) return;
    + 76 		stopAt = this.tree.walkForward(stopAt);
    + 77 		
    + 78 		while(true) {
    + 79 			if(!element || element == stopAt) break;
    + 80 			
    + 81 			if(
    + 82 				this.isPlaceHolder(element) ||
    + 83 				(element.nodeType == 3 && element.nodeValue == "") ||
    + 84 				(!this.getNextSibling(element) && element.nodeType == 3 && element.nodeValue.strip() == "")
    + 85 			) {
    + 86 				var deleteTarget = element;
    + 87 				element = this.tree.walkForward(element);
    + 88 				
    + 89 				this.deleteNode(deleteTarget);
    + 90 			} else {
    + 91 				element = this.tree.walkForward(element);
    + 92 			}
    + 93 		}
    + 94 	},
    + 95 	
    + 96 	/**
    + 97 	 * Sets multiple attributes into element at once
    + 98 	 *
    + 99 	 * @param {Element} element target element
    +100 	 * @param {Object} map key-value pairs
    +101 	 */
    +102 	setAttributes: function(element, map) {
    +103 		for(key in map) element.setAttribute(key, map[key]);
    +104 	},
    +105 
    +106 	/**
    +107 	 * Creates textnode by given node value.
    +108 	 *
    +109 	 * @param {String} value value of textnode
    +110 	 * @returns {Node} Created text node
    +111 	 */	
    +112 	createTextNode: function(value) {return this.doc.createTextNode(value);},
    +113 
    +114 	/**
    +115 	 * Creates empty element by given tag name.
    +116 	 *
    +117 	 * @param {String} tagName name of tag
    +118 	 * @returns {Element} Created element
    +119 	 */	
    +120 	createElement: function(tagName) {return this.doc.createElement(tagName);},
    +121 
    +122 	/**
    +123 	 * Creates element from HTML string
    +124 	 * 
    +125 	 * @param {String} html HTML string
    +126 	 * @returns {Element} Created element
    +127 	 */
    +128 	createElementFromHtml: function(html) {
    +129 		var node = this.createElement("div");
    +130 		node.innerHTML = html;
    +131 		if(node.childNodes.length != 1) {
    +132 			throw "Illegal HTML fragment";
    +133 		}
    +134 		return this.getFirstChild(node);
    +135 	},
    +136 	
    +137 	/**
    +138 	 * Deletes node from DOM tree.
    +139 	 *
    +140 	 * @param {Node} node Target node which should be deleted
    +141 	 * @param {boolean} deleteEmptyParentsRecursively Recursively delete empty parent elements
    +142 	 * @param {boolean} correctEmptyParent Call #correctEmptyElement on empty parent element after deletion
    +143 	 */	
    +144 	deleteNode: function(node, deleteEmptyParentsRecursively, correctEmptyParent) {
    +145 		if(!node || !node.parentNode) return;
    +146 		
    +147 		var parent = node.parentNode;
    +148 		parent.removeChild(node);
    +149 		
    +150 		if(deleteEmptyParentsRecursively) {
    +151 			while(!parent.hasChildNodes()) {
    +152 				node = parent;
    +153 				parent = node.parentNode;
    +154 				if(!parent || this.getRoot() == node) break;
    +155 				parent.removeChild(node);
    +156 			}
    +157 		}
    +158 		
    +159 		if(correctEmptyParent && this.isEmptyBlock(parent)) {
    +160 			parent.innerHTML = "";
    +161 			this.correctEmptyElement(parent);
    +162 		}
    +163 	},
    +164 
    +165 	/**
    +166 	 * Inserts given node into current caret position
    +167 	 *
    +168 	 * @param {Node} node Target node
    +169 	 * @returns {Node} Inserted node. It could be different with given node.
    +170 	 */
    +171 	insertNode: function(node) {throw "Not implemented"},
    +172 
    +173 	/**
    +174 	 * Inserts given html into current caret position
    +175 	 *
    +176 	 * @param {String} html HTML string
    +177 	 * @returns {Node} Inserted node. It could be different with given node.
    +178 	 */
    +179 	insertHtml: function(html) {
    +180 		return this.insertNode(this.createElementFromHtml(html));
    +181 	},
    +182 	
    +183 	/**
    +184 	 * Creates textnode from given text and inserts it into current caret position
    +185 	 *
    +186 	 * @param {String} text Value of textnode
    +187 	 * @returns {Node} Inserted node
    +188 	 */
    +189 	insertText: function(text) {
    +190 		this.insertNode(this.createTextNode(text));
    +191 	},
    +192 	
    +193 	/**
    +194 	 * Places given node nearby target.
    +195 	 *
    +196 	 * @param {Node} node Node to be inserted.
    +197 	 * @param {Node} target Target node.
    +198 	 * @param {String} where Possible values: "before", "start", "end", "after"
    +199 	 * @param {boolean} performValidation Validate node if needed. For example when P placed into UL, its tag name automatically replaced with LI
    +200 	 *
    +201 	 * @returns {Node} Inserted node. It could be different with given node.
    +202 	 */
    +203 	insertNodeAt: function(node, target, where, performValidation) {
    +204 		if(
    +205 			["HTML", "HEAD"].include(target.nodeName) ||
    +206 			["BODY"].include(target.nodeName) && ["before", "after"].include(where)
    +207 		) throw "Illegal argument. Cannot move node[" + node.nodeName + "] to '" + where + "' of target[" + target.nodeName + "]"
    +208 		
    +209 		var object;
    +210 		var message;
    +211 		var secondParam;
    +212 		
    +213 		switch(where.toLowerCase()) {
    +214 			case "before":
    +215 				object = target.parentNode;
    +216 				message = 'insertBefore';
    +217 				secondParam = target;
    +218 				break
    +219 			case "start":
    +220 				if(target.firstChild) {
    +221 					object = target;
    +222 					message = 'insertBefore';
    +223 					secondParam = target.firstChild;
    +224 				} else {
    +225 					object = target;
    +226 					message = 'appendChild';
    +227 				}
    +228 				break
    +229 			case "end":
    +230 				object = target;
    +231 				message = 'appendChild';
    +232 				break
    +233 			case "after":
    +234 				if(target.nextSibling) {
    +235 					object = target.parentNode;
    +236 					message = 'insertBefore';
    +237 					secondParam = target.nextSibling;
    +238 				} else {
    +239 					object = target.parentNode;
    +240 					message = 'appendChild';
    +241 				}
    +242 				break
    +243 		}
    +244 
    +245 		if(performValidation && this.tree.isListContainer(object) && node.nodeName != "LI") {
    +246 			var li = this.createElement("LI");
    +247 			li.appendChild(node);
    +248 			node = li;
    +249 			object[message](node, secondParam);		
    +250 		} else if(performValidation && !this.tree.isListContainer(object) && node.nodeName == "LI") {
    +251 			this.wrapAllInlineOrTextNodesAs("P", node, true);
    +252 			var div = this.createElement("DIV");
    +253 			this.moveChildNodes(node, div);
    +254 			this.deleteNode(node);
    +255 			object[message](div, secondParam);
    +256 			node = this.unwrapElement(div, true);
    +257 		} else {
    +258 			object[message](node, secondParam);
    +259 		}
    +260 		
    +261 		return node;
    +262 	},
    +263 
    +264 	/**
    +265 	 * Creates textnode from given text and places given node nearby target.
    +266 	 *
    +267 	 * @param {String} text Text to be inserted.
    +268 	 * @param {Node} target Target node.
    +269 	 * @param {String} where Possible values: "before", "start", "end", "after"
    +270 	 *
    +271 	 * @returns {Node} Inserted node.
    +272 	 */
    +273 	insertTextAt: function(text, target, where) {
    +274 		return this.insertNodeAt(this.createTextNode(text), target, where);
    +275 	},
    +276 
    +277 	/**
    +278 	 * Creates element from given HTML string and places given it nearby target.
    +279 	 *
    +280 	 * @param {String} html HTML to be inserted.
    +281 	 * @param {Node} target Target node.
    +282 	 * @param {String} where Possible values: "before", "start", "end", "after"
    +283 	 *
    +284 	 * @returns {Node} Inserted node.
    +285 	 */
    +286 	insertHtmlAt: function(html, target, where) {
    +287 		return this.insertNodeAt(this.createElementFromHtml(html), target, where);
    +288 	},
    +289 
    +290 	/**
    +291 	 * Replaces element's tag by removing current element and creating new element by given tag name.
    +292 	 *
    +293 	 * @param {String} tag New tag name
    +294 	 * @param {Element} element Target element
    +295 	 *
    +296 	 * @returns {Element} Replaced element
    +297 	 */	
    +298 	replaceTag: function(tag, element) {
    +299 		if(element.nodeName == tag) return null;
    +300 		if(this.tree.isTableCell(element)) return null;
    +301 		
    +302 		var newElement = this.createElement(tag);
    +303 		this.moveChildNodes(element, newElement);
    +304 		this.copyAttributes(element, newElement, true);
    +305 		element.parentNode.replaceChild(newElement, element);
    +306 		
    +307 		if(!newElement.hasChildNodes()) this.correctEmptyElement(newElement);
    +308 		
    +309 		return newElement;
    +310 	},
    +311 
    +312 	/**
    +313 	 * Unwraps unnecessary paragraph.
    +314 	 *
    +315 	 * Unnecessary paragraph is P which is the only child of given container element.
    +316 	 * For example, P which is contained by LI and is the only child is the unnecessary paragraph.
    +317 	 * But if given container element is a block-only-container(BLOCKQUOTE, BODY), this method does nothing.
    +318 	 *
    +319 	 * @param {Element} element Container element
    +320 	 * @returns {boolean} True if unwrap performed.
    +321 	 */
    +322 	unwrapUnnecessaryParagraph: function(element) {
    +323 		if(!element) return false;
    +324 		
    +325 		if(!this.tree.isBlockOnlyContainer(element) && element.childNodes.length == 1 && element.firstChild.nodeName == "P" && !this.hasImportantAttributes(element.firstChild)) {
    +326 			var p = element.firstChild;
    +327 			this.moveChildNodes(p, element);
    +328 			this.deleteNode(p);
    +329 			return true;
    +330 		}
    +331 		return false;
    +332 	},
    +333 	
    +334 	/**
    +335 	 * Unwraps element by extracting all children out and removing the element.
    +336 	 *
    +337 	 * @param {Element} element Target element
    +338 	 * @param {boolean} wrapInlineAndTextNodes Wrap all inline and text nodes with P before unwrap
    +339 	 * @returns {Node} First child of unwrapped element
    +340 	 */
    +341 	unwrapElement: function(element, wrapInlineAndTextNodes) {
    +342 		if(wrapInlineAndTextNodes) this.wrapAllInlineOrTextNodesAs("P", element);
    +343 		
    +344 		var nodeToReturn = element.firstChild;
    +345 		
    +346 		while(element.firstChild) this.insertNodeAt(element.firstChild, element, "before");
    +347 		this.deleteNode(element);
    +348 		
    +349 		return nodeToReturn;
    +350 	},
    +351 	
    +352 	/**
    +353 	 * Wraps element by given tag
    +354 	 *
    +355 	 * @param {String} tag tag name
    +356 	 * @param {Element} element target element to wrap
    +357 	 * @returns {Element} wrapper
    +358 	 */
    +359 	wrapElement: function(tag, element) {
    +360 		var wrapper = this.insertNodeAt(this.createElement(tag), element, "before");
    +361 		wrapper.appendChild(element);
    +362 		return wrapper;
    +363 	},
    +364 	
    +365 	/**
    +366 	 * Tests #smartWrap with given criteria but doesn't change anything
    +367 	 */
    +368 	testSmartWrap: function(endElement, criteria) {
    +369 		return this.smartWrap(endElement, null, criteria, true);
    +370 	},
    +371 	
    +372 	/**
    +373 	 * Create inline element with given tag name and wraps nodes nearby endElement by given criteria
    +374 	 *
    +375 	 * @param {Element} endElement Boundary(end point, exclusive) of wrapper.
    +376 	 * @param {String} tag Tag name of wrapper.
    +377 	 * @param {Object} function which returns text index of start boundary.
    +378 	 * @param {boolean} testOnly just test boundary and do not perform actual wrapping.
    +379 	 *
    +380 	 * @returns {Element} wrapper
    +381 	 */
    +382 	smartWrap: function(endElement, tag, criteria, testOnly) {
    +383 		var block = this.getParentBlockElementOf(endElement);
    +384 
    +385 		tag = tag || "SPAN";
    +386 		criteria = criteria || function(text) {return -1};
    +387 		
    +388 		// check for empty wrapper
    +389 		if(!testOnly && (!endElement.previousSibling || this.isEmptyBlock(block))) {
    +390 			var wrapper = this.insertNodeAt(this.createElement(tag), endElement, "before");
    +391 			return wrapper;
    +392 		}
    +393 		
    +394 		// collect all textnodes
    +395 		var textNodes = this.tree.collectForward(block, function(node) {return node == endElement}, function(node) {return node.nodeType == 3});
    +396 		
    +397 		// find textnode and break-point
    +398 		var nodeIndex = 0;
    +399 		var nodeValues = textNodes.pluck("nodeValue");
    +400 		var textToWrap = nodeValues.join("");
    +401 		var textIndex = criteria(textToWrap)
    +402 		var breakPoint = textIndex;
    +403 		
    +404 		if(breakPoint == -1) {
    +405 			breakPoint = 0;
    +406 		} else {
    +407 			textToWrap = textToWrap.substring(breakPoint);
    +408 		}
    +409 		
    +410 		for(var i = 0; i < textNodes.length; i++) {
    +411 			if(breakPoint > nodeValues[i].length) {
    +412 				breakPoint -= nodeValues[i].length;
    +413 			} else {
    +414 				nodeIndex = i;
    +415 				break;
    +416 			}
    +417 		}
    +418 		
    +419 		if(testOnly) return {text:textToWrap, textIndex:textIndex, nodeIndex:nodeIndex, breakPoint:breakPoint};
    +420 		
    +421 		// break textnode if necessary 
    +422 		if(breakPoint != 0) {
    +423 			var splitted = textNodes[nodeIndex].splitText(breakPoint);
    +424 			nodeIndex++;
    +425 			textNodes.splice(nodeIndex, 0, splitted);
    +426 		}
    +427 		var startElement = textNodes[nodeIndex] || block.firstChild;
    +428 		
    +429 		// split inline elements up to parent block if necessary
    +430 		var family = this.tree.findCommonAncestorAndImmediateChildrenOf(startElement, endElement);
    +431 		var ca = family.parent;
    +432 		if(ca) {
    +433 			if(startElement.parentNode != ca) startElement = this.splitElementUpto(startElement, ca, true);
    +434 			if(endElement.parentNode != ca) endElement = this.splitElementUpto(endElement, ca, true);
    +435 			
    +436 			var prevStart = startElement.previousSibling;
    +437 			var nextEnd = endElement.nextSibling;
    +438 			
    +439 			// remove empty inline elements
    +440 			if(prevStart && prevStart.nodeType == 1 && this.isEmptyBlock(prevStart)) this.deleteNode(prevStart);
    +441 			if(nextEnd && nextEnd.nodeType == 1 && this.isEmptyBlock(nextEnd)) this.deleteNode(nextEnd);
    +442 			
    +443 			// wrap
    +444 			var wrapper = this.insertNodeAt(this.createElement(tag), startElement, "before");
    +445 			while(wrapper.nextSibling != endElement) wrapper.appendChild(wrapper.nextSibling);
    +446 			return wrapper;
    +447 		} else {
    +448 			// wrap
    +449 			var wrapper = this.insertNodeAt(this.createElement(tag), endElement, "before");
    +450 			return wrapper;
    +451 		}
    +452 	},
    +453 	
    +454 	/**
    +455 	 * Wraps all adjust inline elements and text nodes into block element.
    +456 	 *
    +457 	 * TODO: empty element should return empty array when it is not forced and (at least) single item array when forced
    +458 	 *
    +459 	 * @param {String} tag Tag name of wrapper
    +460 	 * @param {Element} element Target element
    +461 	 * @param {boolean} force Force wrapping. If it is set to false, this method do not makes unnecessary wrapper.
    +462 	 *
    +463 	 * @returns {Array} Array of wrappers. If nothing performed it returns empty array
    +464 	 */
    +465 	wrapAllInlineOrTextNodesAs: function(tag, element, force) {
    +466 		var wrappers = [];
    +467 		
    +468 		if(!force && !this.tree.hasMixedContents(element)) return wrappers;
    +469 		
    +470 		var node = element.firstChild;
    +471 		while(node) {
    +472 			if(this.tree.isTextOrInlineNode(node)) {
    +473 				var wrapper = this.wrapInlineOrTextNodesAs(tag, node);
    +474 				wrappers.push(wrapper);
    +475 				node = wrapper.nextSibling;
    +476 			} else {
    +477 				node = node.nextSibling;
    +478 			}
    +479 		}
    +480 
    +481 		return wrappers;
    +482 	},
    +483 
    +484 	/**
    +485 	 * Wraps node and its adjust next siblings into an element
    +486 	 */
    +487 	wrapInlineOrTextNodesAs: function(tag, node) {
    +488 		var wrapper = this.createElement(tag);
    +489 		var from = node;
    +490 
    +491 		from.parentNode.replaceChild(wrapper, from);
    +492 		wrapper.appendChild(from);
    +493 
    +494 		// move nodes into wrapper
    +495 		while(wrapper.nextSibling && this.tree.isTextOrInlineNode(wrapper.nextSibling)) wrapper.appendChild(wrapper.nextSibling);
    +496 
    +497 		return wrapper;
    +498 	},
    +499 	
    +500 	/**
    +501 	 * Turns block element into list item
    +502 	 *
    +503 	 * @param {Element} element Target element
    +504 	 * @param {String} type One of "UL", "OL", "CODE". "CODE" is same with "OL" but it gives "OL" a class name "code"
    +505 	 *
    +506 	 * @return {Element} LI element
    +507 	 */
    +508 	turnElementIntoListItem: function(element, type) {
    +509 		type = type.toUpperCase();
    +510 		
    +511 		var container = this.createElement(type == "UL" ? "UL" : "OL");
    +512 		if(type == "CODE") container.className = "code";
    +513 		
    +514 		if(this.tree.isTableCell(element)) {
    +515 			var p = this.wrapAllInlineOrTextNodesAs("P", element, true)[0];
    +516 			container = this.insertNodeAt(container, element, "start");
    +517 			var li = this.insertNodeAt(this.createElement("LI"), container, "start");
    +518 			li.appendChild(p);
    +519 		} else {
    +520 			container = this.insertNodeAt(container, element, "after");
    +521 			var li = this.insertNodeAt(this.createElement("LI"), container, "start");
    +522 			li.appendChild(element);
    +523 		}
    +524 		
    +525 		this.unwrapUnnecessaryParagraph(li);
    +526 		this.mergeAdjustLists(container);
    +527 		
    +528 		return li;
    +529 	},
    +530 	
    +531 	/**
    +532 	 * Extracts given element out from its parent element.
    +533 	 * 
    +534 	 * @param {Element} element Target element
    +535 	 */
    +536 	extractOutElementFromParent: function(element) {
    +537 		if(element == this.root || this.root == element.parentNode || !element.offsetParent) return null;
    +538 		
    +539 		if(element.nodeName == "LI") {
    +540 			this.wrapAllInlineOrTextNodesAs("P", element, true);
    +541 			element = element.firstChild;
    +542 		}
    +543 
    +544 		var container = element.parentNode;
    +545 		var nodeToReturn = null;
    +546 		
    +547 		if(container.nodeName == "LI" && container.parentNode.parentNode.nodeName == "LI") {
    +548 			// nested list item
    +549 			if(element.previousSibling) {
    +550 				this.splitContainerOf(element, true);
    +551 				this.correctEmptyElement(element);
    +552 			}
    +553 			
    +554 			this.outdentListItem(element);
    +555 			nodeToReturn = element;
    +556 		} else if(container.nodeName == "LI") {
    +557 			// not-nested list item
    +558 			
    +559 			if(this.tree.isListContainer(element.nextSibling)) {
    +560 				// 1. split listContainer
    +561 				var listContainer = container.parentNode;
    +562 				this.splitContainerOf(container, true);
    +563 				this.correctEmptyElement(element);
    +564 				
    +565 				// 2. extract out LI's children
    +566 				nodeToReturn = container.firstChild;
    +567 				while(container.firstChild) {
    +568 					this.insertNodeAt(container.firstChild, listContainer, "before");
    +569 				}
    +570 				
    +571 				// 3. remove listContainer and merge adjust lists
    +572 				var prevContainer = listContainer.previousSibling;
    +573 				this.deleteNode(listContainer);
    +574 				if(prevContainer && this.tree.isListContainer(prevContainer)) this.mergeAdjustLists(prevContainer);
    +575 			} else {
    +576 				// 1. split LI
    +577 				this.splitContainerOf(element, true);
    +578 				this.correctEmptyElement(element);
    +579 				
    +580 				// 2. split list container
    +581 				var listContainer = this.splitContainerOf(container);
    +582 				
    +583 				// 3. extract out
    +584 				this.insertNodeAt(element, listContainer.parentNode, "before");
    +585 				this.deleteNode(listContainer.parentNode);
    +586 				
    +587 				nodeToReturn = element;
    +588 			}
    +589 		} else if(this.tree.isTableCell(container) || this.tree.isTableCell(element)) {
    +590 			// do nothing
    +591 		} else {
    +592 			// normal block
    +593 			this.splitContainerOf(element, true);
    +594 			this.correctEmptyElement(element);
    +595 			nodeToReturn = this.insertNodeAt(element, container, "before");
    +596 			
    +597 			this.deleteNode(container);
    +598 		}
    +599 		
    +600 		return nodeToReturn;
    +601 	},
    +602 	
    +603 	/**
    +604 	 * Insert new block above or below given element.
    +605 	 *
    +606 	 * @param {Element} block Target block
    +607 	 * @param {boolean} before Insert new block above(before) target block
    +608 	 * @param {String} forceTag New block's tag name. If omitted, target block's tag name will be used.
    +609 	 *
    +610 	 * @returns {Element} Inserted block
    +611 	 */
    +612 	insertNewBlockAround: function(block, before, forceTag) {
    +613 		var isListItem = block.nodeName == "LI" || block.parentNode.nodeName == "LI";
    +614 		
    +615 		this.removeTrailingWhitespace(block);
    +616 		if(this.isFirstLiWithNestedList(block) && !forceTag && before) {
    +617 			var li = this.getParentElementOf(block, ["LI"]);
    +618 			var newBlock = this._insertNewBlockAround(li, before);
    +619 			return newBlock;
    +620 		} else if(isListItem && !forceTag) {
    +621 			var li = this.getParentElementOf(block, ["LI"]);
    +622 			var newBlock = this._insertNewBlockAround(block, before);
    +623 			if(li != block) newBlock = this.splitContainerOf(newBlock, false, "prev");
    +624 			return newBlock;
    +625 		} else if(this.tree.isBlockContainer(block)) {
    +626 			this.wrapAllInlineOrTextNodesAs("P", block, true);
    +627 			return this._insertNewBlockAround(block.firstChild, before, forceTag);
    +628 		} else {
    +629 			return this._insertNewBlockAround(block, before, this.tree.isHeading(block) ? "P" : forceTag);
    +630 		}
    +631 	},
    +632 	
    +633 	/**
    +634 	 * @private
    +635 	 *
    +636 	 * TODO: Rename
    +637 	 */
    +638 	_insertNewBlockAround: function(element, before, tagName) {
    +639 		var newElement = this.createElement(tagName || element.nodeName);
    +640 		this.copyAttributes(element, newElement, false);
    +641 		this.correctEmptyElement(newElement);
    +642 		newElement = this.insertNodeAt(newElement, element, before ? "before" : "after");
    +643 		return newElement;
    +644 	},
    +645 	
    +646 	/**
    +647 	 * Wrap or replace element with given tag name.
    +648 	 *
    +649 	 * @param {String} tag Tag name
    +650 	 * @param {Element} element Target element
    +651 	 *
    +652 	 * @return {Element} wrapper element or replaced element.
    +653 	 */
    +654 	applyTagIntoElement: function(tag, element) {
    +655 		if(this.tree.isBlockOnlyContainer(tag)) {
    +656 			return this.wrapBlock(tag, element);
    +657 		} else if(this.tree.isBlockContainer(element)) {
    +658 			var wrapper = this.createElement(tag);
    +659 			this.moveChildNodes(element, wrapper);
    +660 			return this.insertNodeAt(wrapper, element, "start");
    +661 		} else {
    +662 			if(this.tree.isBlockContainer(tag) && this.hasImportantAttributes(element)) {
    +663 				return this.wrapBlock(tag, element);
    +664 			} else {
    +665 				return this.replaceTag(tag, element);
    +666 			}
    +667 		}
    +668 		
    +669 		throw "IllegalArgumentException - [" + tag + ", " + element + "]";
    +670 	},
    +671 	
    +672 	/**
    +673 	 * Wrap or replace elements with given tag name.
    +674 	 *
    +675 	 * @param {String} tag Tag name
    +676 	 * @param {Element} from Start boundary (inclusive)
    +677 	 * @param {Element} to End boundary (inclusive)
    +678 	 *
    +679 	 * @returns {Array} Array of wrappers or replaced elements
    +680 	 */
    +681 	applyTagIntoElements: function(tagName, from, to) {
    +682 		var applied = [];
    +683 		
    +684 		if(this.tree.isBlockContainer(tagName)) {
    +685 			var family = this.tree.findCommonAncestorAndImmediateChildrenOf(from, to);
    +686 			var node = family.left;
    +687 			var wrapper = this.insertNodeAt(this.createElement(tagName), node, "before");
    +688 			
    +689 			var coveringWholeList =
    +690 				family.parent.nodeName == "LI" &&
    +691 				family.parent.parentNode.childNodes.length == 1 &&
    +692 				!family.left.previousSilbing &&
    +693 				!family.right.nextSibling;
    +694 				
    +695 			if(coveringWholeList) {
    +696 				var ul = node.parentNode.parentNode;
    +697 				this.insertNodeAt(wrapper, ul, "before");
    +698 				wrapper.appendChild(ul);
    +699 			} else {
    +700 				while(node != family.right) {
    +701 					next = node.nextSibling;
    +702 					wrapper.appendChild(node);
    +703 					node = next;
    +704 				}
    +705 				wrapper.appendChild(family.right);
    +706 			}
    +707 			applied.push(wrapper);
    +708 		} else {
    +709 			// is normal tagName
    +710 			var elements = this.getBlockElementsBetween(from, to);
    +711 			for(var i = 0; i < elements.length; i++) {
    +712 				if(this.tree.isBlockContainer(elements[i])) {
    +713 					applied.push(this.wrapAllInlineOrTextNodesAs(tagName, elements[i], true));
    +714 				} else {
    +715 					applied.push(this.replaceTag(tagName, elements[i]));
    +716 				}
    +717 			}
    +718 		}
    +719 		return applied.flatten();
    +720 	},
    +721 	
    +722 	/**
    +723 	 * Moves block up or down
    +724 	 *
    +725 	 * @param {Element} block Target block
    +726 	 * @param {boolean} up Move up if true
    +727 	 * 
    +728 	 * @returns {Element} Moved block. It could be different with given block.
    +729 	 */
    +730 	moveBlock: function(block, up) {
    +731 		// if block is table cell or contained by table cell, select its row as mover
    +732 		block = this.getParentElementOf(block, ["TR"]) || block;
    +733 		
    +734 		// if block is only child, select its parent as mover
    +735 		while(block.nodeName != "TR" && block.parentNode != this.getRoot() && !block.previousSibling && !block.nextSibling && !this.tree.isListContainer(block.parentNode)) {
    +736 			block = block.parentNode;
    +737 		}
    +738 		
    +739 		// find target and where
    +740 		var target, where;
    +741 		if (up) {
    +742 			target = block.previousSibling;
    +743 			
    +744 			if(target) {
    +745 				var singleNodeLi = target.nodeName == 'LI' && ((target.childNodes.length == 1 && this.tree.isBlock(target.firstChild)) || !this.tree.hasBlocks(target));
    +746 				var table = ['TABLE', 'TR'].include(target.nodeName);
    +747 
    +748 				where = this.tree.isBlockContainer(target) && !singleNodeLi && !table ? "end" : "before";
    +749 			} else if(block.parentNode != this.getRoot()) {
    +750 				target = block.parentNode;
    +751 				where = "before";
    +752 			}
    +753 		} else {
    +754 			target = block.nextSibling;
    +755 			
    +756 			if(target) {
    +757 				var singleNodeLi = target.nodeName == 'LI' && ((target.childNodes.length == 1 && this.tree.isBlock(target.firstChild)) || !this.tree.hasBlocks(target));
    +758 				var table = ['TABLE', 'TR'].include(target.nodeName);
    +759 				
    +760 				where = this.tree.isBlockContainer(target) && !singleNodeLi && !table ? "start" : "after";
    +761 			} else if(block.parentNode != this.getRoot()) {
    +762 				target = block.parentNode;
    +763 				where = "after";
    +764 			}
    +765 		}
    +766 		
    +767 		
    +768 		// no way to go?
    +769 		if(!target) return null;
    +770 		if(["TBODY", "THEAD"].include(target.nodeName)) return null;
    +771 		
    +772 		// normalize
    +773 		this.wrapAllInlineOrTextNodesAs("P", target, true);
    +774 		
    +775 		// make placeholder if needed
    +776 		if(this.isFirstLiWithNestedList(block)) {
    +777 			this.insertNewBlockAround(block, false, "P");
    +778 		}
    +779 		
    +780 		// perform move
    +781 		var parent = block.parentNode;
    +782 		var moved = this.insertNodeAt(block, target, where, true);
    +783 		
    +784 		// cleanup
    +785 		if(!parent.hasChildNodes()) this.deleteNode(parent, true);
    +786 		this.unwrapUnnecessaryParagraph(moved);
    +787 		this.unwrapUnnecessaryParagraph(target);
    +788 
    +789 		// remove placeholder
    +790 		if(up) {
    +791 			if(moved.previousSibling && this.isEmptyBlock(moved.previousSibling) && !moved.previousSibling.previousSibling && moved.parentNode.nodeName == "LI" && this.tree.isListContainer(moved.nextSibling)) {
    +792 				this.deleteNode(moved.previousSibling);
    +793 			}
    +794 		} else {
    +795 			if(moved.nextSibling && this.isEmptyBlock(moved.nextSibling) && !moved.previousSibling && moved.parentNode.nodeName == "LI" && this.tree.isListContainer(moved.nextSibling.nextSibling)) {
    +796 				this.deleteNode(moved.nextSibling);
    +797 			}
    +798 		}
    +799 		
    +800 		return moved;
    +801 	},
    +802 	
    +803 	/**
    +804 	 * Remove given block
    +805 	 *
    +806 	 * @param {Element} block Target block
    +807 	 * @returns {Element} Nearest block of remove element
    +808 	 */
    +809 	removeBlock: function(block) {
    +810 		var blockToMove;
    +811 
    +812 		// if block is only child, select its parent as mover
    +813 		while(block.parentNode != this.getRoot() && !block.previousSibling && !block.nextSibling && !this.tree.isListContainer(block.parentNode)) {
    +814 			block = block.parentNode;
    +815 		}
    +816 		
    +817 		var finder = function(node) {return this.tree.isBlock(node) && !this.tree.isAtomic(node) && !this.tree.isDescendantOf(block, node) && !this.tree.hasBlocks(node);}.bind(this);
    +818 		var exitCondition = function(node) {return this.tree.isBlock(node) && !this.tree.isDescendantOf(this.getRoot(), node)}.bind(this);
    +819 		
    +820 		if(this.isFirstLiWithNestedList(block)) {
    +821 			blockToMove = this.outdentListItem(block.nextSibling.firstChild);
    +822 			this.deleteNode(blockToMove.previousSibling, true);
    +823 		} else if(this.tree.isTableCell(block)) {
    +824 			var rtable = new xq.RichTable(this, this.getParentElementOf(block, ["TABLE"]));
    +825 			blockToMove = rtable.getBelowCellOf(block);
    +826 			
    +827 			// should not delete row when there's thead and the row is the only child of tbody
    +828 			if(
    +829 				block.parentNode.parentNode.nodeName == "TBODY" &&
    +830 				rtable.hasHeadingAtTop() &&
    +831 				rtable.getDom().tBodies[0].rows.length == 1) return blockToMove;
    +832 			
    +833 			blockToMove = blockToMove ||
    +834 				this.tree.findForward(block, finder, exitCondition) ||
    +835 				this.tree.findBackward(block, finder, exitCondition);
    +836 			
    +837 			this.deleteNode(block.parentNode, true);
    +838 		} else {
    +839 			blockToMove = blockToMove ||
    +840 				this.tree.findForward(block, finder, exitCondition) ||
    +841 				this.tree.findBackward(block, finder, exitCondition);
    +842 			
    +843 			if(!blockToMove) blockToMove = this.insertNodeAt(this.makeEmptyParagraph(), block, "after");
    +844 			
    +845 			this.deleteNode(block, true);
    +846 		}
    +847 		if(!this.getRoot().hasChildNodes()) {
    +848 			blockToMove = this.createElement("P");
    +849 			this.getRoot().appendChild(blockToMove);
    +850 			this.correctEmptyElement(blockToMove);
    +851 		}
    +852 		
    +853 		return blockToMove;
    +854 	},
    +855 	
    +856 	/**
    +857 	 * Removes trailing whitespaces of given block
    +858 	 *
    +859 	 * @param {Element} block Target block
    +860 	 */
    +861 	removeTrailingWhitespace: function(block) {throw "Not implemented"},
    +862 	
    +863 	/**
    +864 	 * Extract given list item out and change its container's tag
    +865 	 *
    +866 	 * @param {Element} element LI or P which is a child of LI
    +867 	 * @param {String} type "OL", "UL", or "CODE"
    +868 	 *
    +869 	 * @returns {Element} changed element
    +870 	 */
    +871 	changeListTypeTo: function(element, type) {
    +872 		type = type.toUpperCase();
    +873 		
    +874 		var li = this.getParentElementOf(element, ["LI"]);
    +875 		if(!li) throw "IllegalArgumentException";
    +876 		
    +877 		var container = li.parentNode;
    +878 
    +879 		this.splitContainerOf(li);
    +880 		
    +881 		var newContainer = this.insertNodeAt(this.createElement(type == "UL" ? "UL" : "OL"), container, "before");
    +882 		if(type == "CODE") newContainer.className = "code";
    +883 		
    +884 		this.insertNodeAt(li, newContainer, "start");
    +885 		this.deleteNode(container);
    +886 		
    +887 		this.mergeAdjustLists(newContainer);
    +888 		
    +889 		return element;
    +890 	},
    +891 	
    +892 	/**
    +893 	 * Split container of element into (maxium) three pieces.
    +894 	 */
    +895 	splitContainerOf: function(element, preserveElementItself, dir) {
    +896 		if([element, element.parentNode].include(this.getRoot())) return element;
    +897 
    +898 		var container = element.parentNode;
    +899 		if(element.previousSibling && (!dir || dir.toLowerCase() == "prev")) {
    +900 			var prev = this.createElement(container.nodeName);
    +901 			this.copyAttributes(container, prev);
    +902 			while(container.firstChild != element) {
    +903 				prev.appendChild(container.firstChild);
    +904 			}
    +905 			this.insertNodeAt(prev, container, "before");
    +906 			this.unwrapUnnecessaryParagraph(prev);
    +907 		}
    +908 		
    +909 		if(element.nextSibling && (!dir || dir.toLowerCase() == "next")) {
    +910 			var next = this.createElement(container.nodeName);
    +911 			this.copyAttributes(container, next);
    +912 			while(container.lastChild != element) {
    +913 				this.insertNodeAt(container.lastChild, next, "start");
    +914 			}
    +915 			this.insertNodeAt(next, container, "after");
    +916 			this.unwrapUnnecessaryParagraph(next);
    +917 		}
    +918 		
    +919 		if(!preserveElementItself) element = this.unwrapUnnecessaryParagraph(container) ? container : element;
    +920 		return element;
    +921 	},
    +922 
    +923 	/**
    +924 	 * TODO: Add specs
    +925 	 */
    +926 	splitParentElement: function(seperator) {
    +927 		var parent = seperator.parentNode;
    +928 		if(["HTML", "HEAD", "BODY"].include(parent.nodeName)) throw "Illegal argument. Cannot seperate element[" + parent.nodeName + "]";
    +929 
    +930 		var previousSibling = seperator.previousSibling;
    +931 		var nextSibling = seperator.nextSibling;
    +932 		
    +933 		var newElement = this.insertNodeAt(this.createElement(parent.nodeName), parent, "after");
    +934 		
    +935 		var next;
    +936 		while(next = seperator.nextSibling) newElement.appendChild(next);
    +937 		
    +938 		this.insertNodeAt(seperator, newElement, "start");
    +939 		this.copyAttributes(parent, newElement);
    +940 		
    +941 		return newElement;
    +942 	},
    +943 	
    +944 	/**
    +945 	 * TODO: Add specs
    +946 	 */
    +947 	splitElementUpto: function(seperator, element, excludeElement) {
    +948 		while(seperator.previousSibling != element) {
    +949 			if(excludeElement && seperator.parentNode == element) break;
    +950 			seperator = this.splitParentElement(seperator);
    +951 		}
    +952 		return seperator;
    +953 	},
    +954 	
    +955 	/**
    +956 	 * Merges two adjust elements
    +957 	 *
    +958 	 * @param {Element} element base element
    +959 	 * @param {boolean} withNext merge base element with next sibling
    +960 	 * @param {boolean} skip skip merge steps
    +961 	 */
    +962 	mergeElement: function(element, withNext, skip) {
    +963 		this.wrapAllInlineOrTextNodesAs("P", element.parentNode, true);
    +964 		
    +965 		// find two block
    +966 		if(withNext) {
    +967 			var prev = element;
    +968 			var next = this.tree.findForward(
    +969 				element,
    +970 				function(node) {return this.tree.isBlock(node) && !this.tree.isListContainer(node) && node != element.parentNode}.bind(this)
    +971 			);
    +972 		} else {
    +973 			var next = element;
    +974 			var prev = this.tree.findBackward(
    +975 				element,
    +976 				function(node) {return this.tree.isBlock(node) && !this.tree.isListContainer(node) && node != element.parentNode}.bind(this)
    +977 			);
    +978 		}
    +979 		
    +980 		// normalize next block
    +981 		if(next && this.tree.isDescendantOf(this.getRoot(), next)) {
    +982 			var nextContainer = next.parentNode;
    +983 			if(this.tree.isBlockContainer(next)) {
    +984 				nextContainer = next;
    +985 				this.wrapAllInlineOrTextNodesAs("P", nextContainer, true);
    +986 				next = nextContainer.firstChild;
    +987 			}
    +988 		} else {
    +989 			next = null;
    +990 		}
    +991 		
    +992 		// normalize prev block
    +993 		if(prev && this.tree.isDescendantOf(this.getRoot(), prev)) {
    +994 			var prevContainer = prev.parentNode;
    +995 			if(this.tree.isBlockContainer(prev)) {
    +996 				prevContainer = prev;
    +997 				this.wrapAllInlineOrTextNodesAs("P", prevContainer, true);
    +998 				prev = prevContainer.lastChild;
    +999 			}
    +1000 		} else {
    +1001 			prev = null;
    +1002 		}
    +1003 		
    +1004 		try {
    +1005 			var containersAreTableCell =
    +1006 				prevContainer && (this.tree.isTableCell(prevContainer) || ['TR', 'THEAD', 'TBODY'].include(prevContainer.nodeName)) &&
    +1007 				nextContainer && (this.tree.isTableCell(nextContainer) || ['TR', 'THEAD', 'TBODY'].include(nextContainer.nodeName));
    +1008 			
    +1009 			if(containersAreTableCell && prevContainer != nextContainer) return null;
    +1010 			
    +1011 			// if next has margin, perform outdent
    +1012 			if((!skip || !prev) && next && this.outdentElement(next)) return element;
    +1013 
    +1014 			// nextContainer is first li and next of it is list container
    +1015 			if(nextContainer && nextContainer.nodeName == 'LI' && this.tree.isListContainer(next.nextSibling)) {
    +1016 				this.extractOutElementFromParent(nextContainer);
    +1017 				return prev;
    +1018 			}
    +1019 			
    +1020 			// merge two list containers
    +1021 			if(nextContainer && nextContainer.nodeName == 'LI' && this.tree.isListContainer(nextContainer.parentNode.previousSibling)) {
    +1022 				this.mergeAdjustLists(nextContainer.parentNode.previousSibling, true, "next");
    +1023 				return prev;
    +1024 			}
    +1025 
    +1026 			if(next && !containersAreTableCell && prevContainer && prevContainer.nodeName == 'LI' && nextContainer && nextContainer.nodeName == 'LI' && prevContainer.parentNode.nextSibling == nextContainer.parentNode) {
    +1027 				var nextContainerContainer = nextContainer.parentNode;
    +1028 				this.moveChildNodes(nextContainer.parentNode, prevContainer.parentNode);
    +1029 				this.deleteNode(nextContainerContainer);
    +1030 				return prev;
    +1031 			}
    +1032 			
    +1033 			// merge two containers
    +1034 			if(next && !containersAreTableCell && prevContainer && prevContainer.nextSibling == nextContainer && ((skip && prevContainer.nodeName != "LI") || (!skip && prevContainer.nodeName == "LI"))) {
    +1035 				this.moveChildNodes(nextContainer, prevContainer);
    +1036 				return prev;
    +1037 			}
    +1038 
    +1039 			// unwrap container
    +1040 			if(nextContainer && nextContainer.nodeName != "LI" && !this.getParentElementOf(nextContainer, ["TABLE"]) && !this.tree.isListContainer(nextContainer) && nextContainer != this.getRoot() && !next.previousSibling) {
    +1041 				return this.unwrapElement(nextContainer, true);
    +1042 			}
    +1043 			
    +1044 			// delete table
    +1045 			if(withNext && nextContainer && nextContainer.nodeName == "TABLE") {
    +1046 				this.deleteNode(nextContainer, true);
    +1047 				return prev;
    +1048 			} else if(!withNext && prevContainer && this.tree.isTableCell(prevContainer) && !this.tree.isTableCell(nextContainer)) {
    +1049 				this.deleteNode(this.getParentElementOf(prevContainer, ["TABLE"]), true);
    +1050 				return next;
    +1051 			}
    +1052 			
    +1053 			// if prev is same with next, do nothing
    +1054 			if(prev == next) return null;
    +1055 
    +1056 			// if there is a null block, do nothing
    +1057 			if(!prev || !next || !prevContainer || !nextContainer) return null;
    +1058 			
    +1059 			// if two blocks are not in the same table cell, do nothing
    +1060 			if(this.getParentElementOf(prev, ["TD", "TH"]) != this.getParentElementOf(next, ["TD", "TH"])) return null;
    +1061 			
    +1062 			var prevIsEmpty = false;
    +1063 			
    +1064 			// cleanup empty block before merge
    +1065 
    +1066 			// 1. cleanup prev node which ends with marker +  
    +1067 			if(
    +1068 				xq.Browser.isTrident &&
    +1069 				prev.childNodes.length >= 2 &&
    +1070 				this.isMarker(prev.lastChild.previousSibling) &&
    +1071 				prev.lastChild.nodeType == 3 &&
    +1072 				prev.lastChild.nodeValue.length == 1 &&
    +1073 				prev.lastChild.nodeValue.charCodeAt(0) == 160
    +1074 			) {
    +1075 				this.deleteNode(prev.lastChild);
    +1076 			}
    +1077 
    +1078 			// 2. cleanup prev node (if prev is empty, then replace prev's tag with next's)
    +1079 			this.removePlaceHoldersAndEmptyNodes(prev);
    +1080 			if(this.isEmptyBlock(prev)) {
    +1081 				// replace atomic block with normal block so that following code don't need to care about atomic block
    +1082 				if(this.tree.isAtomic(prev)) prev = this.replaceTag("P", prev);
    +1083 				
    +1084 				prev = this.replaceTag(next.nodeName, prev) || prev;
    +1085 				prev.innerHTML = "";
    +1086 			} else if(prev.firstChild == prev.lastChild && this.isMarker(prev.firstChild)) {
    +1087 				prev = this.replaceTag(next.nodeName, prev) || prev;
    +1088 			}
    +1089 			
    +1090 			// 3. cleanup next node
    +1091 			if(this.isEmptyBlock(next)) {
    +1092 				// replace atomic block with normal block so that following code don't need to care about atomic block
    +1093 				if(this.tree.isAtomic(next)) next = this.replaceTag("P", next);
    +1094 				
    +1095 				next.innerHTML = "";
    +1096 			}
    +1097 			
    +1098 			// perform merge
    +1099 			this.moveChildNodes(next, prev);
    +1100 			this.deleteNode(next);
    +1101 			return prev;
    +1102 		} finally {
    +1103 			// cleanup
    +1104 			if(prevContainer && this.isEmptyBlock(prevContainer)) this.deleteNode(prevContainer, true);
    +1105 			if(nextContainer && this.isEmptyBlock(nextContainer)) this.deleteNode(nextContainer, true);
    +1106 			
    +1107 			if(prevContainer) this.unwrapUnnecessaryParagraph(prevContainer);
    +1108 			if(nextContainer) this.unwrapUnnecessaryParagraph(nextContainer);
    +1109 		}
    +1110 	},
    +1111 	
    +1112 	/**
    +1113 	 * Merges adjust list containers which has same tag name
    +1114 	 *
    +1115 	 * @param {Element} container target list container
    +1116 	 * @param {boolean} force force adjust list container even if they have different list type
    +1117 	 * @param {String} dir Specify merge direction: PREV or NEXT. If not supplied it will be merged with both direction.
    +1118 	 */
    +1119 	mergeAdjustLists: function(container, force, dir) {
    +1120 		var prev = container.previousSibling;
    +1121 		var isPrevSame = prev && (prev.nodeName == container.nodeName && prev.className == container.className);
    +1122 		if((!dir || dir.toLowerCase() == 'prev') && (isPrevSame || (force && this.tree.isListContainer(prev)))) {
    +1123 			while(prev.lastChild) {
    +1124 				this.insertNodeAt(prev.lastChild, container, "start");
    +1125 			}
    +1126 			this.deleteNode(prev);
    +1127 		}
    +1128 		
    +1129 		var next = container.nextSibling;
    +1130 		var isNextSame = next && (next.nodeName == container.nodeName && next.className == container.className);
    +1131 		if((!dir || dir.toLowerCase() == 'next') && (isNextSame || (force && this.tree.isListContainer(next)))) {
    +1132 			while(next.firstChild) {
    +1133 				this.insertNodeAt(next.firstChild, container, "end");
    +1134 			}
    +1135 			this.deleteNode(next);
    +1136 		}
    +1137 	},
    +1138 	
    +1139 	/**
    +1140 	 * Moves child nodes from one element into another.
    +1141 	 *
    +1142 	 * @param {Elemet} from source element
    +1143 	 * @param {Elemet} to target element
    +1144 	 */
    +1145 	moveChildNodes: function(from, to) {
    +1146 		if(this.tree.isDescendantOf(from, to) || ["HTML", "HEAD"].include(to.nodeName))
    +1147 			throw "Illegal argument. Cannot move children of element[" + from.nodeName + "] to element[" + to.nodeName + "]";
    +1148 		
    +1149 		if(from == to) return;
    +1150 		
    +1151 		while(from.firstChild) to.appendChild(from.firstChild);
    +1152 	},
    +1153 	
    +1154 	/**
    +1155 	 * Copies attributes from one element into another.
    +1156 	 *
    +1157 	 * @param {Element} from source element
    +1158 	 * @param {Element} to target element
    +1159 	 * @param {boolean} copyId copy ID attribute of source element
    +1160 	 */
    +1161 	copyAttributes: function(from, to, copyId) {
    +1162 		// IE overrides this
    +1163 		
    +1164 		var attrs = from.attributes;
    +1165 		if(!attrs) return;
    +1166 		
    +1167 		for(var i = 0; i < attrs.length; i++) {
    +1168 			if(attrs[i].nodeName == "class" && attrs[i].nodeValue) {
    +1169 				to.className = attrs[i].nodeValue;
    +1170 			} else if((copyId || !["id"].include(attrs[i].nodeName)) && attrs[i].nodeValue) {
    +1171 				to.setAttribute(attrs[i].nodeName, attrs[i].nodeValue);
    +1172 			}
    +1173 		}
    +1174 	},
    +1175 
    +1176 	_indentElements: function(node, blocks, affect) {
    +1177 		for (var i=0; i < affect.length; i++) {
    +1178 			if (affect[i] == node || this.tree.isDescendantOf(affect[i], node))
    +1179 				return;
    +1180 		}
    +1181 		leaves = this.tree.getLeavesAtEdge(node);
    +1182 		
    +1183 		if (blocks.include(leaves[0])) {
    +1184 			var affected = this.indentElement(node, true);
    +1185 			if (affected) {
    +1186 				affect.push(affected);
    +1187 				return;
    +1188 			}
    +1189 		}
    +1190 		
    +1191 		if (blocks.include(node)) {
    +1192 			var affected = this.indentElement(node, true);
    +1193 			if (affected) {
    +1194 				affect.push(affected);
    +1195 				return;
    +1196 			}
    +1197 		}
    +1198 
    +1199 		var children=$A(node.childNodes);
    +1200 		for (var i=0; i < children.length; i++)
    +1201 			this._indentElements(children[i], blocks, affect);
    +1202 		return;
    +1203 	},
    +1204 
    +1205 	indentElements: function(from, to) {
    +1206 		var blocks = this.getBlockElementsBetween(from, to);
    +1207 		var top = this.tree.findCommonAncestorAndImmediateChildrenOf(from, to);
    +1208 		
    +1209 		var affect = [];
    +1210 		
    +1211 		leaves = this.tree.getLeavesAtEdge(top.parent);
    +1212 		if (blocks.include(leaves[0])) {
    +1213 			var affected = this.indentElement(top.parent);
    +1214 			if (affected)
    +1215 				return [affected];
    +1216 		}
    +1217 		
    +1218 		var children = $A(top.parent.childNodes);
    +1219 		for (var i=0; i < children.length; i++) {
    +1220 			this._indentElements(children[i], blocks, affect);
    +1221 		}
    +1222 		
    +1223 		affect = affect.flatten()
    +1224 		return affect.length > 0 ? affect : blocks;
    +1225 	},
    +1226 	
    +1227 	outdentElementsCode: function(node) {
    +1228 		if (node.tagName == 'LI')
    +1229 			node = node.parentNode;
    +1230 		if (node.tagName == 'OL' && node.className == 'code')
    +1231 			return true;
    +1232 		return false;
    +1233 	},
    +1234 	
    +1235 	_outdentElements: function(node, blocks, affect) {
    +1236 		for (var i=0; i < affect.length; i++) {
    +1237 			if (affect[i] == node || this.tree.isDescendantOf(affect[i], node))
    +1238 				return;
    +1239 		}
    +1240 		leaves = this.tree.getLeavesAtEdge(node);
    +1241 		
    +1242 		if (blocks.include(leaves[0]) && !this.outdentElementsCode(leaves[0])) {
    +1243 			var affected = this.outdentElement(node, true);
    +1244 			if (affected) {
    +1245 				affect.push(affected);
    +1246 				return;
    +1247 			}
    +1248 		}
    +1249 		
    +1250 		if (blocks.include(node)) {
    +1251 			var children = $A(node.parentNode.childNodes);
    +1252 			var isCode = this.outdentElementsCode(node);
    +1253 			var affected = this.outdentElement(node, true, isCode);
    +1254 			if (affected) {
    +1255 				if (children.include(affected) && this.tree.isListContainer(node.parentNode) && !isCode) {
    +1256 					for (var i=0; i < children.length; i++) {
    +1257 						if (blocks.include(children[i]) && !affect.include(children[i]))
    +1258 							affect.push(children[i]);
    +1259 					}
    +1260 				}else
    +1261 					affect.push(affected);
    +1262 				return;
    +1263 			}
    +1264 		}
    +1265 
    +1266 		var children=$A(node.childNodes);
    +1267 		for (var i=0; i < children.length; i++)
    +1268 			this._outdentElements(children[i], blocks, affect);
    +1269 		return;
    +1270 	},
    +1271 
    +1272 	outdentElements: function(from, to) {
    +1273 		var start, end;
    +1274 		
    +1275 		if (from.parentNode.tagName == 'LI') start=from.parentNode;
    +1276 		if (to.parentNode.tagName == 'LI') end=to.parentNode;
    +1277 		
    +1278 		var blocks = this.getBlockElementsBetween(from, to);
    +1279 		var top = this.tree.findCommonAncestorAndImmediateChildrenOf(from, to);
    +1280 		
    +1281 		var affect = [];
    +1282 		
    +1283 		leaves = this.tree.getLeavesAtEdge(top.parent);
    +1284 		if (blocks.include(leaves[0]) && !this.outdentElementsCode(top.parent)) {
    +1285 			var affected = this.outdentElement(top.parent);
    +1286 			if (affected)
    +1287 				return [affected];
    +1288 		}
    +1289 		
    +1290 		var children = $A(top.parent.childNodes);
    +1291 		for (var i=0; i < children.length; i++) {
    +1292 			this._outdentElements(children[i], blocks, affect);
    +1293 		}
    +1294 
    +1295 		if (from.offsetParent && to.offsetParent) {
    +1296 			start = from;
    +1297 			end = to;
    +1298 		}else if (blocks.first().offsetParent && blocks.last().offsetParent) {
    +1299 			start = blocks.first();
    +1300 			end = blocks.last();
    +1301 		}
    +1302 		
    +1303 		affect = affect.flatten()
    +1304 		if (!start || !start.offsetParent)
    +1305 			start = affect.first();
    +1306 		if (!end || !end.offsetParent)
    +1307 			end = affect.last();
    +1308 		
    +1309 		return this.getBlockElementsBetween(start, end);
    +1310 	},
    +1311 	
    +1312 	/**
    +1313 	 * Performs indent by increasing element's margin-left
    +1314 	 */	
    +1315 	indentElement: function(element, noParent, forceMargin) {
    +1316 		if(
    +1317 			!forceMargin &&
    +1318 			(element.nodeName == "LI" || (!this.tree.isListContainer(element) && !element.previousSibling && element.parentNode.nodeName == "LI"))
    +1319 		) return this.indentListItem(element, noParent);
    +1320 		
    +1321 		var root = this.getRoot();
    +1322 		if(!element || element == root) return null;
    +1323 		
    +1324 		if (element.parentNode != root && !element.previousSibling && !noParent) element=element.parentNode;
    +1325 		
    +1326 		var margin = element.style.marginLeft;
    +1327 		var cssValue = margin ? this._getCssValue(margin, "px") : {value:0, unit:"em"};
    +1328 		
    +1329 		cssValue.value += 2;
    +1330 		element.style.marginLeft = cssValue.value + cssValue.unit;
    +1331 		
    +1332 		return element;
    +1333 	},
    +1334 	
    +1335 	/**
    +1336 	 * Performs outdent by decreasing element's margin-left
    +1337 	 */	
    +1338 	outdentElement: function(element, noParent, forceMargin) {
    +1339 		if(!forceMargin && element.nodeName == "LI") return this.outdentListItem(element, noParent);
    +1340 		
    +1341 		var root = this.getRoot();
    +1342 		if(!element || element == root) return null;
    +1343 		
    +1344 		var margin = element.style.marginLeft;
    +1345 		
    +1346 		var cssValue = margin ? this._getCssValue(margin, "px") : {value:0, unit:"em"};
    +1347 		if(cssValue.value == 0) {
    +1348 			return element.previousSibling || forceMargin ?
    +1349 				null :
    +1350 				this.outdentElement(element.parentNode, noParent);
    +1351 		}
    +1352 		
    +1353 		cssValue.value -= 2;
    +1354 		element.style.marginLeft = cssValue.value <= 0 ? "" : cssValue.value + cssValue.unit;
    +1355 		if(element.style.cssText == "") element.removeAttribute("style");
    +1356 		
    +1357 		return element;
    +1358 	},
    +1359 	
    +1360 	/**
    +1361 	 * Performs indent for list item
    +1362 	 */
    +1363 	indentListItem: function(element, treatListAsNormalBlock) {
    +1364 		var li = this.getParentElementOf(element, ["LI"]);
    +1365 		var container = li.parentNode;
    +1366 		var prev = li.previousSibling;
    +1367 		if(!li.previousSibling) return this.indentElement(container);
    +1368 		
    +1369 		if(li.parentNode.nodeName == "OL" && li.parentNode.className == "code") return this.indentElement(li, treatListAsNormalBlock, true);
    +1370 		
    +1371 		if(!prev.lastChild) prev.appendChild(this.makePlaceHolder());
    +1372 		
    +1373 		var targetContainer = 
    +1374 			this.tree.isListContainer(prev.lastChild) ?
    +1375 			// if there's existing list container, select it as target container
    +1376 			prev.lastChild :
    +1377 			// if there's nothing, create new one
    +1378 			this.insertNodeAt(this.createElement(container.nodeName), prev, "end");
    +1379 		
    +1380 		this.wrapAllInlineOrTextNodesAs("P", prev, true);
    +1381 		
    +1382 		// perform move
    +1383 		targetContainer.appendChild(li);
    +1384 		
    +1385 		// flatten nested list
    +1386 		if(!treatListAsNormalBlock && li.lastChild && this.tree.isListContainer(li.lastChild)) {
    +1387 			var childrenContainer = li.lastChild;
    +1388 			var child;
    +1389 			while(child = childrenContainer.lastChild) {
    +1390 				this.insertNodeAt(child, li, "after");
    +1391 			}
    +1392 			this.deleteNode(childrenContainer);
    +1393 		}
    +1394 		
    +1395 		this.unwrapUnnecessaryParagraph(li);
    +1396 		
    +1397 		return li;
    +1398 	},
    +1399 	
    +1400 	/**
    +1401 	 * Performs outdent for list item
    +1402 	 *
    +1403 	 * @return {Element} outdented list item or null if no outdent performed
    +1404 	 */
    +1405 	outdentListItem: function(element, treatListAsNormalBlock) {
    +1406 		var li = this.getParentElementOf(element, ["LI"]);
    +1407 		var container = li.parentNode;
    +1408 
    +1409 		if(!li.previousSibling) {
    +1410 			var performed = this.outdentElement(container);
    +1411 			if(performed) return performed;
    +1412 		}
    +1413 
    +1414 		if(li.parentNode.nodeName == "OL" && li.parentNode.className == "code") return this.outdentElement(li, treatListAsNormalBlock, true);
    +1415 		
    +1416 		var parentLi = container.parentNode;
    +1417 		if(parentLi.nodeName != "LI") return null;
    +1418 		
    +1419 		if(treatListAsNormalBlock) {
    +1420 			while(container.lastChild != li) {
    +1421 				this.insertNodeAt(container.lastChild, parentLi, "after");
    +1422 			}
    +1423 		} else {
    +1424 			// make next siblings as children
    +1425 			if(li.nextSibling) {
    +1426 				var targetContainer =
    +1427 					li.lastChild && this.tree.isListContainer(li.lastChild) ?
    +1428 						// if there's existing list container, select it as target container
    +1429 						li.lastChild :
    +1430 						// if there's nothing, create new one
    +1431 						this.insertNodeAt(this.createElement(container.nodeName), li, "end");
    +1432 				
    +1433 				this.copyAttributes(container, targetContainer);
    +1434 				
    +1435 				var sibling;
    +1436 				while(sibling = li.nextSibling) {
    +1437 					targetContainer.appendChild(sibling);
    +1438 				}
    +1439 			}
    +1440 		}
    +1441 		
    +1442 		// move current LI into parent LI's next sibling
    +1443 		li = this.insertNodeAt(li, parentLi, "after");
    +1444 		
    +1445 		// remove empty container
    +1446 		if(container.childNodes.length == 0) this.deleteNode(container);
    +1447 		
    +1448 		if(li.firstChild && this.tree.isListContainer(li.firstChild)) {
    +1449 			this.insertNodeAt(this.makePlaceHolder(), li, "start");
    +1450 		}
    +1451 		
    +1452 		this.wrapAllInlineOrTextNodesAs("P", li);
    +1453 		this.unwrapUnnecessaryParagraph(parentLi);
    +1454 		
    +1455 		return li;
    +1456 	},
    +1457 	
    +1458 	/**
    +1459 	 * Performs justification
    +1460 	 *
    +1461 	 * @param {Element} block target element
    +1462 	 * @param {String} dir one of "LEFT", "CENTER", "RIGHT", "BOTH"
    +1463 	 */
    +1464 	justifyBlock: function(block, dir) {
    +1465 		// if block is only child, select its parent as mover
    +1466 		while(block.parentNode != this.getRoot() && !block.previousSibling && !block.nextSibling && !this.tree.isListContainer(block.parentNode)) {
    +1467 			block = block.parentNode;
    +1468 		}
    +1469 		
    +1470 		var styleValue = dir.toLowerCase() == "both" ? "justify" : dir;
    +1471 		if(styleValue == "left") {
    +1472 			block.style.textAlign = "";
    +1473 			if(block.style.cssText == "") block.removeAttribute("style");
    +1474 		} else {
    +1475 			block.style.textAlign = styleValue;
    +1476 		}
    +1477 		return block;
    +1478 	},
    +1479 	
    +1480 	justifyBlocks: function(blocks, dir) {
    +1481 		blocks.each(function(block) {
    +1482 			this.justifyBlock(block, dir);
    +1483 		}.bind(this));
    +1484 		
    +1485 		return blocks;
    +1486 	},
    +1487 	
    +1488 	/**
    +1489      * Turn given element into list. If the element is a list already, it will be reversed into normal element.
    +1490 	 *
    +1491 	 * @param {Element} element target element
    +1492 	 * @param {String} type one of "UL", "OL"
    +1493 	 * @returns {Element} affected element
    +1494 	 */
    +1495 	applyList: function(element, type) {
    +1496 		type = type.toUpperCase();
    +1497 		var containerTag = type == "UL" ? "UL" : "OL";
    +1498 		
    +1499 		if(element.nodeName == "LI" || (element.parentNode.nodeName == "LI" && !element.previousSibling)) {
    +1500 			var element = this.getParentElementOf(element, ["LI"]);
    +1501 			var container = element.parentNode;
    +1502 			if(container.nodeName == containerTag) {
    +1503 				return this.extractOutElementFromParent(element);
    +1504 			} else {
    +1505 				return this.changeListTypeTo(element, type);
    +1506 			}
    +1507 		} else {
    +1508 			return this.turnElementIntoListItem(element, type);
    +1509 		}
    +1510 	},
    +1511 	
    +1512 	applyLists: function(from, to, type) {
    +1513 		type = type.toUpperCase();
    +1514 		var containerTag = type == "UL" ? "UL" : "OL";
    +1515 		var blocks = this.getBlockElementsBetween(from, to);
    +1516 		
    +1517 		// LIs or Non-containing blocks
    +1518 		var whole = blocks.findAll(function(e) {
    +1519 			return e.nodeName == "LI" || !this.tree.isBlockContainer(e);
    +1520 		}.bind(this));
    +1521 		
    +1522 		// LIs
    +1523 		var listItems = whole.findAll(function(e) {return e.nodeName == "LI"}.bind(this));
    +1524 		
    +1525 		// Non-containing blocks which is not a descendant of any LIs selected above(listItems).
    +1526 		var normalBlocks = whole.findAll(function(e) {
    +1527 			return e.nodeName != "LI" &&
    +1528 				!(e.parentNode.nodeName == "LI" && !e.previousSibling && !e.nextSibling) &&
    +1529 				!this.tree.isDescendantOf(listItems, e)
    +1530 		}.bind(this));
    +1531 		
    +1532 		var diffListItems = listItems.findAll(function(e) {
    +1533 			return e.parentNode.nodeName != containerTag;
    +1534 		}.bind(this));
    +1535 		
    +1536 		// Conditions needed to determine mode
    +1537 		var hasNormalBlocks = normalBlocks.length > 0;
    +1538 		var hasDifferentListStyle = diffListItems.length > 0;
    +1539 		
    +1540 		var blockToHandle = null;
    +1541 		
    +1542 		if(hasNormalBlocks) {
    +1543 			blockToHandle = normalBlocks;
    +1544 		} else if(hasDifferentListStyle) {
    +1545 			blockToHandle = diffListItems;
    +1546 		} else {
    +1547 			blockToHandle = listItems;
    +1548 		}
    +1549 		
    +1550 		// perform operation
    +1551 		for(var i = 0; i < blockToHandle.length; i++) {
    +1552 			var block = blockToHandle[i];
    +1553 			
    +1554 			// preserve original index to restore selection
    +1555 			var originalIndex = blocks.indexOf(block);
    +1556 			blocks[originalIndex] = this.applyList(block, type);
    +1557 		}
    +1558 		
    +1559 		return blocks;
    +1560 	},
    +1561 
    +1562 	/**
    +1563 	 * Insert place-holder for given empty element. Empty element does not displayed and causes many editing problems.
    +1564 	 *
    +1565 	 * @param {Element} element empty element
    +1566 	 */
    +1567 	correctEmptyElement: function(element) {throw "Not implemented"},
    +1568 
    +1569 	/**
    +1570 	 * Corrects current block-only-container to do not take any non-block element or node.
    +1571 	 */
    +1572 	correctParagraph: function() {throw "Not implemented"},
    +1573 	
    +1574 	/**
    +1575 	 * Makes place-holder for empty element.
    +1576 	 *
    +1577 	 * @returns {Node} Platform specific place holder
    +1578 	 */
    +1579 	makePlaceHolder: function() {throw "Not implemented"},
    +1580 	
    +1581 	/**
    +1582 	 * Makes place-holder string.
    +1583 	 *
    +1584 	 * @returns {String} Platform specific place holder string
    +1585 	 */
    +1586 	makePlaceHolderString: function() {throw "Not implemented"},
    +1587 	
    +1588 	/**
    +1589 	 * Makes empty paragraph which contains only one place-holder
    +1590 	 */
    +1591 	makeEmptyParagraph: function() {throw "Not implemented"},
    +1592 
    +1593 	/**
    +1594 	 * Applies background color to selected area
    +1595 	 *
    +1596 	 * @param {Object} color valid CSS color value
    +1597 	 */
    +1598 	applyBackgroundColor: function(color) {throw "Not implemented";},
    +1599 
    +1600 	/**
    +1601 	 * Applies foreground color to selected area
    +1602 	 *
    +1603 	 * @param {Object} color valid CSS color value
    +1604 	 */
    +1605 	applyForegroundColor: function(color) {
    +1606 		this.execCommand("forecolor", color);
    +1607 	},
    +1608 	
    +1609 	execCommand: function(commandId, param) {throw "Not implemented";},
    +1610 	
    +1611 	applyRemoveFormat: function() {throw "Not implemented";},
    +1612 	applyEmphasis: function() {throw "Not implemented";},
    +1613 	applyStrongEmphasis: function() {throw "Not implemented";},
    +1614 	applyStrike: function() {throw "Not implemented";},
    +1615 	applyUnderline: function() {throw "Not implemented";},
    +1616 	applySuperscription: function() {
    +1617 		this.execCommand("superscript");
    +1618 	},
    +1619 	applySubscription: function() {
    +1620 		this.execCommand("subscript");
    +1621 	},
    +1622 	indentBlock: function(element, treatListAsNormalBlock) {
    +1623 		return (!element.previousSibling && element.parentNode.nodeName == "LI") ?
    +1624 			this.indentListItem(element, treatListAsNormalBlock) :
    +1625 			this.indentElement(element);
    +1626 	},
    +1627 	outdentBlock: function(element, treatListAsNormalBlock) {
    +1628 		while(true) {
    +1629 			if(!element.previousSibling && element.parentNode.nodeName == "LI") {
    +1630 				element = this.outdentListItem(element, treatListAsNormalBlock);
    +1631 				return element;
    +1632 			} else {
    +1633 				var performed = this.outdentElement(element);
    +1634 				if(performed) return performed;
    +1635 				
    +1636 				// first-child can outdent container
    +1637 				if(!element.previousSibling) {
    +1638 					element = element.parentNode;
    +1639 				} else {
    +1640 					break;
    +1641 				}
    +1642 			}
    +1643 		}
    +1644 		
    +1645 		return null;
    +1646 	},
    +1647 	wrapBlock: function(tag, start, end) {
    +1648 		if(!this.tree._blockTags.include(tag)) throw "Unsuppored block container: [" + tag + "]";
    +1649 		if(!start) start = this.getCurrentBlockElement();
    +1650 		if(!end) end = start;
    +1651 		
    +1652 		// Check if the selection captures valid fragement
    +1653 		var validFragment = false;
    +1654 		
    +1655 		if(start == end) {
    +1656 			// are they same block?
    +1657 			validFragment = true;
    +1658 		} else if(start.parentNode == end.parentNode && !start.previousSibling && !end.nextSibling) {
    +1659 			// are they covering whole parent?
    +1660 			validFragment = true;
    +1661 			start = end = start.parentNode;
    +1662 		} else {
    +1663 			// are they siblings of non-LI blocks?
    +1664 			validFragment =
    +1665 				(start.parentNode == end.parentNode) &&
    +1666 				(start.nodeName != "LI");
    +1667 		}
    +1668 		
    +1669 		if(!validFragment) return null;
    +1670 		
    +1671 		var wrapper = this.createElement(tag);
    +1672 		
    +1673 		if(start == end) {
    +1674 			// They are same.
    +1675 			if(this.tree.isBlockContainer(start) && !this.tree.isListContainer(start)) {
    +1676 				// It's a block container. Wrap its contents.
    +1677 				if(this.tree.isBlockOnlyContainer(wrapper)) {
    +1678 					this.correctEmptyElement(start);
    +1679 					this.wrapAllInlineOrTextNodesAs("P", start, true);
    +1680 				}
    +1681 				this.moveChildNodes(start, wrapper);
    +1682 				start.appendChild(wrapper);
    +1683 			} else {
    +1684 				// It's not a block container. Wrap itself.
    +1685 				wrapper = this.insertNodeAt(wrapper, start, "after");
    +1686 				wrapper.appendChild(start);
    +1687 			}
    +1688 			
    +1689 			this.correctEmptyElement(wrapper);
    +1690 		} else {
    +1691 			// They are siblings. Wrap'em all.
    +1692 			wrapper = this.insertNodeAt(wrapper, start, "before");
    +1693 			var node = start;
    +1694 			
    +1695 			while(node != end) {
    +1696 				next = node.nextSibling;
    +1697 				wrapper.appendChild(node);
    +1698 				node = next;
    +1699 			}
    +1700 			wrapper.appendChild(node);
    +1701 		}
    +1702 		
    +1703 		return wrapper;
    +1704 	},
    +1705 
    +1706 
    +1707 	
    +1708 	/////////////////////////////////////////////
    +1709 	// Focus/Caret/Selection
    +1710 	
    +1711 	/**
    +1712 	 * Gives focus to root element's window
    +1713 	 */
    +1714 	focus: function() {throw "Not implemented";},
    +1715 
    +1716 	/**
    +1717 	 * Returns selection object
    +1718 	 */
    +1719 	sel: function() {throw "Not implemented";},
    +1720 	
    +1721 	/**
    +1722 	 * Returns range object
    +1723 	 */
    +1724 	rng: function() {throw "Not implemented";},
    +1725 	
    +1726 	/**
    +1727 	 * Returns true if DOM has selection
    +1728 	 */
    +1729 	hasSelection: function() {throw "Not implemented";},
    +1730 
    +1731 	/**
    +1732 	 * Returns true if root element's window has selection
    +1733 	 */
    +1734 	hasFocus: function() {
    +1735 		var cur = this.getCurrentElement();
    +1736 		return (cur && cur.ownerDocument == this.getDoc());
    +1737 	},
    +1738 	
    +1739 	/**
    +1740 	 * Adjust scrollbar to make the element visible in current viewport.
    +1741 	 *
    +1742 	 * @param {Element} element Target element
    +1743 	 * @param {boolean} toTop Align element to top of the viewport
    +1744 	 * @param {boolean} moveCaret Move caret to the element
    +1745 	 */
    +1746 	scrollIntoView: function(element, toTop, moveCaret) {
    +1747 		element.scrollIntoView(toTop);
    +1748 		if(moveCaret) this.placeCaretAtStartOf(element);
    +1749 	},
    +1750 	
    +1751 	/**
    +1752 	 * Select all document
    +1753 	 */
    +1754 	selectAll: function() {
    +1755 		return this.execCommand('selectall');
    +1756 	},
    +1757 	
    +1758 	/**
    +1759 	 * Select specified element.
    +1760 	 *
    +1761 	 * @param {Element} element element to select
    +1762 	 * @param {boolean} entireElement true to select entire element, false to select inner content of element 
    +1763 	 */
    +1764 	selectElement: function(node, entireElement) {throw "Not implemented"},
    +1765 	
    +1766 	/**
    +1767 	 * Select all elements between two blocks(inclusive).
    +1768 	 *
    +1769 	 * @param {Element} start start of selection
    +1770 	 * @param {Element} end end of selection
    +1771 	 */
    +1772 	selectBlocksBetween: function(start, end) {throw "Not implemented"},
    +1773 	
    +1774 	/**
    +1775 	 * Delete selected area
    +1776 	 */
    +1777 	deleteSelection: function() {throw "Not implemented"},
    +1778 	
    +1779 	/**
    +1780 	 * Collapses current selection.
    +1781 	 *
    +1782 	 * @param {boolean} toStart true to move caret to start of selected area.
    +1783 	 */
    +1784 	collapseSelection: function(toStart) {throw "Not implemented"},
    +1785 	
    +1786 	/**
    +1787 	 * Returns selected area as HTML string
    +1788 	 */
    +1789 	getSelectionAsHtml: function() {throw "Not implemented"},
    +1790 	
    +1791 	/**
    +1792 	 * Returns selected area as text string
    +1793 	 */
    +1794 	getSelectionAsText: function() {throw "Not implemented"},
    +1795 	
    +1796 	/**
    +1797 	 * Places caret at start of the element
    +1798 	 *
    +1799 	 * @param {Element} element Target element
    +1800 	 */
    +1801 	placeCaretAtStartOf: function(element) {throw "Not implemented"},
    +1802 	
    +1803 	/**
    +1804 	 * Checks if the node is empty-text-node or not
    +1805 	 */
    +1806 	isEmptyTextNode: function(node) {
    +1807 		return node.nodeType == 3 && node.nodeValue.length == 0;
    +1808 	},
    +1809 	
    +1810 	/**
    +1811 	 * Checks if the caret is place in empty block element
    +1812 	 */
    +1813 	isCaretAtEmptyBlock: function() {
    +1814 		return this.isEmptyBlock(this.getCurrentBlockElement());
    +1815 	},
    +1816 	
    +1817 	/**
    +1818 	 * Checks if the caret is place at start of the block
    +1819 	 */
    +1820 	isCaretAtBlockStart: function() {throw "Not implemented"},
    +1821 
    +1822 	/**
    +1823 	 * Checks if the caret is place at end of the block
    +1824 	 */
    +1825 	isCaretAtBlockEnd: function() {throw "Not implemented"},
    +1826 	
    +1827 	/**
    +1828 	 * Saves current selection info
    +1829 	 *
    +1830 	 * @returns {Object} Bookmark for selection
    +1831 	 */
    +1832 	saveSelection: function() {throw "Not implemented"},
    +1833 	
    +1834 	/**
    +1835 	 * Restores current selection info
    +1836 	 *
    +1837 	 * @param {Object} bookmark Bookmark
    +1838 	 */
    +1839 	restoreSelection: function(bookmark) {throw "Not implemented"},
    +1840 	
    +1841 	/**
    +1842 	 * Create marker
    +1843 	 */
    +1844 	createMarker: function() {
    +1845 		var marker = this.createElement("SPAN");
    +1846 		marker.id = "xquared_marker_" + (this._lastMarkerId++);
    +1847 		marker.className = "xquared_marker";
    +1848 		return marker;
    +1849 	},
    +1850 
    +1851 	/**
    +1852 	 * Create and insert marker into current caret position.
    +1853 	 * Marker is an inline element which has no child nodes. It can be used with many purposes.
    +1854 	 * For example, You can push marker to mark current caret position.
    +1855 	 *
    +1856 	 * @returns {Element} marker
    +1857 	 */
    +1858 	pushMarker: function() {
    +1859 		var marker = this.createMarker();
    +1860 		return this.insertNode(marker);
    +1861 	},
    +1862 	
    +1863 	/**
    +1864 	 * Removes last marker
    +1865 	 *
    +1866 	 * @params {boolean} moveCaret move caret into marker before delete.
    +1867 	 */
    +1868 	popMarker: function(moveCaret) {
    +1869 		var id = "xquared_marker_" + (--this._lastMarkerId);
    +1870 		var marker = this.$(id);
    +1871 		if(!marker) return;
    +1872 		
    +1873 		if(moveCaret) {
    +1874 			this.selectElement(marker, true);
    +1875 			this.collapseSelection(false);
    +1876 		}
    +1877 		
    +1878 		this.deleteNode(marker);
    +1879 	},
    +1880 	
    +1881 	
    +1882 	
    +1883 	/////////////////////////////////////////////
    +1884 	// Query methods
    +1885 	
    +1886 	isMarker: function(node) {
    +1887 		return (node.nodeType == 1 && node.nodeName == "SPAN" && node.className == "xquared_marker");
    +1888 	},
    +1889 	
    +1890 	isFirstBlockOfBody: function(block) {
    +1891 		var root = this.getRoot();
    +1892 		var found = this.tree.findBackward(
    +1893 			block,
    +1894 			function(node) {return (node == root) || node.previousSibling;}.bind(this)
    +1895 		);
    +1896 		
    +1897 		return found == root;
    +1898 	},
    +1899 	
    +1900 	/**
    +1901 	 * Returns outer HTML of given element
    +1902 	 */
    +1903 	getOuterHTML: function(element) {throw "Not implemented"},
    +1904 	
    +1905 	/**
    +1906 	 * Returns inner text of given element
    +1907 	 * 
    +1908 	 * @param {Element} element Target element
    +1909 	 * @returns {String} Text string
    +1910 	 */
    +1911 	getInnerText: function(element) {
    +1912 		return element.innerHTML.stripTags();
    +1913 	},
    +1914 
    +1915 	/**
    +1916 	 * Checks if given node is place holder or not.
    +1917 	 * 
    +1918 	 * @param {Node} node DOM node
    +1919 	 */
    +1920 	isPlaceHolder: function(node) {throw "Not implemented"},
    +1921 	
    +1922 	/**
    +1923 	 * Checks if given block is the first LI whose next sibling is a nested list.
    +1924 	 *
    +1925 	 * @param {Element} block Target block
    +1926 	 */
    +1927 	isFirstLiWithNestedList: function(block) {
    +1928 		return !block.previousSibling &&
    +1929 			block.parentNode.nodeName == "LI" &&
    +1930 			this.tree.isListContainer(block.nextSibling);
    +1931 	},
    +1932 	
    +1933 	/**
    +1934 	 * Search all links within given element
    +1935 	 *
    +1936 	 * @param {Element} [element] Container element. If not given, the root element will be used.
    +1937 	 * @param {Array} [found] if passed, links will be appended into this array.
    +1938 	 * @returns {Array} Array of anchors. It returns empty array if there's no links.
    +1939 	 */
    +1940 	searchAnchors: function(element, found) {
    +1941 		if(!element) element = this.getRoot();
    +1942 		if(!found) found = [];
    +1943 
    +1944 		var anchors = element.getElementsByTagName("A");
    +1945 		for(var i = 0; i < anchors.length; i++) {
    +1946 			found.push(anchors[i]);
    +1947 		}
    +1948 
    +1949 		return found;
    +1950 	},
    +1951 	
    +1952 	/**
    +1953 	 * Search all headings within given element
    +1954 	 *
    +1955 	 * @param {Element} [element] Container element. If not given, the root element will be used.
    +1956 	 * @param {Array} [found] if passed, headings will be appended into this array.
    +1957 	 * @returns {Array} Array of headings. It returns empty array if there's no headings.
    +1958 	 */
    +1959 	searchHeadings: function(element, found) {
    +1960 		if(!element) element = this.getRoot();
    +1961 		if(!found) found = [];
    +1962 
    +1963 		var regexp = /^h[1-6]/ig;
    +1964 
    +1965 		if (!element.childNodes) return [];
    +1966 		$A(element.childNodes).each(function(child) {
    +1967 			var isContainer = child && this.tree._blockContainerTags.include(child.nodeName);
    +1968 			var isHeading = child && child.nodeName.match(regexp);
    +1969 
    +1970 			if (isContainer) {
    +1971 				this.searchHeadings(child, found);
    +1972 			} else if (isHeading) {
    +1973 				found.push(child);
    +1974 			}
    +1975 		}.bind(this));
    +1976 
    +1977 		return found;
    +1978 	},
    +1979 	
    +1980 	/**
    +1981 	 * Collect structure and style informations of given element.
    +1982 	 *
    +1983 	 * @param {Element} element target element
    +1984 	 * @returns {Object} object that contains information: {em: true, strong: false, block: "p", list: "ol", ...}
    +1985 	 */
    +1986 	collectStructureAndStyle: function(element) {
    +1987 		if(!element || element.nodeName == "#document") return {};
    +1988 
    +1989 		var block = this.getParentBlockElementOf(element);
    +1990 		var parents = this.tree.collectParentsOf(element, true, function(node) {return block.parentNode == node});
    +1991 		var blockName = block.nodeName;
    +1992 
    +1993 		var info = {};
    +1994 		
    +1995 		var doc = this.getDoc();
    +1996 		var em = doc.queryCommandState("Italic");
    +1997 		var strong = doc.queryCommandState("Bold");
    +1998 		var strike = doc.queryCommandState("Strikethrough");
    +1999 		var underline = doc.queryCommandState("Underline") && !this.getParentElementOf(element, ["A"]);
    +2000 		var superscription = doc.queryCommandState("superscript");
    +2001 		var subscription = doc.queryCommandState("subscript");
    +2002 		
    +2003 		// if block is only child, select its parent
    +2004 		while(block.parentNode && block.parentNode != this.getRoot() && !block.previousSibling && !block.nextSibling && !this.tree.isListContainer(block.parentNode)) {
    +2005 			block = block.parentNode;
    +2006 		}
    +2007 
    +2008 		var list = false;
    +2009 		if(block.nodeName == "LI") {
    +2010 			var parent = block.parentNode;
    +2011 			var isCode = parent.nodeName == "OL" && parent.className == "code";
    +2012 			list = isCode ? "CODE" : parent.nodeName;
    +2013 		}
    +2014 		
    +2015 		var justification = block.style.textAlign || "left";
    +2016 		
    +2017 		return {
    +2018 			block:blockName,
    +2019 			em: em,
    +2020 			strong: strong,
    +2021 			strike: strike,
    +2022 			underline: underline,
    +2023 			superscription: superscription,
    +2024 			subscription: subscription,
    +2025 			list: list,
    +2026 			justification: justification
    +2027 		};
    +2028 	},
    +2029 	
    +2030 	/**
    +2031 	 * Find elements by CSS selector.
    +2032 	 *
    +2033 	 * WARNING: Use this method carefully since prototype.js doesn't work well with designMode DOM.
    +2034 	 */
    +2035 	findBySelector: function(selector) {
    +2036 		return Element.getElementsBySelector(this.root, selector);
    +2037 	},
    +2038 	
    +2039 	/**
    +2040 	 * Find elements by attribute.
    +2041 	 * 
    +2042 	 * This method will be deprecated when findBySelector get stabilized.
    +2043 	 */
    +2044 	findByAttribute: function(name, value) {
    +2045 		var nodes = [];
    +2046 		this._findByAttribute(nodes, this.root, name, value);
    +2047 		return nodes;
    +2048 	},
    +2049 	
    +2050 	/** @private */
    +2051 	_findByAttribute: function(nodes, element, name, value) {
    +2052 		if(element.getAttribute(name) == value) nodes.push(element);
    +2053 		if(!element.hasChildNodes()) return;
    +2054 		
    +2055 		var children = element.childNodes;
    +2056 		for(var i = 0; i < children.length; i++) {
    +2057 			if(children[i].nodeType == 1) this._findByAttribute(nodes, children[i], name, value);
    +2058 		}
    +2059 	},
    +2060 	
    +2061 	/**
    +2062 	 * Checks if the element has one or more important attributes: id, class, style
    +2063 	 *
    +2064 	 * @param {Element} element Target element
    +2065 	 */
    +2066 	hasImportantAttributes: function(element) {throw "Not implemented"},
    +2067 	
    +2068 	/**
    +2069 	 * Checks if the element is empty or not. Place-holder is not counted as a child.
    +2070 	 *
    +2071 	 * @param {Element} element Target element
    +2072 	 */
    +2073 	isEmptyBlock: function(element) {throw "Not implemented"},
    +2074 	
    +2075 	/**
    +2076 	 * Returns element that contains caret.
    +2077 	 */
    +2078 	getCurrentElement: function() {throw "Not implemented"},
    +2079 	
    +2080 	/**
    +2081 	 * Returns block element that contains caret.
    +2082 	 */
    +2083 	getCurrentBlockElement: function() {
    +2084 		var cur = this.getCurrentElement();
    +2085 		if(!cur) return null;
    +2086 		
    +2087 		var block = this.getParentBlockElementOf(cur);
    +2088 		if(!block) return null;
    +2089 		
    +2090 		return (block.nodeName == "BODY") ? null : block;
    +2091 	},
    +2092 	
    +2093 	/**
    +2094 	 * Returns parent block element of parameter.
    +2095 	 * If the parameter itself is a block, it will be returned.
    +2096 	 *
    +2097 	 * @param {Element} element Target element
    +2098 	 *
    +2099 	 * @returns {Element} Element or null
    +2100 	 */
    +2101 	getParentBlockElementOf: function(element) {
    +2102 		while(element) {
    +2103 			if(this.tree._blockTags.include(element.nodeName)) return element;
    +2104 			element = element.parentNode;
    +2105 		}
    +2106 		return null;
    +2107 	},
    +2108 	
    +2109 	/**
    +2110 	 * Returns parent element of parameter which has one of given tag name.
    +2111 	 * If the parameter itself has the same tag name, it will be returned.
    +2112 	 *
    +2113 	 * @param {Element} element Target element
    +2114 	 * @param {Array} tagNames Array of string which contains tag names
    +2115 	 *
    +2116 	 * @returns {Element} Element or null
    +2117 	 */
    +2118 	getParentElementOf: function(element, tagNames) {
    +2119 		while(element) {
    +2120 			if(tagNames.include(element.nodeName)) return element;
    +2121 			element = element.parentNode;
    +2122 		}
    +2123 		return null;
    +2124 	},
    +2125 	
    +2126 	/**
    +2127 	 * Collects all block elements between two elements
    +2128 	 *
    +2129 	 * @param {Element} from Start element(inclusive)
    +2130 	 * @param {Element} to End element(inclusive)
    +2131 	 */
    +2132 	getBlockElementsBetween: function(from, to) {
    +2133 		return this.tree.collectNodesBetween(from, to, function(node) {
    +2134 			return node.nodeType == 1 && this.tree.isBlock(node);
    +2135 		}.bind(this));
    +2136 	},
    +2137 	
    +2138 	/**
    +2139 	 * Returns block element that contains selection start.
    +2140 	 *
    +2141 	 * This method will return exactly same result with getCurrentBlockElement method
    +2142 	 * when there's no selection.
    +2143 	 */
    +2144 	getBlockElementAtSelectionStart: function() {throw "Not implemented"},
    +2145 	
    +2146 	/**
    +2147 	 * Returns block element that contains selection end.
    +2148 	 *
    +2149 	 * This method will return exactly same result with getCurrentBlockElement method
    +2150 	 * when there's no selection.
    +2151 	 */
    +2152 	getBlockElementAtSelectionEnd: function() {throw "Not implemented"},
    +2153 	
    +2154 	/**
    +2155 	 * Returns blocks at each edge of selection(start and end).
    +2156 	 *
    +2157 	 * TODO: implement ignoreEmptyEdges for FF
    +2158 	 *
    +2159 	 * @param {boolean} naturalOrder Mak the start element always comes before the end element
    +2160 	 * @param {boolean} ignoreEmptyEdges Prevent some browser(Gecko) from selecting one more block than expected
    +2161 	 */
    +2162 	getBlockElementsAtSelectionEdge: function(naturalOrder, ignoreEmptyEdges) {throw "Not implemented"},
    +2163 	
    +2164 	/**
    +2165 	 * Returns array of selected block elements
    +2166 	 */
    +2167 	getSelectedBlockElements: function() {
    +2168 		var selectionEdges = this.getBlockElementsAtSelectionEdge(true, true);
    +2169 		var start = selectionEdges[0];
    +2170 		var end = selectionEdges[1];
    +2171 		
    +2172 		return this.tree.collectNodesBetween(start, end, function(node) {
    +2173 			return node.nodeType == 1 && this.tree.isBlock(node);
    +2174 		}.bind(this));
    +2175 	},
    +2176 	
    +2177 	/**
    +2178 	 * Get element by ID
    +2179 	 *
    +2180 	 * @param {String} id Element's ID
    +2181 	 * @returns {Element} element or null
    +2182 	 */
    +2183 	getElementById: function(id) {return this.doc.getElementById(id)},
    +2184 	
    +2185 	/**
    +2186 	 * Shortcut for #getElementById
    +2187 	 */
    +2188 	$: function(id) {return this.getElementById(id)},
    +2189 	
    +2190 	/**
    +2191 	  * Returns first "valid" child of given element. It ignores empty textnodes.
    +2192 	  *
    +2193 	  * @param {Element} element Target element
    +2194 	  * @returns {Node} first child node or null
    +2195 	  */
    +2196 	getFirstChild: function(element) {
    +2197 		if(!element) return null;
    +2198 		
    +2199 		var nodes = $A(element.childNodes);
    +2200 		for(var i = 0; i < nodes.length; i++) {
    +2201 			if(!this.isEmptyTextNode(nodes[i])) return nodes[i];
    +2202 		}
    +2203 		return null;
    +2204 	},
    +2205 	
    +2206 	/**
    +2207 	  * Returns last "valid" child of given element. It ignores empty textnodes and place-holders.
    +2208 	  *
    +2209 	  * @param {Element} element Target element
    +2210 	  * @returns {Node} last child node or null
    +2211 	  */
    +2212 	getLastChild: function(element) {throw "Not implemented"},
    +2213 
    +2214 	getNextSibling: function(node) {
    +2215 		while(node = node.nextSibling) {
    +2216 			if(node.nodeType != 3 || node.nodeValue.strip() != "") break;
    +2217 		}
    +2218 		return node;
    +2219 	},
    +2220 
    +2221 	getBottommostFirstChild: function(node) {
    +2222 		while(node.firstChild && node.nodeType == 1) node = node.firstChild;
    +2223 		return node;
    +2224 	},
    +2225 	
    +2226 	getBottommostLastChild: function(node) {
    +2227 		while(node.lastChild && node.nodeType == 1) node = node.lastChild;
    +2228 		return node;
    +2229 	},
    +2230 
    +2231 	/** @private */
    +2232 	_getCssValue: function(str, defaultUnit) {
    +2233 		if(!str || str.length == 0) return {value:0, unit:defaultUnit};
    +2234 		
    +2235 		var tokens = str.match(/(\d+)(.*)/);
    +2236 		return {
    +2237 			value:parseInt(tokens[1]),
    +2238 			unit:tokens[2] || defaultUnit
    +2239 		};
    +2240 	}
    +2241 });
    +2242 
    +2243 /**
    +2244  * Creates and returns instance of browser specific implementation.
    +2245  */
    +2246 xq.RichDom.createInstance = function() {
    +2247 	if(xq.Browser.isTrident) {
    +2248 		return new xq.RichDomTrident();
    +2249 	} else if(xq.Browser.isWebkit) {
    +2250 		return new xq.RichDomWebkit();
    +2251 	} else {
    +2252 		return new xq.RichDomGecko();
    +2253 	}
    +2254 }
    +2255 
    \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_07.html b/modules/editor/skins/xquared/doc/api/src_07.html new file mode 100644 index 000000000..6b89ca0d2 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/src_07.html @@ -0,0 +1,54 @@ +
      1 /**
    +  2  * RichDom for Gecko
    +  3  */
    +  4 xq.RichDomGecko = Class.create(xq.RichDomW3, {
    +  5 	makePlaceHolder: function() {
    +  6 		var holder = this.createElement("BR");
    +  7 		holder.setAttribute("type", "_moz");
    +  8 		return holder;
    +  9 	},
    + 10 	
    + 11 	makePlaceHolderString: function() {
    + 12 		return '<br type="_moz" />';
    + 13 	},
    + 14 	
    + 15 	makeEmptyParagraph: function() {
    + 16 		return this.createElementFromHtml('<p><br type="_moz" /></p>');
    + 17 	},
    + 18 
    + 19 	isPlaceHolder: function(node) {
    + 20 		if(node.nodeType != 1) return false;
    + 21 		
    + 22 		var typeMatches = node.nodeName == "BR" && node.getAttribute("type") == "_moz";
    + 23 		if(typeMatches) return true;
    + 24 		
    + 25 		var positionMatches = node.nodeName == "BR" && !this.getNextSibling(node);
    + 26 		if(positionMatches) return true;
    + 27 		
    + 28 		return false;
    + 29 	},
    + 30 
    + 31 	selectElement: function(element, entireElement) {
    + 32 		if(!element) throw "[element] is null";
    + 33 		if(element.nodeType != 1) throw "[element] is not an element";
    + 34 
    + 35 		// required to avoid Windows FF selection bug.
    + 36 		try {
    + 37 			if(!xq.Browser.isMac) this.doc.execCommand("SelectAll", false, null);
    + 38 		} catch(ignored) {}
    + 39 		
    + 40 		if(entireElement) {
    + 41 			this.rng().selectNode(element);
    + 42 		} else {
    + 43 			this.rng().selectNodeContents(element);
    + 44 		}
    + 45 	}
    + 46 });
    + 47 
    \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_08.html b/modules/editor/skins/xquared/doc/api/src_08.html new file mode 100644 index 000000000..ce19b8514 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/src_08.html @@ -0,0 +1,369 @@ +
      1 /**
    +  2  * RichDom for Internet Explorer 6 and 7
    +  3  */
    +  4 xq.RichDomTrident = Class.create(xq.RichDom, {
    +  5 	makePlaceHolder: function() {
    +  6 		return this.createTextNode(" ");
    +  7 	},
    +  8 	
    +  9 	makePlaceHolderString: function() {
    + 10 		return ' ';
    + 11 	},
    + 12 	
    + 13 	makeEmptyParagraph: function() {
    + 14 		return this.createElementFromHtml("<p> </p>");
    + 15 	},
    + 16 
    + 17 	isPlaceHolder: function(node) {
    + 18 		return false;
    + 19 	},
    + 20 
    + 21 	getOuterHTML: function(element) {
    + 22 		return element.outerHTML;
    + 23 	},
    + 24 	
    + 25 	insertNode: function(node) {
    + 26 		if(this.hasSelection()) this.collapseSelection(true);
    + 27 		
    + 28 		this.rng().pasteHTML('<span id="xquared_temp"></span>');
    + 29 		var marker = this.$('xquared_temp');
    + 30 		if(node.id == 'xquared_temp') return marker;
    + 31 		
    + 32 		marker.replaceNode(node);
    + 33 		return node;
    + 34 	},
    + 35 	
    + 36 	removeTrailingWhitespace: function(block) {
    + 37 		if(!block) return;
    + 38 		
    + 39 		// TODO: reimplement to handle atomic tags and so on. (use DomTree)
    + 40 		if(this.tree.isBlockContainer(block)) return;
    + 41 		if(this.isEmptyBlock(block)) return;
    + 42 		
    + 43 		var text = block.innerText;
    + 44 		var lastCharCode = text.charCodeAt(text.length - 1);
    + 45 		if(text.length <= 1 || ![32,160].include(lastCharCode)) return;
    + 46 		
    + 47 		var node = block;
    + 48 		
    + 49 		while(node && node.nodeType != 3) node = node.lastChild;
    + 50 		
    + 51 		if(!node) return;
    + 52 		
    + 53 		// DO NOT REMOVE OR MODIFY FOLLOWING CODE:
    + 54 		//
    + 55 		// Modifying following code crash IE7
    + 56 		var nodeValue = node.nodeValue;
    + 57 		if(nodeValue.length <= 1) {
    + 58 			this.deleteNode(node, true);
    + 59 		} else {
    + 60 			node.nodeValue = nodeValue.substring(0, nodeValue.length - 1);
    + 61 		}
    + 62 	},
    + 63 	
    + 64 	correctEmptyElement: function(element) {
    + 65 		if(!element || element.nodeType != 1 || this.tree.isAtomic(element)) return;
    + 66 		
    + 67 		if(element.firstChild) {
    + 68 			this.correctEmptyElement(element.firstChild);
    + 69 		} else {
    + 70 			element.innerHTML = " ";
    + 71 		}
    + 72 	},
    + 73 
    + 74 	copyAttributes: function(from, to, copyId) {
    + 75 		to.mergeAttributes(from, !copyId);
    + 76 	},
    + 77 
    + 78 	correctParagraph: function() {
    + 79 		if(!this.hasFocus()) return false;
    + 80 		if(this.hasSelection()) return false;
    + 81 		
    + 82 		var block = this.getCurrentElement();
    + 83 		
    + 84 		if(block.nodeName == "BODY") {
    + 85 			// check for atomic block element such as HR
    + 86 			block = this.insertNode(this.makeEmptyParagraph());
    + 87 			var next = block.nextSibling;
    + 88 			if(this.tree.isAtomic(next)) {
    + 89 				block = this.insertNodeAt(block, next, "after");
    + 90 				this.placeCaretAtStartOf(block);
    + 91 				
    + 92 				var nextBlock = this.tree.findForward(
    + 93 					block,
    + 94 					function(node) {return this.tree.isBlock(node) && !this.tree.isBlockOnlyContainer(node)}.bind(this)
    + 95 				);
    + 96 				if(nextBlock) {
    + 97 					this.deleteNode(block);
    + 98 					this.placeCaretAtStartOf(nextBlock);
    + 99 				}
    +100 				return true;
    +101 			} else {
    +102 				var nextBlock = this.tree.findForward(
    +103 					block,
    +104 					function(node) {return this.tree.isBlock(node) && !this.tree.isBlockOnlyContainer(node)}.bind(this)
    +105 				);
    +106 				if(nextBlock) {
    +107 					this.deleteNode(block);
    +108 					this.placeCaretAtStartOf(nextBlock);
    +109 				}
    +110 				return true;
    +111 			}
    +112 		} else {
    +113 			block = this.getCurrentBlockElement();
    +114 			if(block.nodeType == 3) block = block.parentNode;
    +115 			
    +116 			if(this.tree.hasMixedContents(block)) {
    +117 				var marker = this.pushMarker();
    +118 				this.wrapAllInlineOrTextNodesAs("P", block, true);
    +119 				this.popMarker(true);
    +120 				return true;
    +121 			} else if((this.tree.isTextOrInlineNode(block.previousSibling) || this.tree.isTextOrInlineNode(block.nextSibling)) && this.tree.hasMixedContents(block.parentNode)) {
    +122 				// IE?서??Block?Inline/Text??접??경우 getCurrentElement ?이 ?작?한??
    +123 				// ?라???재 Block 주?까? ?번???아주어???다.
    +124 				this.wrapAllInlineOrTextNodesAs("P", block.parentNode, true);
    +125 				return true;
    +126 			} else {
    +127 				return false;
    +128 			}
    +129 		}
    +130 	},
    +131 	
    +132 	
    +133 	
    +134 	//////
    +135 	// Commands
    +136 	execCommand: function(commandId, param) {
    +137 		return this.doc.execCommand(commandId, false, param);
    +138 	},
    +139 	
    +140 	applyBackgroundColor: function(color) {
    +141 		this.execCommand("BackColor", color);
    +142 	},
    +143 	
    +144 	applyEmphasis: function() {
    +145 		// Generate <i> tag. It will be replaced with <emphasis> tag during cleanup phase.
    +146 		this.execCommand("Italic");
    +147 	},
    +148 	applyStrongEmphasis: function() {
    +149 		// Generate <b> tag. It will be replaced with <strong> tag during cleanup phase.
    +150 		this.execCommand("Bold");
    +151 	},
    +152 	applyStrike: function() {
    +153 		// Generate <strike> tag. It will be replaced with <style class="strike"> tag during cleanup phase.
    +154 		this.execCommand("strikethrough");
    +155 	},
    +156 	applyUnderline: function() {
    +157 		// Generate <u> tag. It will be replaced with <em class="underline"> tag during cleanup phase.
    +158 		this.execCommand("underline");
    +159 	},
    +160 	applyRemoveFormat: function() {
    +161 		this.execCommand("RemoveFormat");
    +162 		this.execCommand("Unlink");
    +163 	},
    +164 	execHeading: function(level) {
    +165 		this.execCommand("FormatBlock", "<H" + level + ">");
    +166 	},
    +167 
    +168 
    +169 
    +170 	//////
    +171 	// Focus/Caret/Selection
    +172 	
    +173 	focus: function() {
    +174 		this.win.focus();
    +175 		
    +176 		// ?게 ?으?초기??caret??P 밖에 ?치?면??		// getCurrentElement??면 P?리턴?는 기이???상??발생.
    +177 		if(!this._focusedBefore) {
    +178 			this.correctParagraph();
    +179 			this.placeCaretAtStartOf(this.getCurrentBlockElement());
    +180 			this._focusedBefore = true;
    +181 		}
    +182 	},
    +183 
    +184 	sel: function() {
    +185 		return this.doc.selection;
    +186 	},
    +187 	
    +188 	rng: function() {
    +189 		try {
    +190 			var sel = this.sel();
    +191 			return (sel == null) ? null : sel.createRange();
    +192 		} catch(ignored) {
    +193 			// IE often fails
    +194 			return null;
    +195 		}
    +196 	},
    +197 	
    +198 	hasSelection: function() {
    +199 		var selectionType = this.sel().type.toLowerCase();
    +200 		if("none" == selectionType) return false;
    +201 		if("text" == selectionType && this.getSelectionAsHtml().length == 0) return false;
    +202 		return true;
    +203 	},
    +204 	deleteSelection: function() {
    +205 		if(this.getSelectionAsText() != "") this.sel().clear();
    +206 	},
    +207 	
    +208 	placeCaretAtStartOf: function(element) {
    +209 		// If there's no empty span, caret sometimes moves into a previous node.
    +210 		var ph = this.insertNodeAt(this.createElement("SPAN"), element, "start");
    +211 		this.selectElement(ph);
    +212 		this.collapseSelection(false);
    +213 		this.deleteNode(ph);
    +214 	},
    +215 	
    +216 	selectElement: function(element, entireElement) {
    +217 		if(!element) throw "[element] is null";
    +218 		if(element.nodeType != 1) throw "[element] is not an element";
    +219 		
    +220 		var rng = this.rng();
    +221 		rng.moveToElementText(element);
    +222 		rng.select();
    +223 	},
    +224 
    +225 	selectBlocksBetween: function(start, end) {
    +226 		var rng = this.rng();
    +227 		var rngTemp = this.rng();
    +228 
    +229 		rngTemp.moveToElementText(start);
    +230 		rng.setEndPoint("StartToStart", rngTemp);
    +231 		
    +232 		rngTemp.moveToElementText(end);
    +233 		rng.setEndPoint("EndToEnd", rngTemp);
    +234 		
    +235 		rng.select();
    +236 	},
    +237 	
    +238 	collapseSelection: function(toStart) {
    +239 		var rng = this.rng();
    +240 		rng.collapse(toStart);
    +241 		rng.select();
    +242 	},
    +243 	
    +244 	getSelectionAsHtml: function() {
    +245 		var rng = this.rng()
    +246 		return rng && rng.htmlText ? rng.htmlText : ""
    +247 	},
    +248 	
    +249 	getSelectionAsText: function() {
    +250 		var rng = this.rng();
    +251 		return rng && rng.text ? rng.text : "";
    +252 	},
    +253 	
    +254 	hasImportantAttributes: function(element) {
    +255 		return !!(element.id || element.className || element.style.cssText);
    +256 	},
    +257 
    +258 	isEmptyBlock: function(element) {
    +259 		if(!element.hasChildNodes()) return true;
    +260 		if(element.nodeType == 3 && !element.nodeValue) return true;
    +261 		if([" ", " ", ""].include(element.innerHTML)) return true;
    +262 		
    +263 		return false;
    +264 	},
    +265 	
    +266 	getLastChild: function(element) {
    +267 		if(!element || !element.hasChildNodes()) return null;
    +268 		
    +269 		var nodes = $A(element.childNodes).reverse();
    +270 		
    +271 		for(var i = 0; i < nodes.length; i++) {
    +272 			if(nodes[i].nodeType != 3 || nodes[i].nodeValue.length != 0) return nodes[i];
    +273 		}
    +274 		
    +275 		return null;
    +276 	},
    +277 	
    +278 	getCurrentElement: function() {
    +279 		if(this.sel().type.toLowerCase() == "control") return this.rng().item(0);
    +280 		return this.rng().parentElement();
    +281 	},
    +282 	
    +283 	getBlockElementAtSelectionStart: function() {
    +284 		var rng = this.rng();
    +285 		var dup = rng.duplicate();
    +286 		dup.collapse(true);
    +287 		
    +288 		var result = this.getParentBlockElementOf(dup.parentElement());
    +289 		if(result.nodeName == "BODY") result = result.firstChild;
    +290 		
    +291 		return result;
    +292 	},
    +293 	
    +294 	getBlockElementAtSelectionEnd: function() {
    +295 		var rng = this.rng();
    +296 		var dup = rng.duplicate();
    +297 		dup.collapse(false);
    +298 		
    +299 		var result = this.getParentBlockElementOf(dup.parentElement());
    +300 		if(result.nodeName == "BODY") result = result.lastChild;
    +301 
    +302 		return result;
    +303 	},
    +304 	
    +305 	getBlockElementsAtSelectionEdge: function(naturalOrder, ignoreEmptyEdges) {
    +306 		return [
    +307 			this.getBlockElementAtSelectionStart(),
    +308 			this.getBlockElementAtSelectionEnd()
    +309 		];
    +310 	},
    +311 	
    +312 	isCaretAtBlockStart: function() {
    +313 		if(this.isCaretAtEmptyBlock()) return true;
    +314 		if(this.hasSelection()) return false;
    +315 		var node = this.getCurrentBlockElement();
    +316 		var marker = this.pushMarker();
    +317 		
    +318 		var isTrue = false;
    +319 		while (node = this.getFirstChild(node)) {
    +320 			if (node == marker) {
    +321 				isTrue = true;
    +322 				break;
    +323 			}
    +324 		}
    +325 		
    +326 		this.popMarker();
    +327 		
    +328 		return isTrue;
    +329 	},
    +330 	isCaretAtBlockEnd: function() {
    +331 		if(this.isCaretAtEmptyBlock()) return true;
    +332 		if(this.hasSelection()) return false;
    +333 		var node = this.getCurrentBlockElement();
    +334 		var marker = this.pushMarker();
    +335 		var isTrue = false;
    +336 		while (node = this.getLastChild(node)) {
    +337 			var nodeValue = node.nodeValue;
    +338 			
    +339 			if (node == marker) {
    +340 				isTrue = true;
    +341 				break;
    +342 			} else if(
    +343 				node.nodeType == 3 &&
    +344 				node.previousSibling == marker &&
    +345 				(nodeValue == " " || (nodeValue.length == 1 && nodeValue.charCodeAt(0) == 160))
    +346 			) {
    +347 				isTrue = true;
    +348 				break;
    +349 			}
    +350 		}
    +351 		
    +352 		this.popMarker();
    +353 		return isTrue;
    +354 	},
    +355 	saveSelection: function() {
    +356 		return this.rng();
    +357 	},
    +358 	restoreSelection: function(bookmark) {
    +359 		bookmark.select();
    +360 	}
    +361 });
    +362 
    \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_09.html b/modules/editor/skins/xquared/doc/api/src_09.html new file mode 100644 index 000000000..030d7b252 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/src_09.html @@ -0,0 +1,382 @@ +
      1 /**
    +  2  * RichDom for W3C Standard Engine
    +  3  */
    +  4 xq.RichDomW3 = Class.create(xq.RichDom, {
    +  5 	insertNode: function(node) {
    +  6 		var rng = this.rng();
    +  7 		rng.insertNode(node);
    +  8 		rng.selectNode(node);
    +  9 		rng.collapse(false);
    + 10 		return node;
    + 11 	},
    + 12 
    + 13 	removeTrailingWhitespace: function(block) {
    + 14 		// TODO: do nothing
    + 15 	},
    + 16 
    + 17 	getOuterHTML: function(element) {
    + 18 		var div = element.ownerDocument.createElement("div");
    + 19 		div.appendChild(element.cloneNode(true));
    + 20 		return div.innerHTML;
    + 21 	},
    + 22 	
    + 23 	correctEmptyElement: function(element) {
    + 24 		if(!element || element.nodeType != 1 || this.tree.isAtomic(element)) return;
    + 25 		
    + 26 		if(element.firstChild)
    + 27 			this.correctEmptyElement(element.firstChild);
    + 28 		else
    + 29 			element.appendChild(this.makePlaceHolder());
    + 30 	},
    + 31 	
    + 32 	correctParagraph: function() {
    + 33 		if(this.hasSelection()) return false;
    + 34 		
    + 35 		var block = this.getCurrentElement();
    + 36 		var modified = false;
    + 37 		
    + 38 		if(this.tree.isBlockOnlyContainer(block)) {
    + 39 			this.execCommand("InsertParagraph");
    + 40 			
    + 41 			// check for atomic block element such as HR
    + 42 			var newBlock = this.getCurrentElement();
    + 43 			if(this.tree.isAtomic(newBlock.previousSibling)) {
    + 44 				var nextBlock = this.tree.findForward(
    + 45 					newBlock,
    + 46 					function(node) {return this.tree.isBlock(node) && !this.tree.isBlockOnlyContainer(node)}.bind(this)
    + 47 				);
    + 48 				if(nextBlock) {
    + 49 					this.deleteNode(newBlock);
    + 50 					this.placeCaretAtStartOf(nextBlock);
    + 51 				}
    + 52 			}
    + 53 			modified = true;
    + 54 		} else if(this.tree.hasMixedContents(block)) {
    + 55 			this.wrapAllInlineOrTextNodesAs("P", block, true);
    + 56 			modified = true;
    + 57 		}
    + 58 		
    + 59 		block = this.getCurrentElement();
    + 60 		if(this.tree.isBlock(block) && !this._hasPlaceHolderAtEnd(block)) {
    + 61 			block.appendChild(this.makePlaceHolder());
    + 62 			modified = true;
    + 63 		}
    + 64 		
    + 65 		if(this.tree.isBlock(block)) {
    + 66 			var parentsLastChild = block.parentNode.lastChild;
    + 67 			if(this.isPlaceHolder(parentsLastChild)) {
    + 68 				this.deleteNode(parentsLastChild);
    + 69 				modified = true;
    + 70 			}
    + 71 		}
    + 72 		
    + 73 		return modified;
    + 74 	},
    + 75 	
    + 76 	_hasPlaceHolderAtEnd: function(block) {
    + 77 		if(!block.hasChildNodes()) return false;
    + 78 		return this.isPlaceHolder(block.lastChild) || this._hasPlaceHolderAtEnd(block.lastChild);
    + 79 	},
    + 80 	
    + 81 	applyBackgroundColor: function(color) {
    + 82 		this.execCommand("styleWithCSS", "true");
    + 83 		this.execCommand("hilitecolor", color);
    + 84 		this.execCommand("styleWithCSS", "false");
    + 85 		
    + 86 		// 0. Save current selection
    + 87 		var bookmark = this.saveSelection();
    + 88 		
    + 89 		// 1. Get selected blocks
    + 90 		var blocks = this.getSelectedBlockElements();
    + 91 		if(blocks.length == 0) return;
    + 92 		
    + 93 		// 2. Apply background-color to all adjust inline elements
    + 94 		// 3. Remove background-color from blocks
    + 95 		for(var i = 0; i < blocks.length; i++) {
    + 96 			if((i == 0 || i == blocks.length-1) && !blocks[i].style.backgroundColor) continue;
    + 97 			
    + 98 			var spans = this.wrapAllInlineOrTextNodesAs("SPAN", blocks[i], true);
    + 99 			for(var j = 0; j < spans.length; j++) {
    +100 				spans[j].style.backgroundColor = color;
    +101 			}
    +102 			blocks[i].style.backgroundColor = "";
    +103 		}
    +104 		
    +105 		// 4. Restore selection
    +106 		this.restoreSelection(bookmark);
    +107 	},
    +108 	
    +109 	
    +110 	
    +111 	
    +112 	//////
    +113 	// Commands
    +114 	execCommand: function(commandId, param) {
    +115 		return this.doc.execCommand(commandId, false, param || null);
    +116 	},
    +117 	
    +118 	saveSelection: function() {
    +119 		var rng = this.rng();
    +120 		return [rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset];
    +121 	},
    +122 	
    +123 	restoreSelection: function(bookmark) {
    +124 		var rng = this.rng();
    +125 		rng.setStart(bookmark[0], bookmark[1]);
    +126 		rng.setEnd(bookmark[2], bookmark[3]);
    +127 	},
    +128 	
    +129 	applyRemoveFormat: function() {
    +130 		this.execCommand("RemoveFormat");
    +131 		this.execCommand("Unlink");
    +132 	},
    +133 	applyEmphasis: function() {
    +134 		// Generate <i> tag. It will be replaced with <emphasis> tag during cleanup phase.
    +135 		this.execCommand("styleWithCSS", "false");
    +136 		this.execCommand("italic");
    +137 	},
    +138 	applyStrongEmphasis: function() {
    +139 		// Generate <b> tag. It will be replaced with <strong> tag during cleanup phase.
    +140 		this.execCommand("styleWithCSS", "false");
    +141 		this.execCommand("bold");
    +142 	},
    +143 	applyStrike: function() {
    +144 		// Generate <strike> tag. It will be replaced with <style class="strike"> tag during cleanup phase.
    +145 		this.execCommand("styleWithCSS", "false");
    +146 		this.execCommand("strikethrough");
    +147 	},
    +148 	applyUnderline: function() {
    +149 		// Generate <u> tag. It will be replaced with <em class="underline"> tag during cleanup phase.
    +150 		this.execCommand("styleWithCSS", "false");
    +151 		this.execCommand("underline");
    +152 	},
    +153 	execHeading: function(level) {
    +154 		this.execCommand("Heading", "H" + level);
    +155 	},
    +156 
    +157 
    +158 
    +159 	//////
    +160 	// Focus/Caret/Selection
    +161 	
    +162 	focus: function() {
    +163 		setTimeout(this._focus.bind(this), 0);
    +164 	},
    +165 	
    +166 	/** @private */
    +167 	_focus: function() {
    +168 		this.win.focus();
    +169 		if(!this.hasSelection() && this.getCurrentElement().nodeName == "HTML") {
    +170 			this.selectElement(this.doc.body.firstChild);
    +171 			this.collapseSelection(true);
    +172 		}
    +173 	},
    +174 
    +175 	sel: function() {
    +176 		return this.win.getSelection();
    +177 	},
    +178 	
    +179 	rng: function() {
    +180 		var sel = this.sel();
    +181 		return (sel == null || sel.rangeCount == 0) ? null : sel.getRangeAt(0);
    +182 	},
    +183 
    +184 	hasSelection: function() {
    +185 		var sel = this.sel();
    +186 		return sel && !sel.isCollapsed;
    +187 	},
    +188 	
    +189 	deleteSelection: function() {
    +190 		this.rng().deleteContents();
    +191 		this.sel().collapseToStart();
    +192 	},
    +193 	
    +194 	selectElement: function(element, entireElement) {throw "Not implemented yet"},
    +195 
    +196 	selectBlocksBetween: function(start, end) {
    +197 		// required to avoid FF selection bug.
    +198 		try {
    +199 			if(!xq.Browser.isMac) this.doc.execCommand("SelectAll", false, null);
    +200 		} catch(ignored) {}
    +201 		
    +202 		var rng = this.rng();
    +203 		rng.setStart(start.firstChild, 0);
    +204 		rng.setEnd(end, end.childNodes.length);
    +205 	},
    +206 
    +207 	collapseSelection: function(toStart) {
    +208 		this.rng().collapse(toStart);
    +209 	},
    +210 	
    +211 	placeCaretAtStartOf: function(element) {
    +212 		while(this.tree.isBlock(element.firstChild)) {
    +213 			element = element.firstChild;
    +214 		}
    +215 		this.selectElement(element, false);
    +216 		this.collapseSelection(true);
    +217 	},
    +218 	
    +219 	getSelectionAsHtml: function() {
    +220 		var container = document.createElement("div");
    +221 		container.appendChild(this.rng().cloneContents());
    +222 		return container.innerHTML;
    +223 	},
    +224 	
    +225 	getSelectionAsText: function() {
    +226 		return this.rng().toString()
    +227 	},
    +228 	
    +229 	hasImportantAttributes: function(element) {
    +230 		return !!(element.id || element.className || element.style.cssText);
    +231 	},
    +232 	
    +233 	isEmptyBlock: function(element) {
    +234 		if(!element.hasChildNodes()) return true;
    +235 		var children = element.childNodes;
    +236 		for(var i = 0; i < children.length; i++) {
    +237 			if(!this.isPlaceHolder(children[i]) && !this.isEmptyTextNode(children[i])) return false;
    +238 		}
    +239 		return true;
    +240 	},
    +241 	
    +242 	getLastChild: function(element) {
    +243 		if(!element || !element.hasChildNodes()) return null;
    +244 		
    +245 		var nodes = $A(element.childNodes).reverse();
    +246 		
    +247 		for(var i = 0; i < nodes.length; i++) {
    +248 			if(!this.isPlaceHolder(nodes[i]) && !this.isEmptyTextNode(nodes[i])) return nodes[i];
    +249 		}
    +250 		return null;
    +251 	},
    +252 	
    +253 	getCurrentElement: function() {
    +254 		var rng = this.rng();
    +255 		if(!rng) return null;
    +256 		
    +257 		var container = rng.startContainer;
    +258 		return container.nodeType == 3 ? container.parentNode : container;
    +259 	},
    +260 
    +261 	getBlockElementsAtSelectionEdge: function(naturalOrder, ignoreEmptyEdges) {
    +262 		var start = this.getBlockElementAtSelectionStart();
    +263 		var end = this.getBlockElementAtSelectionEnd();
    +264 		
    +265 		var reversed = false;
    +266 		
    +267 		if(naturalOrder && start != end && this.tree.checkTargetBackward(start, end)) {
    +268 			var temp = start;
    +269 			start = end;
    +270 			end = temp;
    +271 			
    +272 			reversed = true;
    +273 		}
    +274 		
    +275 		if(ignoreEmptyEdges && start != end) {
    +276 			// TODO - Firefox sometimes selects one more block.
    +277 /*
    +278 			
    +279 			var sel = this.sel();
    +280 			if(reversed) {
    +281 				if(sel.focusNode.nodeType == 1) start = start.nextSibling;
    +282 				if(sel.anchorNode.nodeType == 3 && sel.focusOffset == 0) end = end.previousSibling;
    +283 			} else {
    +284 				if(sel.anchorNode.nodeType == 1) start = start.nextSibling;
    +285 				if(sel.focusNode.nodeType == 3 && sel.focusOffset == 0) end = end.previousSibling;
    +286 			}
    +287 */
    +288 		}
    +289 		
    +290 		return [start, end];
    +291 	},
    +292 	
    +293 	getBlockElementAtSelectionStart: function() {
    +294 		var block = this.getParentBlockElementOf(this.sel().anchorNode);
    +295 		
    +296 		// find bottom-most first block child
    +297 		while(this.tree.isBlockContainer(block) && block.firstChild && this.tree.isBlock(block.firstChild)) {
    +298 			block = block.firstChild;
    +299 		}
    +300 		
    +301 		return block;
    +302 	},
    +303 	
    +304 	getBlockElementAtSelectionEnd: function() {
    +305 		var block = this.getParentBlockElementOf(this.sel().focusNode);
    +306 		
    +307 		// find bottom-most last block child
    +308 		while(this.tree.isBlockContainer(block) && block.lastChild && this.tree.isBlock(block.lastChild)) {
    +309 			block = block.lastChild;
    +310 		}
    +311 		
    +312 		return block;
    +313 	},
    +314 
    +315 	isCaretAtBlockStart: function() {
    +316 		if(this.isCaretAtEmptyBlock()) return true;
    +317 		if(this.hasSelection()) return false;
    +318 		var rng = this.rng();
    +319 		var node = this.getCurrentBlockElement();
    +320 		var isTrue = false;
    +321 		
    +322 		if(node == rng.startContainer) {
    +323 			var marker = this.pushMarker();
    +324 			while (node = this.getFirstChild(node)) {
    +325 				if (node == marker) {
    +326 					isTrue = true;
    +327 					break;
    +328 				}
    +329 			}
    +330 			this.popMarker();
    +331 		} else {
    +332 			while (node = node.firstChild) {
    +333 				if (node == rng.startContainer && rng.startOffset == 0) {
    +334 					isTrue = true;
    +335 					break;
    +336 				}
    +337 			}
    +338 		}
    +339 		
    +340 		return isTrue;
    +341 	},
    +342 	
    +343 	isCaretAtBlockEnd: function() {
    +344 		if(this.isCaretAtEmptyBlock()) return true;
    +345 		if(this.hasSelection()) return false;
    +346 		
    +347 		var rng = this.rng();
    +348 		var node = this.getCurrentBlockElement();
    +349 		var isTrue = false;
    +350 		
    +351 		if(node == rng.startContainer) {
    +352 			var marker = this.pushMarker();
    +353 			while (node = this.getLastChild(node)) {
    +354 				if ((node == marker) || (this.isPlaceHolder(node) && node.previousSibling == marker)) {
    +355 					isTrue = true;
    +356 					break;
    +357 				}
    +358 			}
    +359 			this.popMarker();
    +360 		} else {
    +361 			while (node = this.getLastChild(node)) {
    +362 				if (node == rng.endContainer && rng.endContainer.nodeType == 1) {
    +363 					isTrue = true;
    +364 					break;
    +365 				} else if (node == rng.endContainer && rng.endOffset == node.nodeValue.length) {
    +366 					isTrue = true;
    +367 					break;
    +368 				}
    +369 			}
    +370 		}
    +371 		
    +372 		return isTrue;
    +373 	}
    +374 });
    +375 
    \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_10.html b/modules/editor/skins/xquared/doc/api/src_10.html new file mode 100644 index 000000000..9eb4955a5 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/src_10.html @@ -0,0 +1,91 @@ +
      1 /**
    +  2  * RichDom for Webkit
    +  3  */
    +  4 xq.RichDomWebkit = Class.create(xq.RichDomW3, {
    +  5 	makePlaceHolder: function() {
    +  6 		var holder = this.createElement("BR");
    +  7 		holder.className = "webkit-block-placeholder";
    +  8 		return holder;
    +  9 	},
    + 10 	
    + 11 	makePlaceHolderString: function() {
    + 12 		return '<br class="webkit-block-placeholder" />';
    + 13 	},
    + 14 	
    + 15 	makeEmptyParagraph: function() {
    + 16 		return this.createElementFromHtml('<p><br class="webkit-block-placeholder" /></p>');
    + 17 	},
    + 18 	
    + 19 	isPlaceHolder: function(node) {
    + 20 		return node.nodeName == "BR" && node.className == "webkit-block-placeholder";
    + 21 	},
    + 22 
    + 23 	rng: function() {
    + 24 		var sel = this.sel();
    + 25 		var rng = this.doc.createRange();
    + 26 		if (!this._rng ||
    + 27 			this._anchorNode != sel.anchorNode ||
    + 28 			this._anchorOffset != sel.anchorOffset ||
    + 29 			this._focusNode != sel.focusNode ||
    + 30 			this._focusOffset != sel.focusOffset ) {
    + 31 
    + 32 			if (sel.type != 'None') {
    + 33 				rng.setStart(sel.anchorNode, sel.anchorOffset);
    + 34 				rng.setEnd(sel.focusNode, sel.focusOffset);
    + 35 			}
    + 36 			this._anchorNode = sel.anchorNode;
    + 37 			this._anchorOffset = sel.anchorOffset;
    + 38 			this._focusNode = sel.focusNode;
    + 39 			this._focusOffset = sel.focusOffset;
    + 40 			this._rng = rng;
    + 41 		}
    + 42 		return this._rng;
    + 43 	},
    + 44 
    + 45 	selectElement: function(element, entireElement) {
    + 46 		if(!element) throw "[element] is null";
    + 47 		if(element.nodeType != 1) throw "[element] is not an element";
    + 48 		
    + 49 		var rng = this.rng();
    + 50 		if(entireElement) {
    + 51 			rng.selectNode(element);
    + 52 		} else {
    + 53 			rng.selectNodeContents(element);
    + 54 		}
    + 55 		this._setSelectionByRange(rng);
    + 56 	},
    + 57 
    + 58 	deleteSelection: function() {
    + 59 		this.rng().deleteContents();
    + 60 	},
    + 61 
    + 62 	collapseSelection: function(toStart) {
    + 63 		var rng = this.rng();
    + 64 		rng.collapse(toStart);
    + 65 		this._setSelectionByRange(rng);
    + 66 	},
    + 67 
    + 68 	getSelectionAsHtml: function() {
    + 69 		var container = this.createElement("div");
    + 70 		var rng = this.rng();
    + 71 		var contents = this.rng().cloneContents();
    + 72 		if(contents) container.appendChild(contents);
    + 73 		return container.innerHTML;
    + 74 	},
    + 75 	
    + 76 	_setSelectionByRange: function(rng) {
    + 77 		var sel = this.sel();
    + 78 		sel.setBaseAndExtent(rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset);
    + 79 		this._anchorNode = sel.anchorNode;
    + 80 		this._anchorOffset = sel.anchorOffset;
    + 81 		this._focusNode = sel.focusNode;
    + 82 		this._focusOffset = sel.focusOffset;
    + 83 	}
    + 84 });
    \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_11.html b/modules/editor/skins/xquared/doc/api/src_11.html new file mode 100644 index 000000000..58f5fb053 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/src_11.html @@ -0,0 +1,209 @@ +
      1 xq.RichTable = Class.create({
    +  2 	initialize: function(rdom, table) {
    +  3 		this.rdom = rdom;
    +  4 		this.table = table;
    +  5 	},
    +  6 	insertNewRowAt: function(tr, where) {
    +  7 		var row = this.rdom.createElement("TR");
    +  8 		var cells = tr.cells;
    +  9 		for(var i = 0; i < cells.length; i++) {
    + 10 			var cell = this.rdom.createElement(cells[i].nodeName);
    + 11 			this.rdom.correctEmptyElement(cell);
    + 12 			row.appendChild(cell);
    + 13 		}
    + 14 		return this.rdom.insertNodeAt(row, tr, where);
    + 15 	},
    + 16 	insertNewCellAt: function(cell, where) {
    + 17 		// collect cells;
    + 18 		var cells = [];
    + 19 		var x = this.getXIndexOf(cell);
    + 20 		var y = 0;
    + 21 		while(true) {
    + 22 			var cur = this.getCellAt(x, y);
    + 23 			if(!cur) break;
    + 24 			cells.push(cur);
    + 25 			y++;
    + 26 		}
    + 27 		
    + 28 		// insert new cells
    + 29 		for(var i = 0; i < cells.length; i++) {
    + 30 			var cell = this.rdom.createElement(cells[i].nodeName);
    + 31 			this.rdom.correctEmptyElement(cell);
    + 32 			this.rdom.insertNodeAt(cell, cells[i], where);
    + 33 		}
    + 34 	},
    + 35 	deleteRow: function(tr) {
    + 36 		return this.rdom.removeBlock(tr);
    + 37 	},
    + 38 	deleteCell: function(cell) {
    + 39 		if(!cell.previousSibling && !cell.nextSibling) {
    + 40 			this.rdom.deleteNode(this.table);
    + 41 			return;
    + 42 		}
    + 43 		
    + 44 		// collect cells;
    + 45 		var cells = [];
    + 46 		var x = this.getXIndexOf(cell);
    + 47 		var y = 0;
    + 48 		while(true) {
    + 49 			var cur = this.getCellAt(x, y);
    + 50 			if(!cur) break;
    + 51 			cells.push(cur);
    + 52 			y++;
    + 53 		}
    + 54 		
    + 55 		for(var i = 0; i < cells.length; i++) {
    + 56 			this.rdom.deleteNode(cells[i]);
    + 57 		}
    + 58 	},
    + 59 	getPreviousCellOf: function(cell) {
    + 60 		if(cell.previousSibling) return cell.previousSibling;
    + 61 		var adjRow = this.getPreviousRowOf(cell.parentNode);
    + 62 		if(adjRow) return adjRow.lastChild;
    + 63 		return null;
    + 64 	},
    + 65 	getNextCellOf: function(cell) {
    + 66 		if(cell.nextSibling) return cell.nextSibling;
    + 67 		var adjRow = this.getNextRowOf(cell.parentNode);
    + 68 		if(adjRow) return adjRow.firstChild;
    + 69 		return null;
    + 70 	},
    + 71 	getPreviousRowOf: function(row) {
    + 72 		if(row.previousSibling) return row.previousSibling;
    + 73 		var rowContainer = row.parentNode;
    + 74 		if(rowContainer.previousSibling && rowContainer.previousSibling.lastChild) return rowContainer.previousSibling.lastChild;
    + 75 		return null;
    + 76 	},
    + 77 	getNextRowOf: function(row) {
    + 78 		if(row.nextSibling) return row.nextSibling;
    + 79 		var rowContainer = row.parentNode;
    + 80 		if(rowContainer.nextSibling && rowContainer.nextSibling.firstChild) return rowContainer.nextSibling.firstChild;
    + 81 		return null;
    + 82 	},
    + 83 	getAboveCellOf: function(cell) {
    + 84 		var row = this.getPreviousRowOf(cell.parentNode);
    + 85 		if(!row) return null;
    + 86 		
    + 87 		var x = this.getXIndexOf(cell);
    + 88 		return row.cells[x];
    + 89 	},
    + 90 	getBelowCellOf: function(cell) {
    + 91 		var row = this.getNextRowOf(cell.parentNode);
    + 92 		if(!row) return null;
    + 93 		
    + 94 		var x = this.getXIndexOf(cell);
    + 95 		return row.cells[x];
    + 96 	},
    + 97 	getXIndexOf: function(cell) {
    + 98 		var row = cell.parentNode;
    + 99 		for(var i = 0; i < row.cells.length; i++) {
    +100 			if(row.cells[i] == cell) return i;
    +101 		}
    +102 		
    +103 		return -1;
    +104 	},
    +105 	getYIndexOf: function(cell) {
    +106 		var y = -1;
    +107 		
    +108 		// find y
    +109 		var group = row.parentNode;
    +110 		for(var i = 0; i <group.rows.length; i++) {
    +111 			if(group.rows[i] == row) {
    +112 				y = i;
    +113 				break;
    +114 			}
    +115 		}
    +116 		if(this.hasHeadingAtTop() && group.nodeName == "TBODY") y = y + 1;
    +117 		
    +118 		return y;
    +119 	},
    +120 	/**
    +121 	 * TODO: Not used. Delete or not?
    +122 	 */
    +123 	getLocationOf: function(cell) {
    +124 		var x = this.getXIndexOf(cell);
    +125 		var y = this.getYIndexOf(cell);
    +126 		return {x:x, y:y};
    +127 	},
    +128 	getCellAt: function(col, row) {
    +129 		var row = this.getRowAt(row);
    +130 		return (row && row.cells.length > col) ? row.cells[col] : null;
    +131 	},
    +132 	getRowAt: function(index) {
    +133 		if(this.hasHeadingAtTop()) {
    +134 			return index == 0 ? this.table.tHead.rows[0] : this.table.tBodies[0].rows[index - 1];
    +135 		} else {
    +136 			var rows = this.table.tBodies[0].rows;
    +137 			return (rows.length > index) ? rows[index] : null;
    +138 		}
    +139 	},
    +140 	getDom: function() {
    +141 		return this.table;
    +142 	},
    +143 	hasHeadingAtTop: function() {
    +144 		return !!(this.table.tHead && this.table.tHead.rows[0]);
    +145 	},
    +146 	hasHeadingAtLeft: function() {
    +147 		return this.table.tBodies[0].rows[0].cells[0].nodeName == "TH";
    +148 	},
    +149 	correctEmptyCells: function() {
    +150 		var cells = $A(this.table.getElementsByTagName("TH"));
    +151 		cells.push($A(this.table.getElementsByTagName("TD")));
    +152 		cells = cells.flatten();
    +153 		
    +154 		for(var i = 0; i < cells.length; i++) {
    +155 			if(this.rdom.isEmptyBlock(cells[i])) this.rdom.correctEmptyElement(cells[i])
    +156 		}
    +157 	}
    +158 });
    +159 
    +160 xq.RichTable.create = function(rdom, cols, rows, headerPositions) {
    +161 	if(["t", "tl", "lt"].include(headerPositions)) var headingAtTop = true
    +162 	if(["l", "tl", "lt"].include(headerPositions)) var headingAtLeft = true
    +163 
    +164 	var sb = []
    +165 	sb.push('<table class="datatable">')
    +166 	
    +167 	// thead
    +168 	if(headingAtTop) {
    +169 		sb.push('<thead><tr>')
    +170 		for(var i = 0; i < cols; i++) sb.push('<th></th>')
    +171 		sb.push('</tr></thead>')
    +172 		rows -= 1
    +173 	}
    +174 		
    +175 	// tbody
    +176 	sb.push('<tbody>')
    +177 	for(var i = 0; i < rows; i++) {
    +178 		sb.push('<tr>')
    +179 		
    +180 		for(var j = 0; j < cols; j++) {
    +181 			if(headingAtLeft && j == 0) {
    +182 				sb.push('<th></th>')
    +183 			} else {
    +184 				sb.push('<td></td>')
    +185 			}
    +186 		}
    +187 		
    +188 		sb.push('</tr>')
    +189 	}
    +190 	sb.push('</tbody>')
    +191 	
    +192 	sb.push('</table>')
    +193 	
    +194 	// create DOM element
    +195 	var container = rdom.createElement("div");
    +196 	container.innerHTML = sb.join("");
    +197 	
    +198 	// correct empty cells and return
    +199 	var rtable = new xq.RichTable(rdom, container.firstChild);
    +200 	rtable.correctEmptyCells();
    +201 	return rtable;
    +202 }
    \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_12.html b/modules/editor/skins/xquared/doc/api/src_12.html new file mode 100644 index 000000000..72b700cd4 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/src_12.html @@ -0,0 +1,135 @@ +
      1 xq.Shortcut = Class.create({
    +  2 	initialize: function(keymapOrExpression) {
    +  3 		this.keymap = (typeof keymapOrExpression == "string") ?
    +  4 			xq.Shortcut.interprete(keymapOrExpression).keymap :
    +  5 			keymapOrExpression;
    +  6 	},
    +  7 	matches: function(e) {
    +  8 		var which = xq.Browser.isGecko && xq.Browser.isMac ? (e.keyCode + "_" + e.charCode) : e.keyCode;
    +  9 		
    + 10 		var keyMatches =
    + 11 			(this.keymap.which == which) ||
    + 12 			(this.keymap.which == 32 && which == 25); // 25 is SPACE in Type-3 keyboard.
    + 13 		
    + 14 		if(typeof e.metaKey == "undefined") e.metaKey = false;
    + 15 		
    + 16 		var modifierMatches = 
    + 17 			(typeof this.keymap.shiftKey == "undefined" || this.keymap.shiftKey == e.shiftKey) &&
    + 18 			(typeof this.keymap.altKey == "undefined" || this.keymap.altKey == e.altKey) &&
    + 19 			(typeof this.keymap.ctrlKey == "undefined" || this.keymap.ctrlKey == e.ctrlKey) &&
    + 20 			(typeof this.keymap.metaKey == "undefined" || this.keymap.metaKey == e.metaKey)
    + 21 		
    + 22 		return modifierMatches && keyMatches;
    + 23 	}
    + 24 });
    + 25 
    + 26 xq.Shortcut.interprete = function(expression) {
    + 27 	expression = expression.toUpperCase();
    + 28 	
    + 29 	var which = xq.Shortcut._interpreteWhich(expression.split("+").pop());
    + 30 	var ctrlKey = xq.Shortcut._interpreteModifier(expression, "CTRL");
    + 31 	var altKey = xq.Shortcut._interpreteModifier(expression, "ALT");
    + 32 	var shiftKey = xq.Shortcut._interpreteModifier(expression, "SHIFT");
    + 33 	var metaKey = xq.Shortcut._interpreteModifier(expression, "META");
    + 34 	
    + 35 	var keymap = {};
    + 36 	
    + 37 	keymap.which = which;
    + 38 	if(typeof ctrlKey != "undefined") keymap.ctrlKey = ctrlKey;
    + 39 	if(typeof altKey != "undefined") keymap.altKey = altKey;
    + 40 	if(typeof shiftKey != "undefined") keymap.shiftKey = shiftKey;
    + 41 	if(typeof metaKey != "undefined") keymap.metaKey = metaKey;
    + 42 	
    + 43 	return new xq.Shortcut(keymap);
    + 44 }
    + 45 
    + 46 xq.Shortcut._interpreteModifier = function(expression, modifierName) {
    + 47 	return expression.match("\\(" + modifierName + "\\)") ?
    + 48 		undefined :
    + 49 			expression.match(modifierName) ?
    + 50 			true : false;
    + 51 }
    + 52 xq.Shortcut._interpreteWhich = function(keyName) {
    + 53 	var which = keyName.length == 1 ?
    + 54 		((xq.Browser.isMac && xq.Browser.isGecko) ? "0_" + keyName.toLowerCase().charCodeAt(0) : keyName.charCodeAt(0)) :
    + 55 		xq.Shortcut._keyNames[keyName];
    + 56 	
    + 57 	if(typeof which == "undefined") throw "Unknown special key name: [" + keyName + "]"
    + 58 	
    + 59 	return which;
    + 60 }
    + 61 xq.Shortcut._keyNames =
    + 62 	xq.Browser.isMac && xq.Browser.isGecko ?
    + 63 	{
    + 64 		BACKSPACE: "8_0",
    + 65 		TAB: "9_0",
    + 66 		RETURN: "13_0",
    + 67 		ENTER: "13_0",
    + 68 		ESC: "27_0",
    + 69 		SPACE: "0_32",
    + 70 		LEFT: "37_0",
    + 71 		UP: "38_0",
    + 72 		RIGHT: "39_0",
    + 73 		DOWN: "40_0",
    + 74 		DELETE: "46_0",
    + 75 		HOME: "36_0",
    + 76 		END: "35_0",
    + 77 		PAGEUP: "33_0",
    + 78 		PAGEDOWN: "34_0",
    + 79 		COMMA: "0_44",
    + 80 		HYPHEN: "0_45",
    + 81 		EQUAL: "0_61",
    + 82 		PERIOD: "0_46",
    + 83 		SLASH: "0_47",
    + 84 		F1: "112_0",
    + 85 		F2: "113_0",
    + 86 		F3: "114_0",
    + 87 		F4: "115_0",
    + 88 		F5: "116_0",
    + 89 		F6: "117_0",
    + 90 		F7: "118_0",
    + 91 		F8: "119_0"
    + 92 	}
    + 93 	:
    + 94 	{
    + 95 		BACKSPACE: 8,
    + 96 		TAB: 9,
    + 97 		RETURN: 13,
    + 98 		ENTER: 13,
    + 99 		ESC: 27,
    +100 		SPACE: 32,
    +101 		LEFT: 37,
    +102 		UP: 38,
    +103 		RIGHT: 39,
    +104 		DOWN: 40,
    +105 		DELETE: 46,
    +106 		HOME: 36,
    +107 		END: 35,
    +108 		PAGEUP: 33,
    +109 		PAGEDOWN: 34,
    +110 		COMMA: 188,
    +111 		HYPHEN: xq.Browser.isTrident ? 189 : 109,
    +112 		EQUAL: xq.Browser.isTrident ? 187 : 61,
    +113 		PERIOD: 190,
    +114 		SLASH: 191,
    +115 		F1:112,
    +116 		F2:113,
    +117 		F3:114,
    +118 		F4:115,
    +119 		F5:116,
    +120 		F6:117,
    +121 		F7:118,
    +122 		F8:119,
    +123 		F9:120,
    +124 		F10:121,
    +125 		F11:122,
    +126 		F12:123
    +127 	}
    +128 
    \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_13.html b/modules/editor/skins/xquared/doc/api/src_13.html new file mode 100644 index 000000000..e2311e8a9 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/src_13.html @@ -0,0 +1,235 @@ +
      1 /**
    +  2  * Validates and invalidates designmode contents
    +  3  */
    +  4 xq.Validator = Class.create({
    +  5 	initialize: function(curUrl, urlValidationMode, allowedTags, allowedAttrs) {
    +  6 		this.allowedTags = (allowedTags || ['a', 'abbr', 'acronym', 'address', 'blockquote', 'br', 'caption', 'cite', 'code', 'dd', 'dfn', 'div', 'dl', 'dt', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'img', 'kbd', 'li', 'ol', 'p', 'pre', 'q', 'samp', 'span', 'sup', 'sub', 'strong', 'table', 'thead', 'tbody', 'td', 'th', 'tr', 'ul', 'var']).join(' ') + ' ';
    +  7 		this.allowedAttrs = (allowedAttrs || ['alt', 'cite', 'class', 'datetime', 'height', 'href', 'id', 'rel', 'rev', 'src', 'style', 'title', 'width']).join(' ') + ' ';
    +  8 		
    +  9 		this.curUrl = curUrl;
    + 10 		this.curUrlParts = curUrl ? curUrl.parseURL() : null;
    + 11 		this.urlValidationMode = urlValidationMode;
    + 12 	},
    + 13 	
    + 14 	/**
    + 15 	 * Perform validation on given element
    + 16 	 *
    + 17 	 * @param {Element} element Target element. It is not affected by validation.
    + 18 	 * @param {boolean} fullValidation Perform full validation. If you just want to use the result to assign innerHTML, set it false
    + 19 	 *
    + 20 	 * @returns {String} Validated HTML string
    + 21 	 */
    + 22 	validate: function(element, fullValidation) {throw "Not implemented"},
    + 23 	
    + 24 	/**
    + 25 	 * Perform invalidation on given element to make the designmode works well.
    + 26 	 *
    + 27 	 * @param {Element} element Target element.
    + 28 	 * @returns {String} Invalidated HTML string
    + 29 	 */
    + 30 	invalidate: function(element) {throw "Not implemented"},
    + 31 	
    + 32 	validateStrike: function(content) {
    + 33 		content = content.replace(/<strike(>|\s+[^>]*>)/ig, "<span class=\"strike\"$1");
    + 34 		content = content.replace(/<\/strike>/ig, "</span>");
    + 35 		return content;
    + 36 	},
    + 37 	
    + 38 	validateUnderline: function(content) {
    + 39 		content = content.replace(/<u(>|\s+[^>]*>)/ig, "<em class=\"underline\"$1");
    + 40 		content = content.replace(/<\/u>/ig, "</em>");
    + 41 		return content;
    + 42 	},
    + 43 	
    + 44 	replaceTag: function(content, from, to) {
    + 45 		return content.replace(new RegExp("(</?)" + from + "(>|\\s+[^>]*>)", "ig"), "$1" + to + "$2");
    + 46 	},
    + 47 	
    + 48 	validateSelfClosingTags: function(content) {
    + 49 		return content.replace(/<(br|hr|img)([^>]*?)>/img, function(str, tag, attrs) {
    + 50 			return "<" + tag + attrs + " />"
    + 51 		});
    + 52 	},
    + 53 	
    + 54 	removeComments: function(content) {
    + 55 		return content.replace(/<!--.*?-->/img, '');
    + 56 	},
    + 57 	
    + 58 	removeDangerousElements: function(element) {
    + 59 		var scripts = $A(element.getElementsByTagName('SCRIPT')).reverse();
    + 60 		for(var i = 0; i < scripts.length; i++) {
    + 61 			scripts[i].parentNode.removeChild(scripts[i]);
    + 62 		}
    + 63 	},
    + 64 
    + 65 	// TODO: very slow
    + 66 	applyWhitelist: function(content) {
    + 67 		var allowedTags = this.allowedTags;
    + 68 		var allowedAttrs = this.allowedAttrs;
    + 69 		
    + 70 		return content.replace(new RegExp("(</?)([^>]+?)(>|\\s+([^>]*?)(\\s?/?)>)", "g"), function(str, head, tag, tail, attrs, selfClosing) {
    + 71 			if(allowedTags.indexOf(tag) == -1) return '';
    + 72 			
    + 73 			if(attrs) {
    + 74 				attrs = attrs.replace(/(^|\s")([^"=]+)(\s|$)/g, '$1$2="$2"$3'); // for IE
    + 75 				
    + 76 				var sb = [];
    + 77 				var m = attrs.match(/([^=]+)="[^"]*?"/g);
    + 78 				for(var i = 0; i < m.length; i++) {
    + 79 					m[i] = m[i].strip();
    + 80 					var name = m[i].split('=')[0];
    + 81 					if(allowedAttrs.indexOf(name) != -1) sb.push(m[i]);
    + 82 				}
    + 83 				attrs = sb.join(' ');
    + 84 				if(attrs != '') attrs = ' ' + attrs;
    + 85 				return head + tag + attrs + selfClosing + '>';
    + 86 			} else {
    + 87 				return str;
    + 88 			}
    + 89 		});
    + 90 	},
    + 91 	
    + 92 	makeUrlsRelative: function(content) {
    + 93 		var curUrl = this.curUrl;
    + 94 		var urlParts = this.curUrlParts;
    + 95 		
    + 96 		// 1. find attributes and...
    + 97 		return content.replace(/(<\w+\s+)(\/|([^>]+?)(\/?))>/g, function(str, head, ignored, attrs, tail) {
    + 98 			if(attrs) {
    + 99 				// 2. validate URL part
    +100 				attrs = attrs.replace(/(href|src)="([^"]+)"/g, function(str, name, url) {
    +101 					// 3. first, make it absolute
    +102 					var abs = null;
    +103 					if(url.charAt(0) == '#') {
    +104 						abs = urlParts.includeQuery + url;
    +105 					} else if(url.charAt(0) == '?') {
    +106 						abs = urlParts.includePath + url;
    +107 					} else if(url.charAt(0) == '/') {
    +108 						abs = urlParts.includeHost + url;
    +109 					} else if(url.match(/^\w+:\/\//)) {
    +110 						abs = url;
    +111 					} else {
    +112 						abs = urlParts.includeBase + url;
    +113 					}
    +114 					
    +115 					// 4. make it relative by removing same part
    +116 					var rel = abs;
    +117 					
    +118 					if(abs.indexOf(urlParts.includeQuery) == 0) {
    +119 						rel = abs.substring(urlParts.includeQuery.length);
    +120 					} else if(abs.indexOf(urlParts.includePath) == 0) {
    +121 						rel = abs.substring(urlParts.includePath.length);
    +122 					} else if(abs.indexOf(urlParts.includeBase) == 0) {
    +123 						rel = abs.substring(urlParts.includeBase.length);
    +124 					} else if(abs.indexOf(urlParts.includeHost) == 0) {
    +125 						rel = abs.substring(urlParts.includeHost.length);
    +126 					}
    +127 					if(rel == '') rel = '#';
    +128 					
    +129 					return name + '="' + rel + '"';
    +130 				});
    +131 				
    +132 				return head + attrs + tail + '>';
    +133 			} else {
    +134 				return str;
    +135 			}
    +136 		});
    +137 		
    +138 		return content;
    +139 	},
    +140 	
    +141 	makeUrlsHostRelative: function(content) {
    +142 		var curUrl = this.curUrl;
    +143 		var urlParts = this.curUrlParts;
    +144 		
    +145 		// 1. find attributes and...
    +146 		return content.replace(/(<\w+\s+)(\/|([^>]+?)(\/?))>/g, function(str, head, ignored, attrs, tail) {
    +147 			if(attrs) {
    +148 				// 2. validate URL part
    +149 				attrs = attrs.replace(/(href|src)="([^"]+)"/g, function(str, name, url) {
    +150 					// 3. first, make it absolute
    +151 					var abs = null;
    +152 					if(url.charAt(0) == '#') {
    +153 						abs = urlParts.includeQuery + url;
    +154 					} else if(url.charAt(0) == '?') {
    +155 						abs = urlParts.includePath + url;
    +156 					} else if(url.charAt(0) == '/') {
    +157 						abs = urlParts.includeHost + url;
    +158 					} else if(url.match(/^\w+:\/\//)) {
    +159 						abs = url;
    +160 					} else {
    +161 						abs = urlParts.includeBase + url;
    +162 					}
    +163 					
    +164 					// 4. make it relative by removing same part
    +165 					var rel = abs;
    +166 					if(abs.indexOf(urlParts.includeHost) == 0) {
    +167 						rel = abs.substring(urlParts.includeHost.length);
    +168 					}
    +169 					if(rel == '') rel = '#';
    +170 					
    +171 					return name + '="' + rel + '"';
    +172 				});
    +173 				
    +174 				return head + attrs + tail + '>';
    +175 			} else {
    +176 				return str;
    +177 			}
    +178 		});
    +179 		
    +180 		return content;
    +181 	},
    +182 	
    +183 	makeUrlsAbsolute: function(content) {
    +184 		var curUrl = this.curUrl;
    +185 		var urlParts = this.curUrlParts;
    +186 		
    +187 		// 1. find attributes and...
    +188 		return content.replace(/(<\w+\s+)(\/|([^>]+?)(\/?))>/g, function(str, head, ignored, attrs, tail) {
    +189 			if(attrs) {
    +190 				// 2. validate URL part
    +191 				attrs = attrs.replace(/(href|src)="([^"]+)"/g, function(str, name, url) {
    +192 					var abs = null;
    +193 					if(url.charAt(0) == '#') {
    +194 						abs = urlParts.includeQuery + url;
    +195 					} else if(url.charAt(0) == '?') {
    +196 						abs = urlParts.includePath + url;
    +197 					} else if(url.charAt(0) == '/') {
    +198 						abs = urlParts.includeHost + url;
    +199 					} else if(url.match(/^\w+:\/\//)) {
    +200 						abs = url;
    +201 					} else {
    +202 						abs = urlParts.includeBase + url;
    +203 					}
    +204 
    +205 					return name + '="' + abs + '"';
    +206 				});
    +207 				
    +208 				return head + attrs + tail + '>';
    +209 			} else {
    +210 				return str;
    +211 			}
    +212 		});
    +213 	}
    +214 });
    +215 
    +216 /**
    +217  * Creates and returns instance of browser specific implementation.
    +218  */
    +219 xq.Validator.createInstance = function(curUrl, urlValidationMode, allowedTags, allowedAttrs) {
    +220 	if(xq.Browser.isTrident) {
    +221 		return new xq.ValidatorTrident(curUrl, urlValidationMode, allowedTags, allowedAttrs);
    +222 	} else if(xq.Browser.isWebkit) {
    +223 		return new xq.ValidatorWebkit(curUrl, urlValidationMode, allowedTags, allowedAttrs);
    +224 	} else {
    +225 		return new xq.ValidatorGecko(curUrl, urlValidationMode, allowedTags, allowedAttrs);
    +226 	}
    +227 }
    +228 
    \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_14.html b/modules/editor/skins/xquared/doc/api/src_14.html new file mode 100644 index 000000000..9de6a044d --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/src_14.html @@ -0,0 +1,12 @@ +
      1 /**
    +  2  * Validator for Gecko Engine
    +  3  */
    +  4 xq.ValidatorGecko = Class.create(xq.ValidatorW3, {
    +  5 });
    \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_15.html b/modules/editor/skins/xquared/doc/api/src_15.html new file mode 100644 index 000000000..a67012aa6 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/src_15.html @@ -0,0 +1,147 @@ +
      1 /**
    +  2  * Validator for Internet Explorer 6 and 7
    +  3  */
    +  4 xq.ValidatorTrident = Class.create(xq.Validator, {
    +  5 	validate: function(element, fullValidation) {
    +  6 		element = element.cloneNode(true);
    +  7 		
    +  8 		this.removeDangerousElements(element);
    +  9 		this.validateFontColor(element);
    + 10 		this.validateBackgroundColor(element);
    + 11 		
    + 12 		var content = element.innerHTML;
    + 13 		
    + 14 		try {
    + 15 			content = this.validateStrike(content);
    + 16 			content = this.validateUnderline(content);
    + 17 			
    + 18 			if(fullValidation) content = this.performFullValidation(content);
    + 19 		} catch(ignored) {}
    + 20 		
    + 21 		return content;
    + 22 	},
    + 23 	
    + 24 	invalidate: function(element) {
    + 25 		var rdom = xq.RichDom.createInstance();
    + 26 		rdom.setRoot(element);
    + 27 		
    + 28 		this.invalidateFontColor(element);
    + 29 		this.invalidateBackgroundColor(element);
    + 30 		
    + 31 		// <span class="strike"> -> <strike>
    + 32 		var strikes = rdom.findByAttribute("className", "strike");
    + 33 		for(var i = 0; i < strikes.length; i++) {
    + 34 			if("SPAN" == strikes[i].nodeName) rdom.replaceTag("strike", strikes[i]).removeAttribute("className");
    + 35 		}
    + 36 		
    + 37 		// <em|i class="underline"> -> <u>
    + 38 		var underlines = rdom.findByAttribute("className", "underline");
    + 39 		for(var i = 0; i < underlines.length; i++) {
    + 40 			if(["EM", "I"].include(underlines[i].nodeName)) rdom.replaceTag("u", underlines[i]).removeAttribute("className");
    + 41 		}
    + 42 
    + 43 		var content = rdom.getRoot().innerHTML;
    + 44 
    + 45 		content = this.removeComments(content);
    + 46 		
    + 47 		return content;
    + 48 	},
    + 49 	
    + 50 	performFullValidation: function(content) {
    + 51 		content = this.lowerTagNamesAndUniformizeQuotation(content);
    + 52 		content = this.validateSelfClosingTags(content);
    + 53 		content = this.applyWhitelist(content);
    + 54 		
    + 55 		if(this.urlValidationMode == 'relative') {
    + 56 			content = this.makeUrlsRelative(content);
    + 57 		} else if(this.urlValidationMode == 'host_relative') {
    + 58 			content = this.makeUrlsHostRelative(content);
    + 59 		} else if(this.urlValidationMode == 'absolute') {
    + 60 			// Trident always use absolute URL so we don't need to do anything.
    + 61 			//
    + 62 			// content = this.makeUrlsAbsolute(content);
    + 63 		}
    + 64 		
    + 65 		return content;
    + 66 	},
    + 67 	
    + 68 	validateFontColor: function(element) {
    + 69 		var rdom = xq.RichDom.createInstance();
    + 70 		rdom.setRoot(element);
    + 71 		
    + 72 		// It should be reversed to deal with nested elements
    + 73 		var fonts = $A(element.getElementsByTagName('FONT')).reverse();
    + 74 		for(var i = 0; i < fonts.length; i++) {
    + 75 			var font = fonts[i];
    + 76 			var color = font.getAttribute('color');
    + 77 			
    + 78 			if(color) {
    + 79 				var span = rdom.replaceTag("span", font);
    + 80 				span.removeAttribute('color');
    + 81 				span.style.color = color;
    + 82 			}
    + 83 		}
    + 84 	},
    + 85 
    + 86 	invalidateFontColor: function(element) {
    + 87 		var rdom = xq.RichDom.createInstance();
    + 88 		rdom.setRoot(element);
    + 89 
    + 90 		var spans = $A(element.getElementsByTagName('SPAN')).reverse();
    + 91 		for(var i = 0; i < spans.length; i++) {
    + 92 			var span = spans[i];
    + 93 			var color = span.style.color;
    + 94 			
    + 95 			if(color) {
    + 96 				var font = rdom.replaceTag("font", span);
    + 97 				font.style.color = "";
    + 98 				font.setAttribute('color', color);
    + 99 			}
    +100 		}
    +101 	},
    +102 
    +103 	validateBackgroundColor: function(element) {
    +104 		var rdom = xq.RichDom.createInstance();
    +105 		rdom.setRoot(element);
    +106 
    +107 		// It should be reversed to deal with nested elements
    +108 		var fonts = $A(element.getElementsByTagName('FONT')).reverse();
    +109 		for(var i = 0; i < fonts.length; i++) {
    +110 			if(fonts[i].style.color || fonts[i].style.backgroundColor) rdom.replaceTag("span", fonts[i]);
    +111 		}
    +112 	},
    +113 
    +114 	invalidateBackgroundColor: function(element) {
    +115 		var rdom = xq.RichDom.createInstance();
    +116 		rdom.setRoot(element);
    +117 
    +118 		// It should be reversed to deal with nested elements
    +119 		var spans = $A(element.getElementsByTagName('SPAN')).reverse();
    +120 		for(var i = 0; i < spans.length; i++) {
    +121 			if(spans[i].style.color || spans[i].style.backgroundColor) rdom.replaceTag("font", spans[i]);
    +122 		}
    +123 	},
    +124 	
    +125 	lowerTagNamesAndUniformizeQuotation: function(content) {
    +126 		// Uniformize quotation, turn tag names and attribute names into lower case
    +127 		content = content.replace(/<(\/?)(\w+)([^>]*?)>/img, function(str, closingMark, tagName, attrs) {
    +128 			return "<" + closingMark + tagName.toLowerCase() + this.correctHtmlAttrQuotation(attrs) + ">";
    +129 		}.bind(this));
    +130 		
    +131 		return content;
    +132 	},
    +133 	
    +134 	correctHtmlAttrQuotation: function(html) {
    +135 		html = html.replace(/\s(\w+?)=\s+"([^"]+)"/mg,function (str, name, value) {return " " + name.toLowerCase() + '=' + '"' + value + '"'});
    +136 		html = html.replace(/\s(\w+?)=([^ "]+)/mg,function (str, name, value) {return " " + name.toLowerCase() + '=' + '"' + value + '"'});
    +137 		return html;
    +138 	}
    +139 });
    +140 
    \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_16.html b/modules/editor/skins/xquared/doc/api/src_16.html new file mode 100644 index 000000000..eacdef1b9 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/src_16.html @@ -0,0 +1,112 @@ +
      1 /**
    +  2  * Validator for W3C Standard Engine
    +  3  */
    +  4 xq.ValidatorW3 = Class.create(xq.Validator, {
    +  5 	validate: function(element, fullValidation) {
    +  6 		element = element.cloneNode(true);
    +  7 
    +  8 		var rdom = xq.RichDom.createInstance();
    +  9 		rdom.setRoot(element);
    + 10 		rdom.removePlaceHoldersAndEmptyNodes(element);
    + 11 		this.removeDangerousElements(element);
    + 12 		this.validateFontColor(element);
    + 13 
    + 14 		var content = element.innerHTML;
    + 15 		
    + 16 		try {
    + 17 			content = this.replaceTag(content, "b", "strong");
    + 18 			content = this.replaceTag(content, "i", "em");
    + 19 			
    + 20 			content = this.validateStrike(content);
    + 21 			content = this.validateUnderline(content);
    + 22 			content = this.addNbspToEmptyBlocks(content);
    + 23 			
    + 24 			if(fullValidation) content = this.performFullValidation(content);
    + 25 		} catch(ignored) {}
    + 26 
    + 27 		// insert newline between block-tags
    + 28 		var blocks = rdom.tree.getBlockTags().join("|");
    + 29 		var regex = new RegExp("</(" + blocks + ")>([^\n])", "img");
    + 30 		content = content.replace(regex, '</$1>\n$2');
    + 31 		
    + 32 		return content;
    + 33 	},
    + 34 	invalidate: function(element) {
    + 35 		var rdom = xq.RichDom.createInstance();
    + 36 		rdom.setRoot(element);
    + 37 		
    + 38 		// <span class="strike"> -> <strike>
    + 39 		var strikes = rdom.findByAttribute("class", "strike");
    + 40 		for(var i = 0; i < strikes.length; i++) {
    + 41 			if("SPAN" == strikes[i].nodeName) rdom.replaceTag("strike", strikes[i]).removeAttribute("class");
    + 42 		}
    + 43 		
    + 44 		// <em|i class="underline"> -> <u>
    + 45 		var underlines = rdom.findByAttribute("class", "underline");
    + 46 		for(var i = 0; i < underlines.length; i++) {
    + 47 			if(["EM", "I"].include(underlines[i].nodeName)) rdom.replaceTag("u", underlines[i]).removeAttribute("class");
    + 48 		}
    + 49 		
    + 50 		var content = rdom.getRoot().innerHTML;
    + 51 		
    + 52 		content = this.replaceTag(content, "strong", "b");
    + 53 		content = this.replaceTag(content, "em", "i");
    + 54 		content = this.removeComments(content);
    + 55 		content = this.replaceNbspToBr(content);
    + 56 		
    + 57 		return content;
    + 58 	},
    + 59 	
    + 60 	performFullValidation: function(content) {
    + 61 		content = this.validateSelfClosingTags(content);
    + 62 		content = this.applyWhitelist(content);
    + 63 		
    + 64 		if(this.urlValidationMode == 'relative') {
    + 65 			content = this.makeUrlsRelative(content);
    + 66 		} else if(this.urlValidationMode == 'host_relative') {
    + 67 			content = this.makeUrlsHostRelative(content);
    + 68 		} else if(this.urlValidationMode == 'absolute') {
    + 69 			content = this.makeUrlsAbsolute(content);
    + 70 		}
    + 71 
    + 72 		return content;
    + 73 	},
    + 74 	
    + 75 	validateFontColor: function(element) {
    + 76 		var rdom = xq.RichDom.createInstance();
    + 77 		rdom.setRoot(element);
    + 78 
    + 79 		var fonts = $A(element.getElementsByTagName('FONT')).reverse();
    + 80 		for(var i = 0; i < fonts.length; i++) {
    + 81 			var font = fonts[i];
    + 82 			var color = font.getAttribute('color');
    + 83 			
    + 84 			if(color) {
    + 85 				var span = rdom.replaceTag("span", font);
    + 86 				span.removeAttribute('color');
    + 87 				span.style.color = color;
    + 88 			}
    + 89 		}
    + 90 	},
    + 91 	
    + 92 	addNbspToEmptyBlocks: function(content) {
    + 93 		var blocks = new xq.DomTree().getBlockTags().join("|");
    + 94 		var regex = new RegExp("<(" + blocks + ")>\\s*?</(" + blocks + ")>", "img");
    + 95 		return content.replace(regex, '<$1> </$2>');
    + 96 	},
    + 97 	
    + 98 	replaceNbspToBr: function(content) {
    + 99 		var blocks = new xq.DomTree().getBlockTags().join("|");
    +100 		var regex = new RegExp("<(" + blocks + ")>( )?</(" + blocks + ")>", "img");
    +101 		var rdom = xq.RichDom.createInstance();
    +102 		return content.replace(regex, '<$1>' + rdom.makePlaceHolderString() + '</$3>');
    +103 	}
    +104 });
    +105 
    \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_17.html b/modules/editor/skins/xquared/doc/api/src_17.html new file mode 100644 index 000000000..b07ebbc67 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/src_17.html @@ -0,0 +1,21 @@ +
      1 /**
    +  2  * Validator for Webkit
    +  3  */
    +  4 xq.ValidatorWebkit = Class.create(xq.ValidatorW3, {
    +  5 });
    +  6 
    +  7 /*
    +  8 if(node.nodeName == "SPAN" && node.className == "Apple-style-span" && node.style.fontStyle == "italic") em = true;
    +  9 if(node.nodeName == "SPAN" && node.className == "Apple-style-span" && node.style.fontWeight == "bold") strong = true;
    + 10 if(node.nodeName == "SPAN" && node.className == "Apple-style-span" && node.style.textDecoration == "line-through") strike = true;
    + 11 if(node.nodeName == "SPAN" && node.className == "Apple-style-span" && node.style.textDecoration == "underline") underline = true;
    + 12 if(node.nodeName == "SPAN" && node.className == "Apple-style-span" && node.style.cssText.indexOf("vertical-align: super;") != -1) superscription = true;
    + 13 if(node.nodeName == "SPAN" && node.className == "Apple-style-span" && node.style.cssText.indexOf("vertical-align: sub;") != -1) subscription = true;
    + 14 */
    \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_18.html b/modules/editor/skins/xquared/doc/api/src_18.html new file mode 100644 index 000000000..5fa6b1885 --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/src_18.html @@ -0,0 +1,157 @@ +
      1 /**
    +  2  * Namespace for entire Xquared classes
    +  3  */
    +  4 var xq = {
    +  5 	majorVersion: '0.1',
    +  6 	minorVersion: '2007119'
    +  7 };
    +  8 
    +  9 /**
    + 10  * Make given object as event source
    + 11  *
    + 12  * @param {Object} object target object
    + 13  * @param {String} prefix prefix for generated functions
    + 14  * @param {Array} events array of string which contains name of events
    + 15  */
    + 16 xq.asEventSource = function(object, prefix, events) {
    + 17 	object._listeners = []
    + 18 	object._registerEventFirer = function(prefix, name) {
    + 19 		this["_fireOn" + name] = function() {
    + 20 			for(var i = 0; i < this._listeners.length; i++) {
    + 21 				var listener = this._listeners[i];
    + 22 				var func = listener["on" + prefix + name];
    + 23 				if(func) func.apply(listener, $A(arguments));
    + 24 			}
    + 25 		}
    + 26 	}
    + 27 	object.addListener = function(l) {
    + 28 		this._listeners.push(l);
    + 29 	}
    + 30 	
    + 31 	for(var i = 0; i < events.length; i++) {
    + 32 		object._registerEventFirer(prefix, events[i]);
    + 33 	}
    + 34 }
    + 35 
    + 36 /**
    + 37  * Returns the index of given element
    + 38  *
    + 39  * @returns {Number} index or -1
    + 40  */
    + 41 Array.prototype.indexOf = function(n) {
    + 42 	for(var i = 0; i < this.length; i++) {
    + 43 		if(this[i] == n) return i;
    + 44 	}
    + 45 	
    + 46 	return -1;
    + 47 }
    + 48 
    + 49 Date.preset = null;
    + 50 Date.pass = function(msec) {
    + 51 	if(Date.preset == null) return;
    + 52 	Date.preset = new Date(Date.preset.getTime() + msec);
    + 53 }
    + 54 Date.get = function() {
    + 55 	return Date.preset == null ? new Date() : Date.preset;
    + 56 }
    + 57 Date.prototype.elapsed = function(msec) {
    + 58 	return Date.get().getTime() - this.getTime() >= msec;
    + 59 }
    + 60 
    + 61 String.prototype.merge = function(data) {
    + 62 	var newString = this;
    + 63 	for(k in data) {
    + 64 		newString = newString.replace("{" + k + "}", data[k]);
    + 65 	}
    + 66 	return newString;
    + 67 }
    + 68 
    + 69 String.prototype.parseURL = function() {
    + 70 	var m = this.match(/((((\w+):\/\/(((([^@:]+)(:([^@]+))?)@)?([^:\/\?#]+)?(:(\d+))?))?([^\?#]+)?)(\?([^#]+))?)(#(.+))?/);
    + 71 	
    + 72 	var includeAnchor = m[0];
    + 73 	var includeQuery = m[1] || undefined;
    + 74 	var includePath = m[2] || undefined;
    + 75 	var includeHost = m[3] || undefined;
    + 76 	var includeBase = null;
    + 77 	var protocol = m[4] || undefined;
    + 78 	var user = m[8] || undefined;
    + 79 	var password = m[10] || undefined;
    + 80 	var domain = m[11] || undefined;
    + 81 	var port = m[13] || undefined;
    + 82 	var path = m[14] || undefined;
    + 83 	var query = m[16] || undefined;
    + 84 	var anchor = m[18] || undefined;
    + 85 	
    + 86 	if(!path || path == '/') {
    + 87 		includeBase = includeHost + '/';
    + 88 	} else {
    + 89 		var index = path.lastIndexOf('/');
    + 90 		includeBase = includeHost + path.substring(0, index + 1);
    + 91 	}
    + 92 	
    + 93 	return {
    + 94 		includeAnchor: includeAnchor,
    + 95 		includeQuery: includeQuery,
    + 96 		includePath: includePath,
    + 97 		includeBase: includeBase,
    + 98 		includeHost: includeHost,
    + 99 		protocol: protocol,
    +100 		user: user,
    +101 		password: password,
    +102 		domain: domain,
    +103 		port: port,
    +104 		path: path,
    +105 		query: query,
    +106 		anchor: anchor
    +107 	};
    +108 }
    +109 
    +110 xq.findXquaredScript = function() {
    +111     return $A(document.getElementsByTagName("script")).find(function(script) {
    +112     	return script.src && script.src.match(/xquared\.js/i);
    +113     });
    +114 }
    +115 xq.shouldLoadOthers = function() {
    +116 	var script = xq.findXquaredScript();
    +117     return script && !!script.src.match(/xquared\.js\?load_others=1/i);
    +118 }
    +119 xq.loadScript = function(url) {
    +120     document.write('<script type="text/javascript" src="' + url + '"></script>');
    +121 }
    +122 xq.loadOthers = function() {
    +123 	var script = xq.findXquaredScript();
    +124 	var basePath = script.src.match(/(.*\/)xquared\.js.*/i)[1];
    +125 	var others = [
    +126 		'Editor.js',
    +127 		'Browser.js',
    +128 		'Shortcut.js',
    +129 		'DomTree.js',
    +130 		'RichDom.js',
    +131 		'RichDomW3.js',
    +132 		'RichDomGecko.js',
    +133 		'RichDomWebkit.js',
    +134 		'RichDomTrident.js',
    +135 		'RichTable.js',
    +136 		'Validator.js',
    +137 		'ValidatorW3.js',
    +138 		'ValidatorGecko.js',
    +139 		'ValidatorWebkit.js',
    +140 		'ValidatorTrident.js',
    +141 		'EditHistory.js',
    +142 		'Controls.js',
    +143 		'_ui_templates.js'
    +144 	];
    +145 	others.each(function(name) {
    +146 		xq.loadScript(basePath + name);
    +147 	});
    +148 }
    +149 
    +150 if(xq.shouldLoadOthers()) xq.loadOthers();
    \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_19.html b/modules/editor/skins/xquared/doc/api/src_19.html new file mode 100644 index 000000000..feb2f6a4e --- /dev/null +++ b/modules/editor/skins/xquared/doc/api/src_19.html @@ -0,0 +1,16 @@ +
      1 if(!xq) xq = {};
    +  2 if(!xq.ui_templates) xq.ui_templates = {};
    +  3 
    +  4 xq.ui_templates.basicColorPickerDialog='<form action="#" class="xqFormDialog xqBasicColorPickerDialog">\n		<div>\n			<label>\n				<input type="radio" class="initialFocus" name="color" value="black" checked="checked" />\n				<span style="color: black;">Black</span>\n			</label>\n			<label>\n				<input type="radio" name="color" value="red" />\n				<span style="color: red;">Red</span>\n			</label>\n				<input type="radio" name="color" value="yellow" />\n				<span style="color: yellow;">Yellow</span>\n			</label>\n			</label>\n				<input type="radio" name="color" value="pink" />\n				<span style="color: pink;">Pink</span>\n			</label>\n			<label>\n				<input type="radio" name="color" value="blue" />\n				<span style="color: blue;">Blue</span>\n			</label>\n			<label>\n				<input type="radio" name="color" value="green" />\n				<span style="color: green;">Green</span>\n			</label>\n			\n			<input type="submit" value="Ok" />\n			<input type="button" class="cancel" value="Cancel" />\n		</div>\n	</form>';
    +  5 if(!xq) xq = {};
    +  6 if(!xq.ui_templates) xq.ui_templates = {};
    +  7 
    +  8 xq.ui_templates.basicLinkDialog='<form action="#" class="xqFormDialog xqBasicLinkDialog">\n		<h3>Link</h3>\n		<div>\n			<input type="text" class="initialFocus" name="text" value="" />\n			<input type="text" name="url" value="http://" />\n			\n			<input type="submit" value="Ok" />\n			<input type="button" class="cancel" value="Cancel" />\n		</div>\n	</form>';
    +  9 
    \ No newline at end of file diff --git a/modules/editor/skins/xquared/editor.html b/modules/editor/skins/xquared/editor.html new file mode 100644 index 000000000..f0f705a09 --- /dev/null +++ b/modules/editor/skins/xquared/editor.html @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + +
    + + + + + + + + + + + + +
    + + diff --git a/modules/editor/skins/xquared/examples/css/xq_contents.css b/modules/editor/skins/xquared/examples/css/xq_contents.css new file mode 100644 index 000000000..551b8f3f3 --- /dev/null +++ b/modules/editor/skins/xquared/examples/css/xq_contents.css @@ -0,0 +1,122 @@ +/* Basic */ +.xed { + color: #494949; + padding: 0.3em; + font-size: 0.833em; + font-family: Arial, dotum, sans-serif; +} +.xed * { + margin: 0; + padding: 0; +} + + + +/* Headings and paragraph */ +.xed h1, +.xed h2, +.xed h3, +.xed h4, +.xed h5, +.xed h6 { + border-bottom: 2px solid #425e89; + line-height: 1em; + padding-bottom: 0.2em; + margin: 0.2em 0; +} + +.xed h1 {font-size: 2.845em;} +.xed h2 {font-size: 2.460em;} +.xed h3 {font-size: 2.153em;} +.xed h4 {font-size: 1.922em;} +.xed h5 {font-size: 1.461em;} +.xed h6 {font-size: 1.230em;} + +.xed p { + margin: 0.614em 0; + line-height: 1.230em; +} + +.xed hr { +} + + + +/* List */ +.xed ul, +.xed ol { + padding-left: 2em; + margin: 0.614em 0; +} +.xed li { + line-height: 1.306em; +} + + + +/* Other block containers */ +.xed ol.code, +.xed div, +.xed blockquote { + margin: 1em 0; + padding-left: 2.460em; + padding-right: 1em; + border-width: 0 3px; + border-style: solid; + line-height: 1.306em; +} +.xed ol.code { + font-family: monospace; + list-style-type: none; + border-color: #ffb781; + background: url(../img/content/code.gif) no-repeat 0 0; +} +.xed div { + border-color: #8ccfff; + background: url(../img/content/div.gif) no-repeat 0 0; +} +.xed blockquote { + border-color: #c9c9c9; + background: url(../img/content/blockquote.gif) no-repeat 0 0; +} + + + +/* Inline elements */ +.xed em.underline { + font-style: normal; + text-decoration: underline; +} +.xed span.strike { + text-decoration: line-through; +} + + + +/* table */ +.xed table.datatable { + width: 100%; + /width: auto; + border-collapse: collapse; + table-layout: fixed; +} +.xed table.datatable th { + font-weight: normal; + padding: 0.25em 0.307em; +} +.xed table.datatable td { + padding: 0.25em 0.307em; +} +.xed table.datatable { + border-left: 1px solid #000; + border-top: 1px solid #000; +} +.xed table.datatable th { + background-color: #e7e7e7; + border-bottom: 1px solid #000; + border-right: 1px solid #000; +} +.xed table.datatable td { + border-bottom: 1px solid #000; + border-right: 1px solid #000; +} \ No newline at end of file diff --git a/modules/editor/skins/xquared/examples/css/xq_ui.css b/modules/editor/skins/xquared/examples/css/xq_ui.css new file mode 100644 index 000000000..3fe714644 --- /dev/null +++ b/modules/editor/skins/xquared/examples/css/xq_ui.css @@ -0,0 +1,233 @@ +/** + * Default Toolbar + */ + .xquared { + border: 1px solid #c2c2c2; + } +.xquared div.toolbar { + position: relative; + background-color: #ebebeb; + background-position: 0 0; + background-repeat: repeat-x; + background-image: url(../img/toolbar/toolbarBg.gif); +} + +.xquared ul.buttons { + margin: 0; + padding: 5px 4px 2px; + list-style: none; + border-top: 1px solid #fff; + border-bottom: 1px solid #fff; + overflow: hidden; + height: 100%; +} +.xquared ul.buttons li { + float: left; + padding-bottom: 3px; + background-position: 0 0; + background-repeat: repeat-x; + background-image: url(../img/toolbar/toolbarButtonBg.gif); +} +.xquared ul.buttons li.xq_separator { + padding-left: 8px; + margin-left: 8px; + background-position: 0 0; + background-repeat: repeat-x; + background-image: url(../img/toolbar/toolbarSeparator.gif); +} +.xquared ul.buttons li a { + display: block; + padding: 2px; + font-size: 0; + border: 1px solid #d2d2d2; + margin-right: -1px; + position: relative; + height: 100%; + _height: auto; + z-index: 0; +} +.xquared ul.buttons li a img { + margin: 0; + padding: 0; + border: none; + font-size: 1.25em; +} + +/* selected */ +.xquared ul.buttons li a.selected { + background-color: #ffea5f; + border: 1px solid #a0a0a0; + position: relative; + z-index: 1; +} + +/* mouseover */ +.xquared ul.buttons li a:hover { + border: 1px solid #000; + background-color: transparent; + position: relative; + z-index: 2; +} + +/* disabled */ +.xquared .disabled ul.buttons li a, +.xquared ul.buttons li .disabled a { + background-color: #fff; + opacity: 0.3; + filter:alpha(opacity=30); + _width: 1px; + _height: 1px; + cursor: default; +} +.xquared .disabled ul.buttons li a, +.xquared ul.buttons li .disabled a:hover { + border: 1px solid #dbdbdb; + position: relative; + z-index: 0; +} +.xquared .disabled ul.buttons li a, +.xquared ul.buttons li .disabled a.selected { + border: 1px solid #dbdbdb; +} + +.xquared .editor { + border: 0 none; + border-top:1px solid #c2c2c2; + height:300px; +} +.xquared .editor textarea, +.xquared .editor iframe { + margin: 0; + padding: 0; + border: 0 none; + height: 100%; + width: 100%; +} + +.xquared .editor textarea { + _height: expression(this.parentNode.clientHeight - 2); /* TODO remove IE6 hack */ +} +*+html .xquared .editor textarea { + height: expression(this.parentNode.clientHeight - 1); /* TODO remove IE7 hack */ +} + +.xquared .source_editor { + padding-left: 0.3em; +} + + +/** + * Context Menu + */ +.xqContextMenu { + position:absolute; + z-index: 902; + font-size: medium; + font-family: arial, "돋움"; + width:auto; + margin:0; + padding:3px; + border:1px solid #aaa; + list-style:none; + background-color: #fff; +} +.xqContextMenu li { + padding:2px 3px 2px 20px; + background-position:left; + background-repeat:no-repeat; + color:#aaa; + display:block; + width:200px; +} +.xqContextMenu a { + color:#000; + text-decoration:none; +} +.xqContextMenu .separator { + margin-top:5px; + padding-bottom:0px; + line-height:0em; + height: 1px; + /height: auto; + border-top: 1px solid #aaa; +} + + + +/** + * Controls - BasicLinkDialog + */ +.xqFormDialog { + position:absolute; + z-index: 902; + border:1px solid #aaa; + background-color: #fff; + padding: 0.5em; + overflow:auto; /* to fix FF caret bug */ +} + +.xqFormDialog h3 { + font-size: 1.2em; + margin: 0; +} + +/** + * Controls - QuickSearchDialog + */ +.xqQuickSearch { + position:absolute; + z-index: 902; + font-size: medium; + font-family: arial, "돋움"; + width:15em; + margin:0; + padding:0; + border:1px solid #aaa; + list-style:none; + background-color: #fff; + overflow:auto; /* to fix FF caret bug */ +} + +.xqQuickSearch h1 { + font-size: medium; + font-weight: bold; + margin: 2px; + padding: 2px; +} + +.xqQuickSearch .input { + border: 1px solid #aaa; + padding: 2px; + margin: 2px; +} + +.xqQuickSearch form { + padding: 0; + margin: 0; +} + +.xqQuickSearch input { + border-width: 0; + margin: 0 2px; + width: 98%; +} + +.xqQuickSearch ol { + border: 1px solid #aaa; + padding: 2px; + margin: 2px; + height: 10em; + overflow: auto; +} + +.xqQuickSearch li { + list-style: none; + padding-bottom: 1px; + border-bottom: 1px solid #ddd; + cursor: pointer; + _cursor: hand; +} + +.xqQuickSearch li.selected { + background-color: #ffd; +} \ No newline at end of file diff --git a/modules/editor/skins/xquared/examples/default.html b/modules/editor/skins/xquared/examples/default.html new file mode 100644 index 000000000..b91d29415 --- /dev/null +++ b/modules/editor/skins/xquared/examples/default.html @@ -0,0 +1,77 @@ + + + + +Xquared example - Default + + + + + + + +
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +

    This holds true both for individuals as well as whole tagging communities.

    +
      +
    • Item 1
    • +
    • Item 2
    • +
    +

    This holds true both for individuals as well as whole tagging communities.

    +
      +
    • +

      Item 1

      +
        +
      1. Item 1
      2. +
      3. Item 2
      4. +
      +
    • +
    • Item 2
    • +
    • Item 3
    • +
    +

    This holds true both for individuals as well as whole tagging communities.

    +
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +
    +

    This holds true both for individuals as well as whole tagging communities.

    +
    +
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +
    +

    This holds true both for individuals as well as whole tagging communities.

    +
    +
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +

    Heading 1

    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +

    Heading 1

    +

    Heading 2

    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +

    Heading 1

    +

    Heading 2

    +

    Heading 3

    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +

    Heading 4

    +
    Heading 5
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +
    Heading 6
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +
      +
    1. print "Hello World"
    2. +
    3. print "Hello World"
    4. +
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +
    + + diff --git a/modules/editor/skins/xquared/examples/extensionpoint.html b/modules/editor/skins/xquared/examples/extensionpoint.html new file mode 100644 index 000000000..f9bfe5516 --- /dev/null +++ b/modules/editor/skins/xquared/examples/extensionpoint.html @@ -0,0 +1,308 @@ + + + + +Xquared example - Extension point + + + + + + + +
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +

    This holds true both for individuals as well as whole tagging communities.

    +
      +
    • Item 1
    • +
    • Item 2
    • +
    +

    This holds true both for individuals as well as whole tagging communities.

    +
      +
    • +

      Item 1

      +
        +
      1. Item 1
      2. +
      3. Item 2
      4. +
      +
    • +
    • Item 2
    • +
    • Item 3
    • +
    +

    This holds true both for individuals as well as whole tagging communities.

    +
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +
    +

    This holds true both for individuals as well as whole tagging communities.

    +
    +
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +
    +

    This holds true both for individuals as well as whole tagging communities.

    +
    +
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +

    Heading 1

    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +

    Heading 1

    +

    Heading 2

    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +

    Heading 1

    +

    Heading 2

    +

    Heading 3

    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +

    Heading 4

    +
    Heading 5
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +
    Heading 6
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +
      +
    1. print "Hello World"
    2. +
    3. print "Hello World"
    4. +
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +
    + + diff --git a/modules/editor/skins/xquared/examples/form_and_textarea.html b/modules/editor/skins/xquared/examples/form_and_textarea.html new file mode 100644 index 000000000..8423f9355 --- /dev/null +++ b/modules/editor/skins/xquared/examples/form_and_textarea.html @@ -0,0 +1,30 @@ + + + + +Xquared example - Form and Textarea + + + + + + + + + + + + + + diff --git a/modules/editor/skins/xquared/examples/img/content/blockquote.gif b/modules/editor/skins/xquared/examples/img/content/blockquote.gif new file mode 100644 index 0000000000000000000000000000000000000000..3efb99fe04a82787a354cc41cd7ffc7c8bd40083 GIT binary patch literal 99 zcmZ?wbhEHblwuHMn8?7;($aGB&J0Alwf AiU0rr literal 0 HcmV?d00001 diff --git a/modules/editor/skins/xquared/examples/img/content/code.gif b/modules/editor/skins/xquared/examples/img/content/code.gif new file mode 100644 index 0000000000000000000000000000000000000000..151ab68e0ac61e8c86800eaa15ac592fcb0fa3ed GIT binary patch literal 114 zcmZ?wbhEHblwuHMn8?7;($eyOd*lEA{}~t<6o0Y+Nd^WT5CM{BU~=y1U#a<)|1tNb zD980>m9O;}8kEf*Nz9YUY}2(`B%}z2Gd|I=9zd<)oM0&q%%zhg*Z=1|paTyb(<&XRpkWtLs^+#cF!?Yz@23so11U0Jn| Hfx#L8vmhv1 literal 0 HcmV?d00001 diff --git a/modules/editor/skins/xquared/examples/img/toolbar/backgroundColor.gif b/modules/editor/skins/xquared/examples/img/toolbar/backgroundColor.gif new file mode 100644 index 0000000000000000000000000000000000000000..af46da29d16256e759871f70adc090d414014ae3 GIT binary patch literal 68 zcmZ?wbhEHb6kyn+a literal 0 HcmV?d00001 diff --git a/modules/editor/skins/xquared/examples/img/toolbar/code.gif b/modules/editor/skins/xquared/examples/img/toolbar/code.gif new file mode 100644 index 0000000000000000000000000000000000000000..0e8e1e010c22c52d973e8acf9f1916f4751be4d5 GIT binary patch literal 86 zcmZ?wbhEHblw{y%XkcUjg5Q7tDgI;uG8q|kKzxu41Cwq~|H{*E`IA{51UP4(kb3zm kcgBel6^mJ&lG~;qT2^Gac+sx1{I-vm_<6Y6+nE@w0W--RRsaA1 literal 0 HcmV?d00001 diff --git a/modules/editor/skins/xquared/examples/img/toolbar/division.gif b/modules/editor/skins/xquared/examples/img/toolbar/division.gif new file mode 100644 index 0000000000000000000000000000000000000000..6c032d194d920616d437100915be3e761a66eb27 GIT binary patch literal 76 zcmZ?wbhEHblw{y%XkcUjg5Q7tDgI;uG8q|kKzxu41Cw%3|H{*E`4^ikxWwSsW?d~? adZVIn`i_~(S{qX{CVq0c{;gM>!5RPv5*WAu literal 0 HcmV?d00001 diff --git a/modules/editor/skins/xquared/examples/img/toolbar/emphasis.gif b/modules/editor/skins/xquared/examples/img/toolbar/emphasis.gif new file mode 100644 index 0000000000000000000000000000000000000000..bcc53ea2e2dfeab5eb508114e7b143c87ed67af2 GIT binary patch literal 64 zcmZ?wbhEHb N>8ld;?4}5VH2~}n5zqht literal 0 HcmV?d00001 diff --git a/modules/editor/skins/xquared/examples/img/toolbar/foregroundColor.gif b/modules/editor/skins/xquared/examples/img/toolbar/foregroundColor.gif new file mode 100644 index 0000000000000000000000000000000000000000..a393d0d2999b6a1489c3b125d8f495912b496784 GIT binary patch literal 68 zcmZ?wbhEHb6kyjEB<5wG8q|kKzxu41Cw@7|H{*E`ITAPnxr$%`u@&} iynC#0(YBa~&aN}Ze)4AuZl(i3+8 literal 0 HcmV?d00001 diff --git a/modules/editor/skins/xquared/examples/img/toolbar/paragraph.gif b/modules/editor/skins/xquared/examples/img/toolbar/paragraph.gif new file mode 100644 index 0000000000000000000000000000000000000000..f8fa61e20b1df1165bae118dca71cad6165af0da GIT binary patch literal 73 zcmZ?wbhEHbw) TDArMsWHIllyVbkjVhq**WoH!N literal 0 HcmV?d00001 diff --git a/modules/editor/skins/xquared/examples/img/toolbar/subscription.gif b/modules/editor/skins/xquared/examples/img/toolbar/subscription.gif new file mode 100644 index 0000000000000000000000000000000000000000..5e7f73083f1a391b6c138674c156f79e67b1da1e GIT binary patch literal 66 zcmZ?wbhEHbpoh5C#To05DGzZvX%Q literal 0 HcmV?d00001 diff --git a/modules/editor/skins/xquared/examples/img/toolbar/table.gif b/modules/editor/skins/xquared/examples/img/toolbar/table.gif new file mode 100644 index 0000000000000000000000000000000000000000..4a559f82a9ac1f415d9734f49340ba397dcf1357 GIT binary patch literal 74 zcmZ?wbhEHb&qf0C2^}Yg~^Ch|W z-z|7wb6)?zf&vd6ss0m7iZo3u=3mg5;;=SqeON=;>9nZj=*>9)!o=!8-tPN( TEj51YFSGvGQ@6gKfx#L8TsK&q literal 0 HcmV?d00001 diff --git a/modules/editor/skins/xquared/examples/img/toolbar/toolbarButtonBg.gif b/modules/editor/skins/xquared/examples/img/toolbar/toolbarButtonBg.gif new file mode 100644 index 0000000000000000000000000000000000000000..75e74c168bdc9ee4badc9ff1a6a18a101d226b97 GIT binary patch literal 46 vcmZ?wbhEHbWMmL#XkcLY^y$<8|Nj+#vM_*v4u}BBFfg(9^e@=W%3uuuJ*NyS literal 0 HcmV?d00001 diff --git a/modules/editor/skins/xquared/examples/img/toolbar/toolbarSeparator.gif b/modules/editor/skins/xquared/examples/img/toolbar/toolbarSeparator.gif new file mode 100644 index 0000000000000000000000000000000000000000..571a3e846ce6034648f21310d3950168f5cac48f GIT binary patch literal 963 zcmZ?wbhEHbY-A8-_|59{IdO5}(MDP4E*Z}vhlc+DUaMkG z7Ck)KubX^Irqk%@nb{WV*Up^Wyxe<=UGuM+%)k|abFBNdawCHqE-w#Q>^0YG>#D1( zBQ|H<)oRdiT$gaTOV<0^s_TuZmsiD}4s*D?t>E#gslUqB-QAsep6kfz?fT(+|Nr5V Tv)QWm@NgZka$JtN0)sUGv}#^c literal 0 HcmV?d00001 diff --git a/modules/editor/skins/xquared/examples/img/toolbar/underline.gif b/modules/editor/skins/xquared/examples/img/toolbar/underline.gif new file mode 100644 index 0000000000000000000000000000000000000000..6b7e812a01c97c47f2f54a41d7fc425597093504 GIT binary patch literal 73 zcmZ?wbhEHbFZp!Gov4Aua-Ar_AS literal 0 HcmV?d00001 diff --git a/modules/editor/skins/xquared/examples/img/toolbar/undo.gif b/modules/editor/skins/xquared/examples/img/toolbar/undo.gif new file mode 100644 index 0000000000000000000000000000000000000000..19670bca2bc55f663e773bf507803b2adc46422c GIT binary patch literal 69 zcmZ?wbhEHb Ps&u`vUvrrkBZD;n5Q!3S literal 0 HcmV?d00001 diff --git a/modules/editor/skins/xquared/examples/toolbar_customized1.html b/modules/editor/skins/xquared/examples/toolbar_customized1.html new file mode 100644 index 000000000..648a33392 --- /dev/null +++ b/modules/editor/skins/xquared/examples/toolbar_customized1.html @@ -0,0 +1,43 @@ + + + + +Xquared example - Custom toolbar 1 + + + + + + + +
    + + diff --git a/modules/editor/skins/xquared/examples/toolbar_customized2.html b/modules/editor/skins/xquared/examples/toolbar_customized2.html new file mode 100644 index 000000000..84cdbdf5b --- /dev/null +++ b/modules/editor/skins/xquared/examples/toolbar_customized2.html @@ -0,0 +1,92 @@ + + + + +Xquared example - Custom toolbar 2 + + + + + + + + + +
    +
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +

    This holds true both for individuals as well as whole tagging communities.

    +
      +
    • Item 1
    • +
    • Item 2
    • +
    +

    This holds true both for individuals as well as whole tagging communities.

    +
      +
    • +

      Item 1

      +
        +
      1. Item 1
      2. +
      3. Item 2
      4. +
      +
    • +
    • Item 2
    • +
    • Item 3
    • +
    +

    This holds true both for individuals as well as whole tagging communities.

    +
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +
    +

    This holds true both for individuals as well as whole tagging communities.

    +
    +
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +
    +

    This holds true both for individuals as well as whole tagging communities.

    +
    +
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +

    Heading 1

    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +

    Heading 1

    +

    Heading 2

    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +

    Heading 1

    +

    Heading 2

    +

    Heading 3

    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +

    Heading 4

    +
    Heading 5
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +
    Heading 6
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +
      +
    1. print "Hello World"
    2. +
    3. print "Hello World"
    4. +
    +

    Most notably, it has been confirmed in many empirical studies on tagging(see e.g. [Golder:2005, Hotho:2006, Cattuto:2006]), that tag distributions tend follow a power law—a small number of tags is used very often, while a very large number of tags occurs very rarely.

    +
    +
    + + diff --git a/modules/editor/skins/xquared/examples/toolbar_disabled.html b/modules/editor/skins/xquared/examples/toolbar_disabled.html new file mode 100644 index 000000000..bcc90cc5a --- /dev/null +++ b/modules/editor/skins/xquared/examples/toolbar_disabled.html @@ -0,0 +1,28 @@ + + + + +Xquared example - No toolbar + + + + + + + +
    + + diff --git a/modules/editor/skins/xquared/js/prototype.js b/modules/editor/skins/xquared/js/prototype.js new file mode 100644 index 000000000..fc1ecbc38 --- /dev/null +++ b/modules/editor/skins/xquared/js/prototype.js @@ -0,0 +1,4184 @@ +/* Prototype JavaScript framework, version 1.6.0 + * (c) 2005-2007 Sam Stephenson + * + * Prototype is freely distributable under the terms of an MIT-style license. + * For details, see the Prototype web site: http://www.prototypejs.org/ + * + *--------------------------------------------------------------------------*/ + +var Prototype = { + Version: '1.6.0', + + Browser: { + IE: !!(window.attachEvent && !window.opera), + Opera: !!window.opera, + WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, + Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1, + MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/) + }, + + BrowserFeatures: { + XPath: !!document.evaluate, + ElementExtensions: !!window.HTMLElement, + SpecificElementExtensions: + document.createElement('div').__proto__ && + document.createElement('div').__proto__ !== + document.createElement('form').__proto__ + }, + + ScriptFragment: ']*>([\\S\\s]*?)<\/script>', + JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, + + emptyFunction: function() { }, + K: function(x) { return x } +}; + +if (Prototype.Browser.MobileSafari) + Prototype.BrowserFeatures.SpecificElementExtensions = false; + +if (Prototype.Browser.WebKit) + Prototype.BrowserFeatures.XPath = false; + +/* Based on Alex Arnell's inheritance implementation. */ +var Class = { + create: function() { + var parent = null, properties = $A(arguments); + if (Object.isFunction(properties[0])) + parent = properties.shift(); + + function klass() { + this.initialize.apply(this, arguments); + } + + Object.extend(klass, Class.Methods); + klass.superclass = parent; + klass.subclasses = []; + + if (parent) { + var subclass = function() { }; + subclass.prototype = parent.prototype; + klass.prototype = new subclass; + parent.subclasses.push(klass); + } + + for (var i = 0; i < properties.length; i++) + klass.addMethods(properties[i]); + + if (!klass.prototype.initialize) + klass.prototype.initialize = Prototype.emptyFunction; + + klass.prototype.constructor = klass; + + return klass; + } +}; + +Class.Methods = { + addMethods: function(source) { + var ancestor = this.superclass && this.superclass.prototype; + var properties = Object.keys(source); + + if (!Object.keys({ toString: true }).length) + properties.push("toString", "valueOf"); + + for (var i = 0, length = properties.length; i < length; i++) { + var property = properties[i], value = source[property]; + if (ancestor && Object.isFunction(value) && + value.argumentNames().first() == "$super") { + var method = value, value = Object.extend((function(m) { + return function() { return ancestor[m].apply(this, arguments) }; + })(property).wrap(method), { + valueOf: function() { return method }, + toString: function() { return method.toString() } + }); + } + this.prototype[property] = value; + } + + return this; + } +}; + +var Abstract = { }; + +Object.extend = function(destination, source) { + for (var property in source) + destination[property] = source[property]; + return destination; +}; + +Object.extend(Object, { + inspect: function(object) { + try { + if (object === undefined) return 'undefined'; + if (object === null) return 'null'; + return object.inspect ? object.inspect() : object.toString(); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } + }, + + toJSON: function(object) { + var type = typeof object; + switch (type) { + case 'undefined': + case 'function': + case 'unknown': return; + case 'boolean': return object.toString(); + } + + if (object === null) return 'null'; + if (object.toJSON) return object.toJSON(); + if (Object.isElement(object)) return; + + var results = []; + for (var property in object) { + var value = Object.toJSON(object[property]); + if (value !== undefined) + results.push(property.toJSON() + ': ' + value); + } + + return '{' + results.join(', ') + '}'; + }, + + toQueryString: function(object) { + return $H(object).toQueryString(); + }, + + toHTML: function(object) { + return object && object.toHTML ? object.toHTML() : String.interpret(object); + }, + + keys: function(object) { + var keys = []; + for (var property in object) + keys.push(property); + return keys; + }, + + values: function(object) { + var values = []; + for (var property in object) + values.push(object[property]); + return values; + }, + + clone: function(object) { + return Object.extend({ }, object); + }, + + isElement: function(object) { + return object && object.nodeType == 1; + }, + + isArray: function(object) { + return object && object.constructor === Array; + }, + + isHash: function(object) { + return object instanceof Hash; + }, + + isFunction: function(object) { + return typeof object == "function"; + }, + + isString: function(object) { + return typeof object == "string"; + }, + + isNumber: function(object) { + return typeof object == "number"; + }, + + isUndefined: function(object) { + return typeof object == "undefined"; + } +}); + +Object.extend(Function.prototype, { + argumentNames: function() { + var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip"); + return names.length == 1 && !names[0] ? [] : names; + }, + + bind: function() { + if (arguments.length < 2 && arguments[0] === undefined) return this; + var __method = this, args = $A(arguments), object = args.shift(); + return function() { + return __method.apply(object, args.concat($A(arguments))); + } + }, + + bindAsEventListener: function() { + var __method = this, args = $A(arguments), object = args.shift(); + return function(event) { + return __method.apply(object, [event || window.event].concat(args)); + } + }, + + curry: function() { + if (!arguments.length) return this; + var __method = this, args = $A(arguments); + return function() { + return __method.apply(this, args.concat($A(arguments))); + } + }, + + delay: function() { + var __method = this, args = $A(arguments), timeout = args.shift() * 1000; + return window.setTimeout(function() { + return __method.apply(__method, args); + }, timeout); + }, + + wrap: function(wrapper) { + var __method = this; + return function() { + return wrapper.apply(this, [__method.bind(this)].concat($A(arguments))); + } + }, + + methodize: function() { + if (this._methodized) return this._methodized; + var __method = this; + return this._methodized = function() { + return __method.apply(null, [this].concat($A(arguments))); + }; + } +}); + +Function.prototype.defer = Function.prototype.delay.curry(0.01); + +Date.prototype.toJSON = function() { + return '"' + this.getUTCFullYear() + '-' + + (this.getUTCMonth() + 1).toPaddedString(2) + '-' + + this.getUTCDate().toPaddedString(2) + 'T' + + this.getUTCHours().toPaddedString(2) + ':' + + this.getUTCMinutes().toPaddedString(2) + ':' + + this.getUTCSeconds().toPaddedString(2) + 'Z"'; +}; + +var Try = { + these: function() { + var returnValue; + + for (var i = 0, length = arguments.length; i < length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) { } + } + + return returnValue; + } +}; + +RegExp.prototype.match = RegExp.prototype.test; + +RegExp.escape = function(str) { + return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); +}; + +/*--------------------------------------------------------------------------*/ + +var PeriodicalExecuter = Class.create({ + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this.currentlyExecuting = false; + + this.registerCallback(); + }, + + registerCallback: function() { + this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + execute: function() { + this.callback(this); + }, + + stop: function() { + if (!this.timer) return; + clearInterval(this.timer); + this.timer = null; + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.execute(); + } finally { + this.currentlyExecuting = false; + } + } + } +}); +Object.extend(String, { + interpret: function(value) { + return value == null ? '' : String(value); + }, + specialChar: { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '\\': '\\\\' + } +}); + +Object.extend(String.prototype, { + gsub: function(pattern, replacement) { + var result = '', source = this, match; + replacement = arguments.callee.prepareReplacement(replacement); + + while (source.length > 0) { + if (match = source.match(pattern)) { + result += source.slice(0, match.index); + result += String.interpret(replacement(match)); + source = source.slice(match.index + match[0].length); + } else { + result += source, source = ''; + } + } + return result; + }, + + sub: function(pattern, replacement, count) { + replacement = this.gsub.prepareReplacement(replacement); + count = count === undefined ? 1 : count; + + return this.gsub(pattern, function(match) { + if (--count < 0) return match[0]; + return replacement(match); + }); + }, + + scan: function(pattern, iterator) { + this.gsub(pattern, iterator); + return String(this); + }, + + truncate: function(length, truncation) { + length = length || 30; + truncation = truncation === undefined ? '...' : truncation; + return this.length > length ? + this.slice(0, length - truncation.length) + truncation : String(this); + }, + + strip: function() { + return this.replace(/^\s+/, '').replace(/\s+$/, ''); + }, + + stripTags: function() { + return this.replace(/<\/?[^>]+>/gi, ''); + }, + + stripScripts: function() { + return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); + }, + + extractScripts: function() { + var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); + var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); + return (this.match(matchAll) || []).map(function(scriptTag) { + return (scriptTag.match(matchOne) || ['', ''])[1]; + }); + }, + + evalScripts: function() { + return this.extractScripts().map(function(script) { return eval(script) }); + }, + + escapeHTML: function() { + var self = arguments.callee; + self.text.data = this; + return self.div.innerHTML; + }, + + unescapeHTML: function() { + var div = new Element('div'); + div.innerHTML = this.stripTags(); + return div.childNodes[0] ? (div.childNodes.length > 1 ? + $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : + div.childNodes[0].nodeValue) : ''; + }, + + toQueryParams: function(separator) { + var match = this.strip().match(/([^?#]*)(#.*)?$/); + if (!match) return { }; + + return match[1].split(separator || '&').inject({ }, function(hash, pair) { + if ((pair = pair.split('='))[0]) { + var key = decodeURIComponent(pair.shift()); + var value = pair.length > 1 ? pair.join('=') : pair[0]; + if (value != undefined) value = decodeURIComponent(value); + + if (key in hash) { + if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; + hash[key].push(value); + } + else hash[key] = value; + } + return hash; + }); + }, + + toArray: function() { + return this.split(''); + }, + + succ: function() { + return this.slice(0, this.length - 1) + + String.fromCharCode(this.charCodeAt(this.length - 1) + 1); + }, + + times: function(count) { + return count < 1 ? '' : new Array(count + 1).join(this); + }, + + camelize: function() { + var parts = this.split('-'), len = parts.length; + if (len == 1) return parts[0]; + + var camelized = this.charAt(0) == '-' + ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) + : parts[0]; + + for (var i = 1; i < len; i++) + camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); + + return camelized; + }, + + capitalize: function() { + return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); + }, + + underscore: function() { + return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); + }, + + dasherize: function() { + return this.gsub(/_/,'-'); + }, + + inspect: function(useDoubleQuotes) { + var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { + var character = String.specialChar[match[0]]; + return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16); + }); + if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; + return "'" + escapedString.replace(/'/g, '\\\'') + "'"; + }, + + toJSON: function() { + return this.inspect(true); + }, + + unfilterJSON: function(filter) { + return this.sub(filter || Prototype.JSONFilter, '#{1}'); + }, + + isJSON: function() { + var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); + return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); + }, + + evalJSON: function(sanitize) { + var json = this.unfilterJSON(); + try { + if (!sanitize || json.isJSON()) return eval('(' + json + ')'); + } catch (e) { } + throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); + }, + + include: function(pattern) { + return this.indexOf(pattern) > -1; + }, + + startsWith: function(pattern) { + return this.indexOf(pattern) === 0; + }, + + endsWith: function(pattern) { + var d = this.length - pattern.length; + return d >= 0 && this.lastIndexOf(pattern) === d; + }, + + empty: function() { + return this == ''; + }, + + blank: function() { + return /^\s*$/.test(this); + }, + + interpolate: function(object, pattern) { + return new Template(this, pattern).evaluate(object); + } +}); + +if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { + escapeHTML: function() { + return this.replace(/&/g,'&').replace(//g,'>'); + }, + unescapeHTML: function() { + return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); + } +}); + +String.prototype.gsub.prepareReplacement = function(replacement) { + if (Object.isFunction(replacement)) return replacement; + var template = new Template(replacement); + return function(match) { return template.evaluate(match) }; +}; + +String.prototype.parseQuery = String.prototype.toQueryParams; + +Object.extend(String.prototype.escapeHTML, { + div: document.createElement('div'), + text: document.createTextNode('') +}); + +with (String.prototype.escapeHTML) div.appendChild(text); + +var Template = Class.create({ + initialize: function(template, pattern) { + this.template = template.toString(); + this.pattern = pattern || Template.Pattern; + }, + + evaluate: function(object) { + if (Object.isFunction(object.toTemplateReplacements)) + object = object.toTemplateReplacements(); + + return this.template.gsub(this.pattern, function(match) { + if (object == null) return ''; + + var before = match[1] || ''; + if (before == '\\') return match[2]; + + var ctx = object, expr = match[3]; + var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/, match = pattern.exec(expr); + if (match == null) return before; + + while (match != null) { + var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1]; + ctx = ctx[comp]; + if (null == ctx || '' == match[3]) break; + expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); + match = pattern.exec(expr); + } + + return before + String.interpret(ctx); + }.bind(this)); + } +}); +Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; + +var $break = { }; + +var Enumerable = { + each: function(iterator, context) { + var index = 0; + iterator = iterator.bind(context); + try { + this._each(function(value) { + iterator(value, index++); + }); + } catch (e) { + if (e != $break) throw e; + } + return this; + }, + + eachSlice: function(number, iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var index = -number, slices = [], array = this.toArray(); + while ((index += number) < array.length) + slices.push(array.slice(index, index+number)); + return slices.collect(iterator, context); + }, + + all: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var result = true; + this.each(function(value, index) { + result = result && !!iterator(value, index); + if (!result) throw $break; + }); + return result; + }, + + any: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var result = false; + this.each(function(value, index) { + if (result = !!iterator(value, index)) + throw $break; + }); + return result; + }, + + collect: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var results = []; + this.each(function(value, index) { + results.push(iterator(value, index)); + }); + return results; + }, + + detect: function(iterator, context) { + iterator = iterator.bind(context); + var result; + this.each(function(value, index) { + if (iterator(value, index)) { + result = value; + throw $break; + } + }); + return result; + }, + + findAll: function(iterator, context) { + iterator = iterator.bind(context); + var results = []; + this.each(function(value, index) { + if (iterator(value, index)) + results.push(value); + }); + return results; + }, + + grep: function(filter, iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var results = []; + + if (Object.isString(filter)) + filter = new RegExp(filter); + + this.each(function(value, index) { + if (filter.match(value)) + results.push(iterator(value, index)); + }); + return results; + }, + + include: function(object) { + if (Object.isFunction(this.indexOf)) + if (this.indexOf(object) != -1) return true; + + var found = false; + this.each(function(value) { + if (value == object) { + found = true; + throw $break; + } + }); + return found; + }, + + inGroupsOf: function(number, fillWith) { + fillWith = fillWith === undefined ? null : fillWith; + return this.eachSlice(number, function(slice) { + while(slice.length < number) slice.push(fillWith); + return slice; + }); + }, + + inject: function(memo, iterator, context) { + iterator = iterator.bind(context); + this.each(function(value, index) { + memo = iterator(memo, value, index); + }); + return memo; + }, + + invoke: function(method) { + var args = $A(arguments).slice(1); + return this.map(function(value) { + return value[method].apply(value, args); + }); + }, + + max: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var result; + this.each(function(value, index) { + value = iterator(value, index); + if (result == undefined || value >= result) + result = value; + }); + return result; + }, + + min: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var result; + this.each(function(value, index) { + value = iterator(value, index); + if (result == undefined || value < result) + result = value; + }); + return result; + }, + + partition: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var trues = [], falses = []; + this.each(function(value, index) { + (iterator(value, index) ? + trues : falses).push(value); + }); + return [trues, falses]; + }, + + pluck: function(property) { + var results = []; + this.each(function(value) { + results.push(value[property]); + }); + return results; + }, + + reject: function(iterator, context) { + iterator = iterator.bind(context); + var results = []; + this.each(function(value, index) { + if (!iterator(value, index)) + results.push(value); + }); + return results; + }, + + sortBy: function(iterator, context) { + iterator = iterator.bind(context); + return this.map(function(value, index) { + return {value: value, criteria: iterator(value, index)}; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }).pluck('value'); + }, + + toArray: function() { + return this.map(); + }, + + zip: function() { + var iterator = Prototype.K, args = $A(arguments); + if (Object.isFunction(args.last())) + iterator = args.pop(); + + var collections = [this].concat(args).map($A); + return this.map(function(value, index) { + return iterator(collections.pluck(index)); + }); + }, + + size: function() { + return this.toArray().length; + }, + + inspect: function() { + return '#'; + } +}; + +Object.extend(Enumerable, { + map: Enumerable.collect, + find: Enumerable.detect, + select: Enumerable.findAll, + filter: Enumerable.findAll, + member: Enumerable.include, + entries: Enumerable.toArray, + every: Enumerable.all, + some: Enumerable.any +}); +function $A(iterable) { + if (!iterable) return []; + if (iterable.toArray) return iterable.toArray(); + var length = iterable.length, results = new Array(length); + while (length--) results[length] = iterable[length]; + return results; +} + +if (Prototype.Browser.WebKit) { + function $A(iterable) { + if (!iterable) return []; + if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') && + iterable.toArray) return iterable.toArray(); + var length = iterable.length, results = new Array(length); + while (length--) results[length] = iterable[length]; + return results; + } +} + +Array.from = $A; + +Object.extend(Array.prototype, Enumerable); + +if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse; + +Object.extend(Array.prototype, { + _each: function(iterator) { + for (var i = 0, length = this.length; i < length; i++) + iterator(this[i]); + }, + + clear: function() { + this.length = 0; + return this; + }, + + first: function() { + return this[0]; + }, + + last: function() { + return this[this.length - 1]; + }, + + compact: function() { + return this.select(function(value) { + return value != null; + }); + }, + + flatten: function() { + return this.inject([], function(array, value) { + return array.concat(Object.isArray(value) ? + value.flatten() : [value]); + }); + }, + + without: function() { + var values = $A(arguments); + return this.select(function(value) { + return !values.include(value); + }); + }, + + reverse: function(inline) { + return (inline !== false ? this : this.toArray())._reverse(); + }, + + reduce: function() { + return this.length > 1 ? this : this[0]; + }, + + uniq: function(sorted) { + return this.inject([], function(array, value, index) { + if (0 == index || (sorted ? array.last() != value : !array.include(value))) + array.push(value); + return array; + }); + }, + + intersect: function(array) { + return this.uniq().findAll(function(item) { + return array.detect(function(value) { return item === value }); + }); + }, + + clone: function() { + return [].concat(this); + }, + + size: function() { + return this.length; + }, + + inspect: function() { + return '[' + this.map(Object.inspect).join(', ') + ']'; + }, + + toJSON: function() { + var results = []; + this.each(function(object) { + var value = Object.toJSON(object); + if (value !== undefined) results.push(value); + }); + return '[' + results.join(', ') + ']'; + } +}); + +// use native browser JS 1.6 implementation if available +if (Object.isFunction(Array.prototype.forEach)) + Array.prototype._each = Array.prototype.forEach; + +if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) { + i || (i = 0); + var length = this.length; + if (i < 0) i = length + i; + for (; i < length; i++) + if (this[i] === item) return i; + return -1; +}; + +if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) { + i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; + var n = this.slice(0, i).reverse().indexOf(item); + return (n < 0) ? n : i - n - 1; +}; + +Array.prototype.toArray = Array.prototype.clone; + +function $w(string) { + if (!Object.isString(string)) return []; + string = string.strip(); + return string ? string.split(/\s+/) : []; +} + +if (Prototype.Browser.Opera){ + Array.prototype.concat = function() { + var array = []; + for (var i = 0, length = this.length; i < length; i++) array.push(this[i]); + for (var i = 0, length = arguments.length; i < length; i++) { + if (Object.isArray(arguments[i])) { + for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) + array.push(arguments[i][j]); + } else { + array.push(arguments[i]); + } + } + return array; + }; +} +Object.extend(Number.prototype, { + toColorPart: function() { + return this.toPaddedString(2, 16); + }, + + succ: function() { + return this + 1; + }, + + times: function(iterator) { + $R(0, this, true).each(iterator); + return this; + }, + + toPaddedString: function(length, radix) { + var string = this.toString(radix || 10); + return '0'.times(length - string.length) + string; + }, + + toJSON: function() { + return isFinite(this) ? this.toString() : 'null'; + } +}); + +$w('abs round ceil floor').each(function(method){ + Number.prototype[method] = Math[method].methodize(); +}); +function $H(object) { + return new Hash(object); +}; + +var Hash = Class.create(Enumerable, (function() { + if (function() { + var i = 0, Test = function(value) { this.key = value }; + Test.prototype.key = 'foo'; + for (var property in new Test('bar')) i++; + return i > 1; + }()) { + function each(iterator) { + var cache = []; + for (var key in this._object) { + var value = this._object[key]; + if (cache.include(key)) continue; + cache.push(key); + var pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + } + } else { + function each(iterator) { + for (var key in this._object) { + var value = this._object[key], pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + } + } + + function toQueryPair(key, value) { + if (Object.isUndefined(value)) return key; + return key + '=' + encodeURIComponent(String.interpret(value)); + } + + return { + initialize: function(object) { + this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); + }, + + _each: each, + + set: function(key, value) { + return this._object[key] = value; + }, + + get: function(key) { + return this._object[key]; + }, + + unset: function(key) { + var value = this._object[key]; + delete this._object[key]; + return value; + }, + + toObject: function() { + return Object.clone(this._object); + }, + + keys: function() { + return this.pluck('key'); + }, + + values: function() { + return this.pluck('value'); + }, + + index: function(value) { + var match = this.detect(function(pair) { + return pair.value === value; + }); + return match && match.key; + }, + + merge: function(object) { + return this.clone().update(object); + }, + + update: function(object) { + return new Hash(object).inject(this, function(result, pair) { + result.set(pair.key, pair.value); + return result; + }); + }, + + toQueryString: function() { + return this.map(function(pair) { + var key = encodeURIComponent(pair.key), values = pair.value; + + if (values && typeof values == 'object') { + if (Object.isArray(values)) + return values.map(toQueryPair.curry(key)).join('&'); + } + return toQueryPair(key, values); + }).join('&'); + }, + + inspect: function() { + return '#'; + }, + + toJSON: function() { + return Object.toJSON(this.toObject()); + }, + + clone: function() { + return new Hash(this); + } + } +})()); + +Hash.prototype.toTemplateReplacements = Hash.prototype.toObject; +Hash.from = $H; +var ObjectRange = Class.create(Enumerable, { + initialize: function(start, end, exclusive) { + this.start = start; + this.end = end; + this.exclusive = exclusive; + }, + + _each: function(iterator) { + var value = this.start; + while (this.include(value)) { + iterator(value); + value = value.succ(); + } + }, + + include: function(value) { + if (value < this.start) + return false; + if (this.exclusive) + return value < this.end; + return value <= this.end; + } +}); + +var $R = function(start, end, exclusive) { + return new ObjectRange(start, end, exclusive); +}; + +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new XMLHttpRequest()}, + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')} + ) || false; + }, + + activeRequestCount: 0 +}; + +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responder) { + if (!this.include(responder)) + this.responders.push(responder); + }, + + unregister: function(responder) { + this.responders = this.responders.without(responder); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (Object.isFunction(responder[callback])) { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) { } + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { Ajax.activeRequestCount++ }, + onComplete: function() { Ajax.activeRequestCount-- } +}); + +Ajax.Base = Class.create({ + initialize: function(options) { + this.options = { + method: 'post', + asynchronous: true, + contentType: 'application/x-www-form-urlencoded', + encoding: 'UTF-8', + parameters: '', + evalJSON: true, + evalJS: true + }; + Object.extend(this.options, options || { }); + + this.options.method = this.options.method.toLowerCase(); + if (Object.isString(this.options.parameters)) + this.options.parameters = this.options.parameters.toQueryParams(); + } +}); + +Ajax.Request = Class.create(Ajax.Base, { + _complete: false, + + initialize: function($super, url, options) { + $super(options); + this.transport = Ajax.getTransport(); + this.request(url); + }, + + request: function(url) { + this.url = url; + this.method = this.options.method; + var params = Object.clone(this.options.parameters); + + if (!['get', 'post'].include(this.method)) { + // simulate other verbs over post + params['_method'] = this.method; + this.method = 'post'; + } + + this.parameters = params; + + if (params = Object.toQueryString(params)) { + // when GET, append parameters to URL + if (this.method == 'get') + this.url += (this.url.include('?') ? '&' : '?') + params; + else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) + params += '&_='; + } + + try { + var response = new Ajax.Response(this); + if (this.options.onCreate) this.options.onCreate(response); + Ajax.Responders.dispatch('onCreate', this, response); + + this.transport.open(this.method.toUpperCase(), this.url, + this.options.asynchronous); + + if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); + + this.transport.onreadystatechange = this.onStateChange.bind(this); + this.setRequestHeaders(); + + this.body = this.method == 'post' ? (this.options.postBody || params) : null; + this.transport.send(this.body); + + /* Force Firefox to handle ready state 4 for synchronous requests */ + if (!this.options.asynchronous && this.transport.overrideMimeType) + this.onStateChange(); + + } + catch (e) { + this.dispatchException(e); + } + }, + + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState > 1 && !((readyState == 4) && this._complete)) + this.respondToReadyState(this.transport.readyState); + }, + + setRequestHeaders: function() { + var headers = { + 'X-Requested-With': 'XMLHttpRequest', + 'X-Prototype-Version': Prototype.Version, + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' + }; + + if (this.method == 'post') { + headers['Content-type'] = this.options.contentType + + (this.options.encoding ? '; charset=' + this.options.encoding : ''); + + /* Force "Connection: close" for older Mozilla browsers to work + * around a bug where XMLHttpRequest sends an incorrect + * Content-length header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType && + (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) + headers['Connection'] = 'close'; + } + + // user-defined headers + if (typeof this.options.requestHeaders == 'object') { + var extras = this.options.requestHeaders; + + if (Object.isFunction(extras.push)) + for (var i = 0, length = extras.length; i < length; i += 2) + headers[extras[i]] = extras[i+1]; + else + $H(extras).each(function(pair) { headers[pair.key] = pair.value }); + } + + for (var name in headers) + this.transport.setRequestHeader(name, headers[name]); + }, + + success: function() { + var status = this.getStatus(); + return !status || (status >= 200 && status < 300); + }, + + getStatus: function() { + try { + return this.transport.status || 0; + } catch (e) { return 0 } + }, + + respondToReadyState: function(readyState) { + var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); + + if (state == 'Complete') { + try { + this._complete = true; + (this.options['on' + response.status] + || this.options['on' + (this.success() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(response, response.headerJSON); + } catch (e) { + this.dispatchException(e); + } + + var contentType = response.getHeader('Content-type'); + if (this.options.evalJS == 'force' + || (this.options.evalJS && contentType + && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) + this.evalResponse(); + } + + try { + (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); + Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); + } catch (e) { + this.dispatchException(e); + } + + if (state == 'Complete') { + // avoid memory leak in MSIE: clean up + this.transport.onreadystatechange = Prototype.emptyFunction; + } + }, + + getHeader: function(name) { + try { + return this.transport.getResponseHeader(name); + } catch (e) { return null } + }, + + evalResponse: function() { + try { + return eval((this.transport.responseText || '').unfilterJSON()); + } catch (e) { + this.dispatchException(e); + } + }, + + dispatchException: function(exception) { + (this.options.onException || Prototype.emptyFunction)(this, exception); + Ajax.Responders.dispatch('onException', this, exception); + } +}); + +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + +Ajax.Response = Class.create({ + initialize: function(request){ + this.request = request; + var transport = this.transport = request.transport, + readyState = this.readyState = transport.readyState; + + if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { + this.status = this.getStatus(); + this.statusText = this.getStatusText(); + this.responseText = String.interpret(transport.responseText); + this.headerJSON = this._getHeaderJSON(); + } + + if(readyState == 4) { + var xml = transport.responseXML; + this.responseXML = xml === undefined ? null : xml; + this.responseJSON = this._getResponseJSON(); + } + }, + + status: 0, + statusText: '', + + getStatus: Ajax.Request.prototype.getStatus, + + getStatusText: function() { + try { + return this.transport.statusText || ''; + } catch (e) { return '' } + }, + + getHeader: Ajax.Request.prototype.getHeader, + + getAllHeaders: function() { + try { + return this.getAllResponseHeaders(); + } catch (e) { return null } + }, + + getResponseHeader: function(name) { + return this.transport.getResponseHeader(name); + }, + + getAllResponseHeaders: function() { + return this.transport.getAllResponseHeaders(); + }, + + _getHeaderJSON: function() { + var json = this.getHeader('X-JSON'); + if (!json) return null; + json = decodeURIComponent(escape(json)); + try { + return json.evalJSON(this.request.options.sanitizeJSON); + } catch (e) { + this.request.dispatchException(e); + } + }, + + _getResponseJSON: function() { + var options = this.request.options; + if (!options.evalJSON || (options.evalJSON != 'force' && + !(this.getHeader('Content-type') || '').include('application/json'))) + return null; + try { + return this.transport.responseText.evalJSON(options.sanitizeJSON); + } catch (e) { + this.request.dispatchException(e); + } + } +}); + +Ajax.Updater = Class.create(Ajax.Request, { + initialize: function($super, container, url, options) { + this.container = { + success: (container.success || container), + failure: (container.failure || (container.success ? null : container)) + }; + + options = options || { }; + var onComplete = options.onComplete; + options.onComplete = (function(response, param) { + this.updateContent(response.responseText); + if (Object.isFunction(onComplete)) onComplete(response, param); + }).bind(this); + + $super(url, options); + }, + + updateContent: function(responseText) { + var receiver = this.container[this.success() ? 'success' : 'failure'], + options = this.options; + + if (!options.evalScripts) responseText = responseText.stripScripts(); + + if (receiver = $(receiver)) { + if (options.insertion) { + if (Object.isString(options.insertion)) { + var insertion = { }; insertion[options.insertion] = responseText; + receiver.insert(insertion); + } + else options.insertion(receiver, responseText); + } + else receiver.update(responseText); + } + + if (this.success()) { + if (this.onComplete) this.onComplete.bind(this).defer(); + } + } +}); + +Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { + initialize: function($super, container, url, options) { + $super(options); + this.onComplete = this.options.onComplete; + + this.frequency = (this.options.frequency || 2); + this.decay = (this.options.decay || 1); + + this.updater = { }; + this.container = container; + this.url = url; + + this.start(); + }, + + start: function() { + this.options.onComplete = this.updateComplete.bind(this); + this.onTimerEvent(); + }, + + stop: function() { + this.updater.options.onComplete = undefined; + clearTimeout(this.timer); + (this.onComplete || Prototype.emptyFunction).apply(this, arguments); + }, + + updateComplete: function(response) { + if (this.options.decay) { + this.decay = (response.responseText == this.lastText ? + this.decay * this.options.decay : 1); + + this.lastText = response.responseText; + } + this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); + }, + + onTimerEvent: function() { + this.updater = new Ajax.Updater(this.container, this.url, this.options); + } +}); +function $(element) { + if (arguments.length > 1) { + for (var i = 0, elements = [], length = arguments.length; i < length; i++) + elements.push($(arguments[i])); + return elements; + } + if (Object.isString(element)) + element = document.getElementById(element); + return Element.extend(element); +} + +if (Prototype.BrowserFeatures.XPath) { + document._getElementsByXPath = function(expression, parentElement) { + var results = []; + var query = document.evaluate(expression, $(parentElement) || document, + null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + for (var i = 0, length = query.snapshotLength; i < length; i++) + results.push(Element.extend(query.snapshotItem(i))); + return results; + }; +} + +/*--------------------------------------------------------------------------*/ + +if (!window.Node) var Node = { }; + +if (!Node.ELEMENT_NODE) { + // DOM level 2 ECMAScript Language Binding + Object.extend(Node, { + ELEMENT_NODE: 1, + ATTRIBUTE_NODE: 2, + TEXT_NODE: 3, + CDATA_SECTION_NODE: 4, + ENTITY_REFERENCE_NODE: 5, + ENTITY_NODE: 6, + PROCESSING_INSTRUCTION_NODE: 7, + COMMENT_NODE: 8, + DOCUMENT_NODE: 9, + DOCUMENT_TYPE_NODE: 10, + DOCUMENT_FRAGMENT_NODE: 11, + NOTATION_NODE: 12 + }); +} + +(function() { + var element = this.Element; + this.Element = function(tagName, attributes) { + attributes = attributes || { }; + tagName = tagName.toLowerCase(); + var cache = Element.cache; + if (Prototype.Browser.IE && attributes.name) { + tagName = '<' + tagName + ' name="' + attributes.name + '">'; + delete attributes.name; + return Element.writeAttribute(document.createElement(tagName), attributes); + } + if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); + return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); + }; + Object.extend(this.Element, element || { }); +}).call(window); + +Element.cache = { }; + +Element.Methods = { + visible: function(element) { + return $(element).style.display != 'none'; + }, + + toggle: function(element) { + element = $(element); + Element[Element.visible(element) ? 'hide' : 'show'](element); + return element; + }, + + hide: function(element) { + $(element).style.display = 'none'; + return element; + }, + + show: function(element) { + $(element).style.display = ''; + return element; + }, + + remove: function(element) { + element = $(element); + element.parentNode.removeChild(element); + return element; + }, + + update: function(element, content) { + element = $(element); + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) return element.update().insert(content); + content = Object.toHTML(content); + element.innerHTML = content.stripScripts(); + content.evalScripts.bind(content).defer(); + return element; + }, + + replace: function(element, content) { + element = $(element); + if (content && content.toElement) content = content.toElement(); + else if (!Object.isElement(content)) { + content = Object.toHTML(content); + var range = element.ownerDocument.createRange(); + range.selectNode(element); + content.evalScripts.bind(content).defer(); + content = range.createContextualFragment(content.stripScripts()); + } + element.parentNode.replaceChild(content, element); + return element; + }, + + insert: function(element, insertions) { + element = $(element); + + if (Object.isString(insertions) || Object.isNumber(insertions) || + Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) + insertions = {bottom:insertions}; + + var content, t, range; + + for (position in insertions) { + content = insertions[position]; + position = position.toLowerCase(); + t = Element._insertionTranslations[position]; + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) { + t.insert(element, content); + continue; + } + + content = Object.toHTML(content); + + range = element.ownerDocument.createRange(); + t.initializeRange(element, range); + t.insert(element, range.createContextualFragment(content.stripScripts())); + + content.evalScripts.bind(content).defer(); + } + + return element; + }, + + wrap: function(element, wrapper, attributes) { + element = $(element); + if (Object.isElement(wrapper)) + $(wrapper).writeAttribute(attributes || { }); + else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); + else wrapper = new Element('div', wrapper); + if (element.parentNode) + element.parentNode.replaceChild(wrapper, element); + wrapper.appendChild(element); + return wrapper; + }, + + inspect: function(element) { + element = $(element); + var result = '<' + element.tagName.toLowerCase(); + $H({'id': 'id', 'className': 'class'}).each(function(pair) { + var property = pair.first(), attribute = pair.last(); + var value = (element[property] || '').toString(); + if (value) result += ' ' + attribute + '=' + value.inspect(true); + }); + return result + '>'; + }, + + recursivelyCollect: function(element, property) { + element = $(element); + var elements = []; + while (element = element[property]) + if (element.nodeType == 1) + elements.push(Element.extend(element)); + return elements; + }, + + ancestors: function(element) { + return $(element).recursivelyCollect('parentNode'); + }, + + descendants: function(element) { + return $A($(element).getElementsByTagName('*')).each(Element.extend); + }, + + firstDescendant: function(element) { + element = $(element).firstChild; + while (element && element.nodeType != 1) element = element.nextSibling; + return $(element); + }, + + immediateDescendants: function(element) { + if (!(element = $(element).firstChild)) return []; + while (element && element.nodeType != 1) element = element.nextSibling; + if (element) return [element].concat($(element).nextSiblings()); + return []; + }, + + previousSiblings: function(element) { + return $(element).recursivelyCollect('previousSibling'); + }, + + nextSiblings: function(element) { + return $(element).recursivelyCollect('nextSibling'); + }, + + siblings: function(element) { + element = $(element); + return element.previousSiblings().reverse().concat(element.nextSiblings()); + }, + + match: function(element, selector) { + if (Object.isString(selector)) + selector = new Selector(selector); + return selector.match($(element)); + }, + + up: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(element.parentNode); + var ancestors = element.ancestors(); + return expression ? Selector.findElement(ancestors, expression, index) : + ancestors[index || 0]; + }, + + down: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return element.firstDescendant(); + var descendants = element.descendants(); + return expression ? Selector.findElement(descendants, expression, index) : + descendants[index || 0]; + }, + + previous: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); + var previousSiblings = element.previousSiblings(); + return expression ? Selector.findElement(previousSiblings, expression, index) : + previousSiblings[index || 0]; + }, + + next: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); + var nextSiblings = element.nextSiblings(); + return expression ? Selector.findElement(nextSiblings, expression, index) : + nextSiblings[index || 0]; + }, + + select: function() { + var args = $A(arguments), element = $(args.shift()); + return Selector.findChildElements(element, args); + }, + + adjacent: function() { + var args = $A(arguments), element = $(args.shift()); + return Selector.findChildElements(element.parentNode, args).without(element); + }, + + identify: function(element) { + element = $(element); + var id = element.readAttribute('id'), self = arguments.callee; + if (id) return id; + do { id = 'anonymous_element_' + self.counter++ } while ($(id)); + element.writeAttribute('id', id); + return id; + }, + + readAttribute: function(element, name) { + element = $(element); + if (Prototype.Browser.IE) { + var t = Element._attributeTranslations.read; + if (t.values[name]) return t.values[name](element, name); + if (t.names[name]) name = t.names[name]; + if (name.include(':')) { + return (!element.attributes || !element.attributes[name]) ? null : + element.attributes[name].value; + } + } + return element.getAttribute(name); + }, + + writeAttribute: function(element, name, value) { + element = $(element); + var attributes = { }, t = Element._attributeTranslations.write; + + if (typeof name == 'object') attributes = name; + else attributes[name] = value === undefined ? true : value; + + for (var attr in attributes) { + var name = t.names[attr] || attr, value = attributes[attr]; + if (t.values[attr]) name = t.values[attr](element, value); + if (value === false || value === null) + element.removeAttribute(name); + else if (value === true) + element.setAttribute(name, name); + else element.setAttribute(name, value); + } + return element; + }, + + getHeight: function(element) { + return $(element).getDimensions().height; + }, + + getWidth: function(element) { + return $(element).getDimensions().width; + }, + + classNames: function(element) { + return new Element.ClassNames(element); + }, + + hasClassName: function(element, className) { + if (!(element = $(element))) return; + var elementClassName = element.className; + return (elementClassName.length > 0 && (elementClassName == className || + new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); + }, + + addClassName: function(element, className) { + if (!(element = $(element))) return; + if (!element.hasClassName(className)) + element.className += (element.className ? ' ' : '') + className; + return element; + }, + + removeClassName: function(element, className) { + if (!(element = $(element))) return; + element.className = element.className.replace( + new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); + return element; + }, + + toggleClassName: function(element, className) { + if (!(element = $(element))) return; + return element[element.hasClassName(className) ? + 'removeClassName' : 'addClassName'](className); + }, + + // removes whitespace-only text node children + cleanWhitespace: function(element) { + element = $(element); + var node = element.firstChild; + while (node) { + var nextNode = node.nextSibling; + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + element.removeChild(node); + node = nextNode; + } + return element; + }, + + empty: function(element) { + return $(element).innerHTML.blank(); + }, + + descendantOf: function(element, ancestor) { + element = $(element), ancestor = $(ancestor); + + if (element.compareDocumentPosition) + return (element.compareDocumentPosition(ancestor) & 8) === 8; + + if (element.sourceIndex && !Prototype.Browser.Opera) { + var e = element.sourceIndex, a = ancestor.sourceIndex, + nextAncestor = ancestor.nextSibling; + if (!nextAncestor) { + do { ancestor = ancestor.parentNode; } + while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode); + } + if (nextAncestor) return (e > a && e < nextAncestor.sourceIndex); + } + + while (element = element.parentNode) + if (element == ancestor) return true; + return false; + }, + + scrollTo: function(element) { + element = $(element); + var pos = element.cumulativeOffset(); + window.scrollTo(pos[0], pos[1]); + return element; + }, + + getStyle: function(element, style) { + element = $(element); + style = style == 'float' ? 'cssFloat' : style.camelize(); + var value = element.style[style]; + if (!value) { + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css[style] : null; + } + if (style == 'opacity') return value ? parseFloat(value) : 1.0; + return value == 'auto' ? null : value; + }, + + getOpacity: function(element) { + return $(element).getStyle('opacity'); + }, + + setStyle: function(element, styles) { + element = $(element); + var elementStyle = element.style, match; + if (Object.isString(styles)) { + element.style.cssText += ';' + styles; + return styles.include('opacity') ? + element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; + } + for (var property in styles) + if (property == 'opacity') element.setOpacity(styles[property]); + else + elementStyle[(property == 'float' || property == 'cssFloat') ? + (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') : + property] = styles[property]; + + return element; + }, + + setOpacity: function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + return element; + }, + + getDimensions: function(element) { + element = $(element); + var display = $(element).getStyle('display'); + if (display != 'none' && display != null) // Safari bug + return {width: element.offsetWidth, height: element.offsetHeight}; + + // All *Width and *Height properties give 0 on elements with display none, + // so enable the element temporarily + var els = element.style; + var originalVisibility = els.visibility; + var originalPosition = els.position; + var originalDisplay = els.display; + els.visibility = 'hidden'; + els.position = 'absolute'; + els.display = 'block'; + var originalWidth = element.clientWidth; + var originalHeight = element.clientHeight; + els.display = originalDisplay; + els.position = originalPosition; + els.visibility = originalVisibility; + return {width: originalWidth, height: originalHeight}; + }, + + makePositioned: function(element) { + element = $(element); + var pos = Element.getStyle(element, 'position'); + if (pos == 'static' || !pos) { + element._madePositioned = true; + element.style.position = 'relative'; + // Opera returns the offset relative to the positioning context, when an + // element is position relative but top and left have not been defined + if (window.opera) { + element.style.top = 0; + element.style.left = 0; + } + } + return element; + }, + + undoPositioned: function(element) { + element = $(element); + if (element._madePositioned) { + element._madePositioned = undefined; + element.style.position = + element.style.top = + element.style.left = + element.style.bottom = + element.style.right = ''; + } + return element; + }, + + makeClipping: function(element) { + element = $(element); + if (element._overflow) return element; + element._overflow = Element.getStyle(element, 'overflow') || 'auto'; + if (element._overflow !== 'hidden') + element.style.overflow = 'hidden'; + return element; + }, + + undoClipping: function(element) { + element = $(element); + if (!element._overflow) return element; + element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; + element._overflow = null; + return element; + }, + + cumulativeOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + positionedOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + if (element.tagName == 'BODY') break; + var p = Element.getStyle(element, 'position'); + if (p == 'relative' || p == 'absolute') break; + } + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + absolutize: function(element) { + element = $(element); + if (element.getStyle('position') == 'absolute') return; + // Position.prepare(); // To be done manually by Scripty when it needs it. + + var offsets = element.positionedOffset(); + var top = offsets[1]; + var left = offsets[0]; + var width = element.clientWidth; + var height = element.clientHeight; + + element._originalLeft = left - parseFloat(element.style.left || 0); + element._originalTop = top - parseFloat(element.style.top || 0); + element._originalWidth = element.style.width; + element._originalHeight = element.style.height; + + element.style.position = 'absolute'; + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.width = width + 'px'; + element.style.height = height + 'px'; + return element; + }, + + relativize: function(element) { + element = $(element); + if (element.getStyle('position') == 'relative') return; + // Position.prepare(); // To be done manually by Scripty when it needs it. + + element.style.position = 'relative'; + var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); + var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); + + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.height = element._originalHeight; + element.style.width = element._originalWidth; + return element; + }, + + cumulativeScrollOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + getOffsetParent: function(element) { + if (element.offsetParent) return $(element.offsetParent); + if (element == document.body) return $(element); + + while ((element = element.parentNode) && element != document.body) + if (Element.getStyle(element, 'position') != 'static') + return $(element); + + return $(document.body); + }, + + viewportOffset: function(forElement) { + var valueT = 0, valueL = 0; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + + // Safari fix + if (element.offsetParent == document.body && + Element.getStyle(element, 'position') == 'absolute') break; + + } while (element = element.offsetParent); + + element = forElement; + do { + if (!Prototype.Browser.Opera || element.tagName == 'BODY') { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } + } while (element = element.parentNode); + + return Element._returnOffset(valueL, valueT); + }, + + clonePosition: function(element, source) { + var options = Object.extend({ + setLeft: true, + setTop: true, + setWidth: true, + setHeight: true, + offsetTop: 0, + offsetLeft: 0 + }, arguments[2] || { }); + + // find page position of source + source = $(source); + var p = source.viewportOffset(); + + // find coordinate system to use + element = $(element); + var delta = [0, 0]; + var parent = null; + // delta [0,0] will do fine with position: fixed elements, + // position:absolute needs offsetParent deltas + if (Element.getStyle(element, 'position') == 'absolute') { + parent = element.getOffsetParent(); + delta = parent.viewportOffset(); + } + + // correct by body offsets (fixes Safari) + if (parent == document.body) { + delta[0] -= document.body.offsetLeft; + delta[1] -= document.body.offsetTop; + } + + // set position + if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; + if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; + if (options.setWidth) element.style.width = source.offsetWidth + 'px'; + if (options.setHeight) element.style.height = source.offsetHeight + 'px'; + return element; + } +}; + +Element.Methods.identify.counter = 1; + +Object.extend(Element.Methods, { + getElementsBySelector: Element.Methods.select, + childElements: Element.Methods.immediateDescendants +}); + +Element._attributeTranslations = { + write: { + names: { + className: 'class', + htmlFor: 'for' + }, + values: { } + } +}; + + +if (!document.createRange || Prototype.Browser.Opera) { + Element.Methods.insert = function(element, insertions) { + element = $(element); + + if (Object.isString(insertions) || Object.isNumber(insertions) || + Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) + insertions = { bottom: insertions }; + + var t = Element._insertionTranslations, content, position, pos, tagName; + + for (position in insertions) { + content = insertions[position]; + position = position.toLowerCase(); + pos = t[position]; + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) { + pos.insert(element, content); + continue; + } + + content = Object.toHTML(content); + tagName = ((position == 'before' || position == 'after') + ? element.parentNode : element).tagName.toUpperCase(); + + if (t.tags[tagName]) { + var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + if (position == 'top' || position == 'after') fragments.reverse(); + fragments.each(pos.insert.curry(element)); + } + else element.insertAdjacentHTML(pos.adjacency, content.stripScripts()); + + content.evalScripts.bind(content).defer(); + } + + return element; + }; +} + +if (Prototype.Browser.Opera) { + Element.Methods._getStyle = Element.Methods.getStyle; + Element.Methods.getStyle = function(element, style) { + switch(style) { + case 'left': + case 'top': + case 'right': + case 'bottom': + if (Element._getStyle(element, 'position') == 'static') return null; + default: return Element._getStyle(element, style); + } + }; + Element.Methods._readAttribute = Element.Methods.readAttribute; + Element.Methods.readAttribute = function(element, attribute) { + if (attribute == 'title') return element.title; + return Element._readAttribute(element, attribute); + }; +} + +else if (Prototype.Browser.IE) { + $w('positionedOffset getOffsetParent viewportOffset').each(function(method) { + Element.Methods[method] = Element.Methods[method].wrap( + function(proceed, element) { + element = $(element); + var position = element.getStyle('position'); + if (position != 'static') return proceed(element); + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + } + ); + }); + + Element.Methods.getStyle = function(element, style) { + element = $(element); + style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); + var value = element.style[style]; + if (!value && element.currentStyle) value = element.currentStyle[style]; + + if (style == 'opacity') { + if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) + if (value[1]) return parseFloat(value[1]) / 100; + return 1.0; + } + + if (value == 'auto') { + if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) + return element['offset' + style.capitalize()] + 'px'; + return null; + } + return value; + }; + + Element.Methods.setOpacity = function(element, value) { + function stripAlpha(filter){ + return filter.replace(/alpha\([^\)]*\)/gi,''); + } + element = $(element); + var currentStyle = element.currentStyle; + if ((currentStyle && !currentStyle.hasLayout) || + (!currentStyle && element.style.zoom == 'normal')) + element.style.zoom = 1; + + var filter = element.getStyle('filter'), style = element.style; + if (value == 1 || value === '') { + (filter = stripAlpha(filter)) ? + style.filter = filter : style.removeAttribute('filter'); + return element; + } else if (value < 0.00001) value = 0; + style.filter = stripAlpha(filter) + + 'alpha(opacity=' + (value * 100) + ')'; + return element; + }; + + Element._attributeTranslations = { + read: { + names: { + 'class': 'className', + 'for': 'htmlFor' + }, + values: { + _getAttr: function(element, attribute) { + return element.getAttribute(attribute, 2); + }, + _getAttrNode: function(element, attribute) { + var node = element.getAttributeNode(attribute); + return node ? node.value : ""; + }, + _getEv: function(element, attribute) { + var attribute = element.getAttribute(attribute); + return attribute ? attribute.toString().slice(23, -2) : null; + }, + _flag: function(element, attribute) { + return $(element).hasAttribute(attribute) ? attribute : null; + }, + style: function(element) { + return element.style.cssText.toLowerCase(); + }, + title: function(element) { + return element.title; + } + } + } + }; + + Element._attributeTranslations.write = { + names: Object.clone(Element._attributeTranslations.read.names), + values: { + checked: function(element, value) { + element.checked = !!value; + }, + + style: function(element, value) { + element.style.cssText = value ? value : ''; + } + } + }; + + Element._attributeTranslations.has = {}; + + $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + + 'encType maxLength readOnly longDesc').each(function(attr) { + Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; + Element._attributeTranslations.has[attr.toLowerCase()] = attr; + }); + + (function(v) { + Object.extend(v, { + href: v._getAttr, + src: v._getAttr, + type: v._getAttr, + action: v._getAttrNode, + disabled: v._flag, + checked: v._flag, + readonly: v._flag, + multiple: v._flag, + onload: v._getEv, + onunload: v._getEv, + onclick: v._getEv, + ondblclick: v._getEv, + onmousedown: v._getEv, + onmouseup: v._getEv, + onmouseover: v._getEv, + onmousemove: v._getEv, + onmouseout: v._getEv, + onfocus: v._getEv, + onblur: v._getEv, + onkeypress: v._getEv, + onkeydown: v._getEv, + onkeyup: v._getEv, + onsubmit: v._getEv, + onreset: v._getEv, + onselect: v._getEv, + onchange: v._getEv + }); + })(Element._attributeTranslations.read.values); +} + +else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1) ? 0.999999 : + (value === '') ? '' : (value < 0.00001) ? 0 : value; + return element; + }; +} + +else if (Prototype.Browser.WebKit) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + + if (value == 1) + if(element.tagName == 'IMG' && element.width) { + element.width++; element.width--; + } else try { + var n = document.createTextNode(' '); + element.appendChild(n); + element.removeChild(n); + } catch (e) { } + + return element; + }; + + // Safari returns margins on body which is incorrect if the child is absolutely + // positioned. For performance reasons, redefine Position.cumulativeOffset for + // KHTML/WebKit only. + Element.Methods.cumulativeOffset = function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return Element._returnOffset(valueL, valueT); + }; +} + +if (Prototype.Browser.IE || Prototype.Browser.Opera) { + // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements + Element.Methods.update = function(element, content) { + element = $(element); + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) return element.update().insert(content); + + content = Object.toHTML(content); + var tagName = element.tagName.toUpperCase(); + + if (tagName in Element._insertionTranslations.tags) { + $A(element.childNodes).each(function(node) { element.removeChild(node) }); + Element._getContentFromAnonymousElement(tagName, content.stripScripts()) + .each(function(node) { element.appendChild(node) }); + } + else element.innerHTML = content.stripScripts(); + + content.evalScripts.bind(content).defer(); + return element; + }; +} + +if (document.createElement('div').outerHTML) { + Element.Methods.replace = function(element, content) { + element = $(element); + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) { + element.parentNode.replaceChild(content, element); + return element; + } + + content = Object.toHTML(content); + var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); + + if (Element._insertionTranslations.tags[tagName]) { + var nextSibling = element.next(); + var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + parent.removeChild(element); + if (nextSibling) + fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); + else + fragments.each(function(node) { parent.appendChild(node) }); + } + else element.outerHTML = content.stripScripts(); + + content.evalScripts.bind(content).defer(); + return element; + }; +} + +Element._returnOffset = function(l, t) { + var result = [l, t]; + result.left = l; + result.top = t; + return result; +}; + +Element._getContentFromAnonymousElement = function(tagName, html) { + var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; + div.innerHTML = t[0] + html + t[1]; + t[2].times(function() { div = div.firstChild }); + return $A(div.childNodes); +}; + +Element._insertionTranslations = { + before: { + adjacency: 'beforeBegin', + insert: function(element, node) { + element.parentNode.insertBefore(node, element); + }, + initializeRange: function(element, range) { + range.setStartBefore(element); + } + }, + top: { + adjacency: 'afterBegin', + insert: function(element, node) { + element.insertBefore(node, element.firstChild); + }, + initializeRange: function(element, range) { + range.selectNodeContents(element); + range.collapse(true); + } + }, + bottom: { + adjacency: 'beforeEnd', + insert: function(element, node) { + element.appendChild(node); + } + }, + after: { + adjacency: 'afterEnd', + insert: function(element, node) { + element.parentNode.insertBefore(node, element.nextSibling); + }, + initializeRange: function(element, range) { + range.setStartAfter(element); + } + }, + tags: { + TABLE: ['', '
    ', 1], + TBODY: ['', '
    ', 2], + TR: ['', '
    ', 3], + TD: ['
    ', '
    ', 4], + SELECT: ['', 1] + } +}; + +(function() { + this.bottom.initializeRange = this.top.initializeRange; + Object.extend(this.tags, { + THEAD: this.tags.TBODY, + TFOOT: this.tags.TBODY, + TH: this.tags.TD + }); +}).call(Element._insertionTranslations); + +Element.Methods.Simulated = { + hasAttribute: function(element, attribute) { + attribute = Element._attributeTranslations.has[attribute] || attribute; + var node = $(element).getAttributeNode(attribute); + return node && node.specified; + } +}; + +Element.Methods.ByTag = { }; + +Object.extend(Element, Element.Methods); + +if (!Prototype.BrowserFeatures.ElementExtensions && + document.createElement('div').__proto__) { + window.HTMLElement = { }; + window.HTMLElement.prototype = document.createElement('div').__proto__; + Prototype.BrowserFeatures.ElementExtensions = true; +} + +Element.extend = (function() { + if (Prototype.BrowserFeatures.SpecificElementExtensions) + return Prototype.K; + + var Methods = { }, ByTag = Element.Methods.ByTag; + + var extend = Object.extend(function(element) { + if (!element || element._extendedByPrototype || + element.nodeType != 1 || element == window) return element; + + var methods = Object.clone(Methods), + tagName = element.tagName, property, value; + + // extend methods for specific tags + if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); + + for (property in methods) { + value = methods[property]; + if (Object.isFunction(value) && !(property in element)) + element[property] = value.methodize(); + } + + element._extendedByPrototype = Prototype.emptyFunction; + return element; + + }, { + refresh: function() { + // extend methods for all tags (Safari doesn't need this) + if (!Prototype.BrowserFeatures.ElementExtensions) { + Object.extend(Methods, Element.Methods); + Object.extend(Methods, Element.Methods.Simulated); + } + } + }); + + extend.refresh(); + return extend; +})(); + +Element.hasAttribute = function(element, attribute) { + if (element.hasAttribute) return element.hasAttribute(attribute); + return Element.Methods.Simulated.hasAttribute(element, attribute); +}; + +Element.addMethods = function(methods) { + var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; + + if (!methods) { + Object.extend(Form, Form.Methods); + Object.extend(Form.Element, Form.Element.Methods); + Object.extend(Element.Methods.ByTag, { + "FORM": Object.clone(Form.Methods), + "INPUT": Object.clone(Form.Element.Methods), + "SELECT": Object.clone(Form.Element.Methods), + "TEXTAREA": Object.clone(Form.Element.Methods) + }); + } + + if (arguments.length == 2) { + var tagName = methods; + methods = arguments[1]; + } + + if (!tagName) Object.extend(Element.Methods, methods || { }); + else { + if (Object.isArray(tagName)) tagName.each(extend); + else extend(tagName); + } + + function extend(tagName) { + tagName = tagName.toUpperCase(); + if (!Element.Methods.ByTag[tagName]) + Element.Methods.ByTag[tagName] = { }; + Object.extend(Element.Methods.ByTag[tagName], methods); + } + + function copy(methods, destination, onlyIfAbsent) { + onlyIfAbsent = onlyIfAbsent || false; + for (var property in methods) { + var value = methods[property]; + if (!Object.isFunction(value)) continue; + if (!onlyIfAbsent || !(property in destination)) + destination[property] = value.methodize(); + } + } + + function findDOMClass(tagName) { + var klass; + var trans = { + "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", + "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", + "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", + "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", + "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": + "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": + "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": + "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": + "FrameSet", "IFRAME": "IFrame" + }; + if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName.capitalize() + 'Element'; + if (window[klass]) return window[klass]; + + window[klass] = { }; + window[klass].prototype = document.createElement(tagName).__proto__; + return window[klass]; + } + + if (F.ElementExtensions) { + copy(Element.Methods, HTMLElement.prototype); + copy(Element.Methods.Simulated, HTMLElement.prototype, true); + } + + if (F.SpecificElementExtensions) { + for (var tag in Element.Methods.ByTag) { + var klass = findDOMClass(tag); + if (Object.isUndefined(klass)) continue; + copy(T[tag], klass.prototype); + } + } + + Object.extend(Element, Element.Methods); + delete Element.ByTag; + + if (Element.extend.refresh) Element.extend.refresh(); + Element.cache = { }; +}; + +document.viewport = { + getDimensions: function() { + var dimensions = { }; + $w('width height').each(function(d) { + var D = d.capitalize(); + dimensions[d] = self['inner' + D] || + (document.documentElement['client' + D] || document.body['client' + D]); + }); + return dimensions; + }, + + getWidth: function() { + return this.getDimensions().width; + }, + + getHeight: function() { + return this.getDimensions().height; + }, + + getScrollOffsets: function() { + return Element._returnOffset( + window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, + window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); + } +}; +/* Portions of the Selector class are derived from Jack Slocum’s DomQuery, + * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style + * license. Please see http://www.yui-ext.com/ for more information. */ + +var Selector = Class.create({ + initialize: function(expression) { + this.expression = expression.strip(); + this.compileMatcher(); + }, + + compileMatcher: function() { + // Selectors with namespaced attributes can't use the XPath version + if (Prototype.BrowserFeatures.XPath && !(/(\[[\w-]*?:|:checked)/).test(this.expression)) + return this.compileXPathMatcher(); + + var e = this.expression, ps = Selector.patterns, h = Selector.handlers, + c = Selector.criteria, le, p, m; + + if (Selector._cache[e]) { + this.matcher = Selector._cache[e]; + return; + } + + this.matcher = ["this.matcher = function(root) {", + "var r = root, h = Selector.handlers, c = false, n;"]; + + while (e && le != e && (/\S/).test(e)) { + le = e; + for (var i in ps) { + p = ps[i]; + if (m = e.match(p)) { + this.matcher.push(Object.isFunction(c[i]) ? c[i](m) : + new Template(c[i]).evaluate(m)); + e = e.replace(m[0], ''); + break; + } + } + } + + this.matcher.push("return h.unique(n);\n}"); + eval(this.matcher.join('\n')); + Selector._cache[this.expression] = this.matcher; + }, + + compileXPathMatcher: function() { + var e = this.expression, ps = Selector.patterns, + x = Selector.xpath, le, m; + + if (Selector._cache[e]) { + this.xpath = Selector._cache[e]; return; + } + + this.matcher = ['.//*']; + while (e && le != e && (/\S/).test(e)) { + le = e; + for (var i in ps) { + if (m = e.match(ps[i])) { + this.matcher.push(Object.isFunction(x[i]) ? x[i](m) : + new Template(x[i]).evaluate(m)); + e = e.replace(m[0], ''); + break; + } + } + } + + this.xpath = this.matcher.join(''); + Selector._cache[this.expression] = this.xpath; + }, + + findElements: function(root) { + root = root || document; + if (this.xpath) return document._getElementsByXPath(this.xpath, root); + return this.matcher(root); + }, + + match: function(element) { + this.tokens = []; + + var e = this.expression, ps = Selector.patterns, as = Selector.assertions; + var le, p, m; + + while (e && le !== e && (/\S/).test(e)) { + le = e; + for (var i in ps) { + p = ps[i]; + if (m = e.match(p)) { + // use the Selector.assertions methods unless the selector + // is too complex. + if (as[i]) { + this.tokens.push([i, Object.clone(m)]); + e = e.replace(m[0], ''); + } else { + // reluctantly do a document-wide search + // and look for a match in the array + return this.findElements(document).include(element); + } + } + } + } + + var match = true, name, matches; + for (var i = 0, token; token = this.tokens[i]; i++) { + name = token[0], matches = token[1]; + if (!Selector.assertions[name](element, matches)) { + match = false; break; + } + } + + return match; + }, + + toString: function() { + return this.expression; + }, + + inspect: function() { + return "#"; + } +}); + +Object.extend(Selector, { + _cache: { }, + + xpath: { + descendant: "//*", + child: "/*", + adjacent: "/following-sibling::*[1]", + laterSibling: '/following-sibling::*', + tagName: function(m) { + if (m[1] == '*') return ''; + return "[local-name()='" + m[1].toLowerCase() + + "' or local-name()='" + m[1].toUpperCase() + "']"; + }, + className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", + id: "[@id='#{1}']", + attrPresence: "[@#{1}]", + attr: function(m) { + m[3] = m[5] || m[6]; + return new Template(Selector.xpath.operators[m[2]]).evaluate(m); + }, + pseudo: function(m) { + var h = Selector.xpath.pseudos[m[1]]; + if (!h) return ''; + if (Object.isFunction(h)) return h(m); + return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); + }, + operators: { + '=': "[@#{1}='#{3}']", + '!=': "[@#{1}!='#{3}']", + '^=': "[starts-with(@#{1}, '#{3}')]", + '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", + '*=': "[contains(@#{1}, '#{3}')]", + '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", + '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" + }, + pseudos: { + 'first-child': '[not(preceding-sibling::*)]', + 'last-child': '[not(following-sibling::*)]', + 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', + 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]", + 'checked': "[@checked]", + 'disabled': "[@disabled]", + 'enabled': "[not(@disabled)]", + 'not': function(m) { + var e = m[6], p = Selector.patterns, + x = Selector.xpath, le, m, v; + + var exclusion = []; + while (e && le != e && (/\S/).test(e)) { + le = e; + for (var i in p) { + if (m = e.match(p[i])) { + v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m); + exclusion.push("(" + v.substring(1, v.length - 1) + ")"); + e = e.replace(m[0], ''); + break; + } + } + } + return "[not(" + exclusion.join(" and ") + ")]"; + }, + 'nth-child': function(m) { + return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); + }, + 'nth-last-child': function(m) { + return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m); + }, + 'nth-of-type': function(m) { + return Selector.xpath.pseudos.nth("position() ", m); + }, + 'nth-last-of-type': function(m) { + return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m); + }, + 'first-of-type': function(m) { + m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); + }, + 'last-of-type': function(m) { + m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); + }, + 'only-of-type': function(m) { + var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m); + }, + nth: function(fragment, m) { + var mm, formula = m[6], predicate; + if (formula == 'even') formula = '2n+0'; + if (formula == 'odd') formula = '2n+1'; + if (mm = formula.match(/^(\d+)$/)) // digit only + return '[' + fragment + "= " + mm[1] + ']'; + if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b + if (mm[1] == "-") mm[1] = -1; + var a = mm[1] ? Number(mm[1]) : 1; + var b = mm[2] ? Number(mm[2]) : 0; + predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " + + "((#{fragment} - #{b}) div #{a} >= 0)]"; + return new Template(predicate).evaluate({ + fragment: fragment, a: a, b: b }); + } + } + } + }, + + criteria: { + tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', + className: 'n = h.className(n, r, "#{1}", c); c = false;', + id: 'n = h.id(n, r, "#{1}", c); c = false;', + attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;', + attr: function(m) { + m[3] = (m[5] || m[6]); + return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m); + }, + pseudo: function(m) { + if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); + return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); + }, + descendant: 'c = "descendant";', + child: 'c = "child";', + adjacent: 'c = "adjacent";', + laterSibling: 'c = "laterSibling";' + }, + + patterns: { + // combinators must be listed first + // (and descendant needs to be last combinator) + laterSibling: /^\s*~\s*/, + child: /^\s*>\s*/, + adjacent: /^\s*\+\s*/, + descendant: /^\s/, + + // selectors follow + tagName: /^\s*(\*|[\w\-]+)(\b|$)?/, + id: /^#([\w\-\*]+)(\b|$)/, + className: /^\.([\w\-\*]+)(\b|$)/, + pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s)|(?=:))/, + attrPresence: /^\[([\w]+)\]/, + attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ + }, + + // for Selector.match and Element#match + assertions: { + tagName: function(element, matches) { + return matches[1].toUpperCase() == element.tagName.toUpperCase(); + }, + + className: function(element, matches) { + return Element.hasClassName(element, matches[1]); + }, + + id: function(element, matches) { + return element.id === matches[1]; + }, + + attrPresence: function(element, matches) { + return Element.hasAttribute(element, matches[1]); + }, + + attr: function(element, matches) { + var nodeValue = Element.readAttribute(element, matches[1]); + return Selector.operators[matches[2]](nodeValue, matches[3]); + } + }, + + handlers: { + // UTILITY FUNCTIONS + // joins two collections + concat: function(a, b) { + for (var i = 0, node; node = b[i]; i++) + a.push(node); + return a; + }, + + // marks an array of nodes for counting + mark: function(nodes) { + for (var i = 0, node; node = nodes[i]; i++) + node._counted = true; + return nodes; + }, + + unmark: function(nodes) { + for (var i = 0, node; node = nodes[i]; i++) + node._counted = undefined; + return nodes; + }, + + // mark each child node with its position (for nth calls) + // "ofType" flag indicates whether we're indexing for nth-of-type + // rather than nth-child + index: function(parentNode, reverse, ofType) { + parentNode._counted = true; + if (reverse) { + for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { + var node = nodes[i]; + if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++; + } + } else { + for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) + if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++; + } + }, + + // filters out duplicates and extends all nodes + unique: function(nodes) { + if (nodes.length == 0) return nodes; + var results = [], n; + for (var i = 0, l = nodes.length; i < l; i++) + if (!(n = nodes[i])._counted) { + n._counted = true; + results.push(Element.extend(n)); + } + return Selector.handlers.unmark(results); + }, + + // COMBINATOR FUNCTIONS + descendant: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + h.concat(results, node.getElementsByTagName('*')); + return results; + }, + + child: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) { + for (var j = 0, children = [], child; child = node.childNodes[j]; j++) + if (child.nodeType == 1 && child.tagName != '!') results.push(child); + } + return results; + }, + + adjacent: function(nodes) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + var next = this.nextElementSibling(node); + if (next) results.push(next); + } + return results; + }, + + laterSibling: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + h.concat(results, Element.nextSiblings(node)); + return results; + }, + + nextElementSibling: function(node) { + while (node = node.nextSibling) + if (node.nodeType == 1) return node; + return null; + }, + + previousElementSibling: function(node) { + while (node = node.previousSibling) + if (node.nodeType == 1) return node; + return null; + }, + + // TOKEN FUNCTIONS + tagName: function(nodes, root, tagName, combinator) { + tagName = tagName.toUpperCase(); + var results = [], h = Selector.handlers; + if (nodes) { + if (combinator) { + // fastlane for ordinary descendant combinators + if (combinator == "descendant") { + for (var i = 0, node; node = nodes[i]; i++) + h.concat(results, node.getElementsByTagName(tagName)); + return results; + } else nodes = this[combinator](nodes); + if (tagName == "*") return nodes; + } + for (var i = 0, node; node = nodes[i]; i++) + if (node.tagName.toUpperCase() == tagName) results.push(node); + return results; + } else return root.getElementsByTagName(tagName); + }, + + id: function(nodes, root, id, combinator) { + var targetNode = $(id), h = Selector.handlers; + if (!targetNode) return []; + if (!nodes && root == document) return [targetNode]; + if (nodes) { + if (combinator) { + if (combinator == 'child') { + for (var i = 0, node; node = nodes[i]; i++) + if (targetNode.parentNode == node) return [targetNode]; + } else if (combinator == 'descendant') { + for (var i = 0, node; node = nodes[i]; i++) + if (Element.descendantOf(targetNode, node)) return [targetNode]; + } else if (combinator == 'adjacent') { + for (var i = 0, node; node = nodes[i]; i++) + if (Selector.handlers.previousElementSibling(targetNode) == node) + return [targetNode]; + } else nodes = h[combinator](nodes); + } + for (var i = 0, node; node = nodes[i]; i++) + if (node == targetNode) return [targetNode]; + return []; + } + return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; + }, + + className: function(nodes, root, className, combinator) { + if (nodes && combinator) nodes = this[combinator](nodes); + return Selector.handlers.byClassName(nodes, root, className); + }, + + byClassName: function(nodes, root, className) { + if (!nodes) nodes = Selector.handlers.descendant([root]); + var needle = ' ' + className + ' '; + for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { + nodeClassName = node.className; + if (nodeClassName.length == 0) continue; + if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) + results.push(node); + } + return results; + }, + + attrPresence: function(nodes, root, attr) { + if (!nodes) nodes = root.getElementsByTagName("*"); + var results = []; + for (var i = 0, node; node = nodes[i]; i++) + if (Element.hasAttribute(node, attr)) results.push(node); + return results; + }, + + attr: function(nodes, root, attr, value, operator) { + if (!nodes) nodes = root.getElementsByTagName("*"); + var handler = Selector.operators[operator], results = []; + for (var i = 0, node; node = nodes[i]; i++) { + var nodeValue = Element.readAttribute(node, attr); + if (nodeValue === null) continue; + if (handler(nodeValue, value)) results.push(node); + } + return results; + }, + + pseudo: function(nodes, name, value, root, combinator) { + if (nodes && combinator) nodes = this[combinator](nodes); + if (!nodes) nodes = root.getElementsByTagName("*"); + return Selector.pseudos[name](nodes, value, root); + } + }, + + pseudos: { + 'first-child': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + if (Selector.handlers.previousElementSibling(node)) continue; + results.push(node); + } + return results; + }, + 'last-child': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + if (Selector.handlers.nextElementSibling(node)) continue; + results.push(node); + } + return results; + }, + 'only-child': function(nodes, value, root) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) + results.push(node); + return results; + }, + 'nth-child': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root); + }, + 'nth-last-child': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, true); + }, + 'nth-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, false, true); + }, + 'nth-last-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, true, true); + }, + 'first-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, "1", root, false, true); + }, + 'last-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, "1", root, true, true); + }, + 'only-of-type': function(nodes, formula, root) { + var p = Selector.pseudos; + return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); + }, + + // handles the an+b logic + getIndices: function(a, b, total) { + if (a == 0) return b > 0 ? [b] : []; + return $R(1, total).inject([], function(memo, i) { + if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); + return memo; + }); + }, + + // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type + nth: function(nodes, formula, root, reverse, ofType) { + if (nodes.length == 0) return []; + if (formula == 'even') formula = '2n+0'; + if (formula == 'odd') formula = '2n+1'; + var h = Selector.handlers, results = [], indexed = [], m; + h.mark(nodes); + for (var i = 0, node; node = nodes[i]; i++) { + if (!node.parentNode._counted) { + h.index(node.parentNode, reverse, ofType); + indexed.push(node.parentNode); + } + } + if (formula.match(/^\d+$/)) { // just a number + formula = Number(formula); + for (var i = 0, node; node = nodes[i]; i++) + if (node.nodeIndex == formula) results.push(node); + } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b + if (m[1] == "-") m[1] = -1; + var a = m[1] ? Number(m[1]) : 1; + var b = m[2] ? Number(m[2]) : 0; + var indices = Selector.pseudos.getIndices(a, b, nodes.length); + for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { + for (var j = 0; j < l; j++) + if (node.nodeIndex == indices[j]) results.push(node); + } + } + h.unmark(nodes); + h.unmark(indexed); + return results; + }, + + 'empty': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + // IE treats comments as element nodes + if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue; + results.push(node); + } + return results; + }, + + 'not': function(nodes, selector, root) { + var h = Selector.handlers, selectorType, m; + var exclusions = new Selector(selector).findElements(root); + h.mark(exclusions); + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!node._counted) results.push(node); + h.unmark(exclusions); + return results; + }, + + 'enabled': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!node.disabled) results.push(node); + return results; + }, + + 'disabled': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (node.disabled) results.push(node); + return results; + }, + + 'checked': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (node.checked) results.push(node); + return results; + } + }, + + operators: { + '=': function(nv, v) { return nv == v; }, + '!=': function(nv, v) { return nv != v; }, + '^=': function(nv, v) { return nv.startsWith(v); }, + '$=': function(nv, v) { return nv.endsWith(v); }, + '*=': function(nv, v) { return nv.include(v); }, + '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, + '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); } + }, + + matchElements: function(elements, expression) { + var matches = new Selector(expression).findElements(), h = Selector.handlers; + h.mark(matches); + for (var i = 0, results = [], element; element = elements[i]; i++) + if (element._counted) results.push(element); + h.unmark(matches); + return results; + }, + + findElement: function(elements, expression, index) { + if (Object.isNumber(expression)) { + index = expression; expression = false; + } + return Selector.matchElements(elements, expression || '*')[index || 0]; + }, + + findChildElements: function(element, expressions) { + var exprs = expressions.join(','), expressions = []; + exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { + expressions.push(m[1].strip()); + }); + var results = [], h = Selector.handlers; + for (var i = 0, l = expressions.length, selector; i < l; i++) { + selector = new Selector(expressions[i].strip()); + h.concat(results, selector.findElements(element)); + } + return (l > 1) ? h.unique(results) : results; + } +}); + +function $$() { + return Selector.findChildElements(document, $A(arguments)); +} +var Form = { + reset: function(form) { + $(form).reset(); + return form; + }, + + serializeElements: function(elements, options) { + if (typeof options != 'object') options = { hash: !!options }; + else if (options.hash === undefined) options.hash = true; + var key, value, submitted = false, submit = options.submit; + + var data = elements.inject({ }, function(result, element) { + if (!element.disabled && element.name) { + key = element.name; value = $(element).getValue(); + if (value != null && (element.type != 'submit' || (!submitted && + submit !== false && (!submit || key == submit) && (submitted = true)))) { + if (key in result) { + // a key is already present; construct an array of values + if (!Object.isArray(result[key])) result[key] = [result[key]]; + result[key].push(value); + } + else result[key] = value; + } + } + return result; + }); + + return options.hash ? data : Object.toQueryString(data); + } +}; + +Form.Methods = { + serialize: function(form, options) { + return Form.serializeElements(Form.getElements(form), options); + }, + + getElements: function(form) { + return $A($(form).getElementsByTagName('*')).inject([], + function(elements, child) { + if (Form.Element.Serializers[child.tagName.toLowerCase()]) + elements.push(Element.extend(child)); + return elements; + } + ); + }, + + getInputs: function(form, typeName, name) { + form = $(form); + var inputs = form.getElementsByTagName('input'); + + if (!typeName && !name) return $A(inputs).map(Element.extend); + + for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { + var input = inputs[i]; + if ((typeName && input.type != typeName) || (name && input.name != name)) + continue; + matchingInputs.push(Element.extend(input)); + } + + return matchingInputs; + }, + + disable: function(form) { + form = $(form); + Form.getElements(form).invoke('disable'); + return form; + }, + + enable: function(form) { + form = $(form); + Form.getElements(form).invoke('enable'); + return form; + }, + + findFirstElement: function(form) { + var elements = $(form).getElements().findAll(function(element) { + return 'hidden' != element.type && !element.disabled; + }); + var firstByIndex = elements.findAll(function(element) { + return element.hasAttribute('tabIndex') && element.tabIndex >= 0; + }).sortBy(function(element) { return element.tabIndex }).first(); + + return firstByIndex ? firstByIndex : elements.find(function(element) { + return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); + }); + }, + + focusFirstElement: function(form) { + form = $(form); + form.findFirstElement().activate(); + return form; + }, + + request: function(form, options) { + form = $(form), options = Object.clone(options || { }); + + var params = options.parameters, action = form.readAttribute('action') || ''; + if (action.blank()) action = window.location.href; + options.parameters = form.serialize(true); + + if (params) { + if (Object.isString(params)) params = params.toQueryParams(); + Object.extend(options.parameters, params); + } + + if (form.hasAttribute('method') && !options.method) + options.method = form.method; + + return new Ajax.Request(action, options); + } +}; + +/*--------------------------------------------------------------------------*/ + +Form.Element = { + focus: function(element) { + $(element).focus(); + return element; + }, + + select: function(element) { + $(element).select(); + return element; + } +}; + +Form.Element.Methods = { + serialize: function(element) { + element = $(element); + if (!element.disabled && element.name) { + var value = element.getValue(); + if (value != undefined) { + var pair = { }; + pair[element.name] = value; + return Object.toQueryString(pair); + } + } + return ''; + }, + + getValue: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + return Form.Element.Serializers[method](element); + }, + + setValue: function(element, value) { + element = $(element); + var method = element.tagName.toLowerCase(); + Form.Element.Serializers[method](element, value); + return element; + }, + + clear: function(element) { + $(element).value = ''; + return element; + }, + + present: function(element) { + return $(element).value != ''; + }, + + activate: function(element) { + element = $(element); + try { + element.focus(); + if (element.select && (element.tagName.toLowerCase() != 'input' || + !['button', 'reset', 'submit'].include(element.type))) + element.select(); + } catch (e) { } + return element; + }, + + disable: function(element) { + element = $(element); + element.blur(); + element.disabled = true; + return element; + }, + + enable: function(element) { + element = $(element); + element.disabled = false; + return element; + } +}; + +/*--------------------------------------------------------------------------*/ + +var Field = Form.Element; +var $F = Form.Element.Methods.getValue; + +/*--------------------------------------------------------------------------*/ + +Form.Element.Serializers = { + input: function(element, value) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + return Form.Element.Serializers.inputSelector(element, value); + default: + return Form.Element.Serializers.textarea(element, value); + } + }, + + inputSelector: function(element, value) { + if (value === undefined) return element.checked ? element.value : null; + else element.checked = !!value; + }, + + textarea: function(element, value) { + if (value === undefined) return element.value; + else element.value = value; + }, + + select: function(element, index) { + if (index === undefined) + return this[element.type == 'select-one' ? + 'selectOne' : 'selectMany'](element); + else { + var opt, value, single = !Object.isArray(index); + for (var i = 0, length = element.length; i < length; i++) { + opt = element.options[i]; + value = this.optionValue(opt); + if (single) { + if (value == index) { + opt.selected = true; + return; + } + } + else opt.selected = index.include(value); + } + } + }, + + selectOne: function(element) { + var index = element.selectedIndex; + return index >= 0 ? this.optionValue(element.options[index]) : null; + }, + + selectMany: function(element) { + var values, length = element.length; + if (!length) return null; + + for (var i = 0, values = []; i < length; i++) { + var opt = element.options[i]; + if (opt.selected) values.push(this.optionValue(opt)); + } + return values; + }, + + optionValue: function(opt) { + // extend element because hasAttribute may not be native + return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; + } +}; + +/*--------------------------------------------------------------------------*/ + +Abstract.TimedObserver = Class.create(PeriodicalExecuter, { + initialize: function($super, element, frequency, callback) { + $super(callback, frequency); + this.element = $(element); + this.lastValue = this.getValue(); + }, + + execute: function() { + var value = this.getValue(); + if (Object.isString(this.lastValue) && Object.isString(value) ? + this.lastValue != value : String(this.lastValue) != String(value)) { + this.callback(this.element, value); + this.lastValue = value; + } + } +}); + +Form.Element.Observer = Class.create(Abstract.TimedObserver, { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.Observer = Class.create(Abstract.TimedObserver, { + getValue: function() { + return Form.serialize(this.element); + } +}); + +/*--------------------------------------------------------------------------*/ + +Abstract.EventObserver = Class.create({ + initialize: function(element, callback) { + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + if (this.element.tagName.toLowerCase() == 'form') + this.registerFormCallbacks(); + else + this.registerCallback(this.element); + }, + + onElementEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + }, + + registerFormCallbacks: function() { + Form.getElements(this.element).each(this.registerCallback, this); + }, + + registerCallback: function(element) { + if (element.type) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + Event.observe(element, 'click', this.onElementEvent.bind(this)); + break; + default: + Event.observe(element, 'change', this.onElementEvent.bind(this)); + break; + } + } + } +}); + +Form.Element.EventObserver = Class.create(Abstract.EventObserver, { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.EventObserver = Class.create(Abstract.EventObserver, { + getValue: function() { + return Form.serialize(this.element); + } +}); +if (!window.Event) var Event = { }; + +Object.extend(Event, { + KEY_BACKSPACE: 8, + KEY_TAB: 9, + KEY_RETURN: 13, + KEY_ESC: 27, + KEY_LEFT: 37, + KEY_UP: 38, + KEY_RIGHT: 39, + KEY_DOWN: 40, + KEY_DELETE: 46, + KEY_HOME: 36, + KEY_END: 35, + KEY_PAGEUP: 33, + KEY_PAGEDOWN: 34, + KEY_INSERT: 45, + + cache: { }, + + relatedTarget: function(event) { + var element; + switch(event.type) { + case 'mouseover': element = event.fromElement; break; + case 'mouseout': element = event.toElement; break; + default: return null; + } + return Element.extend(element); + } +}); + +Event.Methods = (function() { + var isButton; + + if (Prototype.Browser.IE) { + var buttonMap = { 0: 1, 1: 4, 2: 2 }; + isButton = function(event, code) { + return event.button == buttonMap[code]; + }; + + } else if (Prototype.Browser.WebKit) { + isButton = function(event, code) { + switch (code) { + case 0: return event.which == 1 && !event.metaKey; + case 1: return event.which == 1 && event.metaKey; + default: return false; + } + }; + + } else { + isButton = function(event, code) { + return event.which ? (event.which === code + 1) : (event.button === code); + }; + } + + return { + isLeftClick: function(event) { return isButton(event, 0) }, + isMiddleClick: function(event) { return isButton(event, 1) }, + isRightClick: function(event) { return isButton(event, 2) }, + + element: function(event) { + var node = Event.extend(event).target; + return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node); + }, + + findElement: function(event, expression) { + var element = Event.element(event); + return element.match(expression) ? element : element.up(expression); + }, + + pointer: function(event) { + return { + x: event.pageX || (event.clientX + + (document.documentElement.scrollLeft || document.body.scrollLeft)), + y: event.pageY || (event.clientY + + (document.documentElement.scrollTop || document.body.scrollTop)) + }; + }, + + pointerX: function(event) { return Event.pointer(event).x }, + pointerY: function(event) { return Event.pointer(event).y }, + + stop: function(event) { + Event.extend(event); + event.preventDefault(); + event.stopPropagation(); + event.stopped = true; + } + }; +})(); + +Event.extend = (function() { + var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { + m[name] = Event.Methods[name].methodize(); + return m; + }); + + if (Prototype.Browser.IE) { + Object.extend(methods, { + stopPropagation: function() { this.cancelBubble = true }, + preventDefault: function() { this.returnValue = false }, + inspect: function() { return "[object Event]" } + }); + + return function(event) { + if (!event) return false; + if (event._extendedByPrototype) return event; + + event._extendedByPrototype = Prototype.emptyFunction; + var pointer = Event.pointer(event); + Object.extend(event, { + target: event.srcElement, + relatedTarget: Event.relatedTarget(event), + pageX: pointer.x, + pageY: pointer.y + }); + return Object.extend(event, methods); + }; + + } else { + Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__; + Object.extend(Event.prototype, methods); + return Prototype.K; + } +})(); + +Object.extend(Event, (function() { + var cache = Event.cache; + + function getEventID(element) { + if (element._eventID) return element._eventID; + arguments.callee.id = arguments.callee.id || 1; + return element._eventID = ++arguments.callee.id; + } + + function getDOMEventName(eventName) { + if (eventName && eventName.include(':')) return "dataavailable"; + return eventName; + } + + function getCacheForID(id) { + return cache[id] = cache[id] || { }; + } + + function getWrappersForEventName(id, eventName) { + var c = getCacheForID(id); + return c[eventName] = c[eventName] || []; + } + + function createWrapper(element, eventName, handler) { + var id = getEventID(element); + var c = getWrappersForEventName(id, eventName); + if (c.pluck("handler").include(handler)) return false; + + var wrapper = function(event) { + if (!Event || !Event.extend || + (event.eventName && event.eventName != eventName)) + return false; + + Event.extend(event); + handler.call(element, event) + }; + + wrapper.handler = handler; + c.push(wrapper); + return wrapper; + } + + function findWrapper(id, eventName, handler) { + var c = getWrappersForEventName(id, eventName); + return c.find(function(wrapper) { return wrapper.handler == handler }); + } + + function destroyWrapper(id, eventName, handler) { + var c = getCacheForID(id); + if (!c[eventName]) return false; + c[eventName] = c[eventName].without(findWrapper(id, eventName, handler)); + } + + function destroyCache() { + for (var id in cache) + for (var eventName in cache[id]) + cache[id][eventName] = null; + } + + if (window.attachEvent) { + window.attachEvent("onunload", destroyCache); + } + + return { + observe: function(element, eventName, handler) { + element = $(element); + var name = getDOMEventName(eventName); + + var wrapper = createWrapper(element, eventName, handler); + if (!wrapper) return element; + + if (element.addEventListener) { + element.addEventListener(name, wrapper, false); + } else { + element.attachEvent("on" + name, wrapper); + } + + return element; + }, + + stopObserving: function(element, eventName, handler) { + element = $(element); + var id = getEventID(element), name = getDOMEventName(eventName); + + if (!handler && eventName) { + getWrappersForEventName(id, eventName).each(function(wrapper) { + element.stopObserving(eventName, wrapper.handler); + }); + return element; + + } else if (!eventName) { + Object.keys(getCacheForID(id)).each(function(eventName) { + element.stopObserving(eventName); + }); + return element; + } + + var wrapper = findWrapper(id, eventName, handler); + if (!wrapper) return element; + + if (element.removeEventListener) { + element.removeEventListener(name, wrapper, false); + } else { + element.detachEvent("on" + name, wrapper); + } + + destroyWrapper(id, eventName, handler); + + return element; + }, + + fire: function(element, eventName, memo) { + element = $(element); + if (element == document && document.createEvent && !element.dispatchEvent) + element = document.documentElement; + + if (document.createEvent) { + var event = document.createEvent("HTMLEvents"); + event.initEvent("dataavailable", true, true); + } else { + var event = document.createEventObject(); + event.eventType = "ondataavailable"; + } + + event.eventName = eventName; + event.memo = memo || { }; + + if (document.createEvent) { + element.dispatchEvent(event); + } else { + element.fireEvent(event.eventType, event); + } + + return event; + } + }; +})()); + +Object.extend(Event, Event.Methods); + +Element.addMethods({ + fire: Event.fire, + observe: Event.observe, + stopObserving: Event.stopObserving +}); + +Object.extend(document, { + fire: Element.Methods.fire.methodize(), + observe: Element.Methods.observe.methodize(), + stopObserving: Element.Methods.stopObserving.methodize() +}); + +(function() { + /* Support for the DOMContentLoaded event is based on work by Dan Webb, + Matthias Miller, Dean Edwards and John Resig. */ + + var timer, fired = false; + + function fireContentLoadedEvent() { + if (fired) return; + if (timer) window.clearInterval(timer); + document.fire("dom:loaded"); + fired = true; + } + + if (document.addEventListener) { + if (Prototype.Browser.WebKit) { + timer = window.setInterval(function() { + if (/loaded|complete/.test(document.readyState)) + fireContentLoadedEvent(); + }, 0); + + Event.observe(window, "load", fireContentLoadedEvent); + + } else { + document.addEventListener("DOMContentLoaded", + fireContentLoadedEvent, false); + } + + } else { + document.write("") +}; +xq.loadOthers=function(){var A=xq.findXquaredScript(); +var C=A.src.match(/(.*\/)xquared\.js.*/i)[1]; +var B=["Editor.js","Browser.js","Shortcut.js","DomTree.js","RichDom.js","RichDomW3.js","RichDomGecko.js","RichDomWebkit.js","RichDomTrident.js","RichTable.js","Validator.js","ValidatorW3.js","ValidatorGecko.js","ValidatorWebkit.js","ValidatorTrident.js","EditHistory.js","Controls.js","_ui_templates.js"]; +B.each(function(D){xq.loadScript(C+D) +}) +}; +if(xq.shouldLoadOthers()){xq.loadOthers() +}xq.Editor=Class.create({initialize:function(B,A){if(!B){throw"[contentElement] is null" +}if(B.nodeType!=1){throw"[contentElement] is not an element" +}xq.asEventSource(this,"Editor",["ElementChanged","BeforeEvent","AfterEvent","CurrentContentChanged","StaticContentChanged","CurrentEditModeChanged"]); +this.config={}; +this.config.enableLinkClick=false; +this.config.changeCursorOnLink=false; +this.config.generateDefaultToolbar=true; +this.config.defaultToolbarButtonMap=[[{className:"foregroundColor",title:"Foreground color",handler:"xed.handleForegroundColor()"},{className:"backgroundColor",title:"Background color",handler:"xed.handleBackgroundColor()"}],[{className:"link",title:"Link",handler:"xed.handleLink()"},{className:"strongEmphasis",title:"Strong emphasis",handler:"xed.handleStrongEmphasis()"},{className:"emphasis",title:"Emphasis",handler:"xed.handleEmphasis()"},{className:"underline",title:"Underline",handler:"xed.handleUnderline()"},{className:"strike",title:"Strike",handler:"xed.handleStrike()"},{className:"superscription",title:"Superscription",handler:"xed.handleSuperscription()"},{className:"subscription",title:"Subscription",handler:"xed.handleSubscription()"}],[{className:"removeFormat",title:"Remove format",handler:"xed.handleRemoveFormat()"}],[{className:"justifyLeft",title:"Justify left",handler:"xed.handleJustify('left')"},{className:"justifyCenter",title:"Justify center",handler:"xed.handleJustify('center')"},{className:"justifyRight",title:"Justify right",handler:"xed.handleJustify('right')"},{className:"justifyBoth",title:"Justify both",handler:"xed.handleJustify('both')"}],[{className:"indent",title:"Indent",handler:"xed.handleIndent()"},{className:"outdent",title:"Outdent",handler:"xed.handleOutdent()"}],[{className:"unorderedList",title:"Unordered list",handler:"xed.handleList('UL')"},{className:"orderedList",title:"Ordered list",handler:"xed.handleList('OL')"}],[{className:"paragraph",title:"Paragraph",handler:"xed.handleApplyBlock('P')"},{className:"heading1",title:"Heading 1",handler:"xed.handleApplyBlock('H1')"},{className:"blockquote",title:"Blockquote",handler:"xed.handleApplyBlock('BLOCKQUOTE')"},{className:"code",title:"Code",handler:"xed.handleList('CODE')"},{className:"division",title:"Division",handler:"xed.handleApplyBlock('DIV')"}],[{className:"table",title:"Table",handler:"xed.handleTable(3,3,'tl')"},{className:"separator",title:"Separator",handler:"xed.handleSeparator()"}],[{className:"html",title:"Edit source",handler:"xed.toggleSourceAndWysiwygMode()"}],[{className:"undo",title:"Undo",handler:"xed.handleUndo()"},{className:"redo",title:"Redo",handler:"xed.handleRedo()"}]]; +this.config.imagePathForDefaultToobar=request_uri+editor_path+'examples/img/toolbar/'; +this.config.urlValidationMode="absolute"; +this.config.automaticallyHookSubmitEvent=true; +this.config.allowedTags=["a","abbr","acronym","address","blockquote","br","caption","cite","code","dd","dfn","div","dl","dt","em","h1","h2","h3","h4","h5","h6","hr","img","kbd","li","ol","p","pre","q","samp","span","sup","sub","strong","table","thead","tbody","td","th","tr","ul","var"]; +this.config.allowedAttributes=["alt","cite","class","datetime","height","href","id","rel","rev","src","style","title","width"]; +this.config.shortcuts={}; +this.config.autocorrections={}; +this.config.autocompletions={}; +this.config.templateProcessors={}; +this.config.contextMenuHandlers={}; +this.contentElement=B; +this.doc=this.contentElement.ownerDocument; +this.body=this.doc.body; +this.currentEditMode="readonly"; +this.rdom=xq.RichDom.createInstance(); +this.validator=null; +this.outmostWrapper=null; +this.sourceEditorDiv=null; +this.sourceEditorTextarea=null; +this.wysiwygEditorDiv=null; +this.editorFrame=null; +this.editorWin=null; +this.editorDoc=null; +this.editorBody=null; +this.toolbarContainer=A; +this.toolbarButtons=null; +this.editHistory=null; +this._contextMenuContainer=null; +this._contextMenuItems=null; +this._validContentCache=null; +this._lastModified=null; +this.addShortcuts(this._getDefaultShortcuts()); +this.addTemplateProcessors(this._getDefaultTemplateProcessors()); +this.addListener({onEditorCurrentContentChanged:function(D){var C=D.rdom.getCurrentElement(); +if(!C){return +}if(D._lastFocusElement!=C){if(!D.rdom.tree.isBlockOnlyContainer(D._lastFocusElement)&&D.rdom.tree.isBlock(D._lastFocusElement)){D.rdom.removeTrailingWhitespace(D._lastFocusElement) +}D._fireOnElementChanged(D._lastFocusElement,C); +D._lastFocusElement=C +}D.updateAllToolbarButtonsStatus(C) +}}) +},_getDefaultShortcuts:function(){if(xq.Browser.isMac){return[{event:"Ctrl+Shift+SPACE",handler:"this.handleAutocompletion(); stop = true;"},{event:"ENTER",handler:"this.handleEnter(false, false)"},{event:"Ctrl+ENTER",handler:"this.handleEnter(true, false)"},{event:"Ctrl+Shift+ENTER",handler:"this.handleEnter(true, true)"},{event:"TAB",handler:"this.handleTab()"},{event:"Shift+TAB",handler:"this.handleShiftTab()"},{event:"DELETE",handler:"this.handleDelete()"},{event:"BACKSPACE",handler:"this.handleBackspace()"},{event:"Ctrl+B",handler:"this.handleStrongEmphasis()"},{event:"Ctrl+I",handler:"this.handleEmphasis()"},{event:"Ctrl+U",handler:"this.handleUnderline()"},{event:"Ctrl+K",handler:"this.handleStrike()"},{event:"Meta+Z",handler:"this.handleUndo()"},{event:"Meta+Shift+Z",handler:"this.handleRedo()"},{event:"Meta+Y",handler:"this.handleRedo()"}] +}else{if(xq.Browser.isUbuntu){return[{event:"Ctrl+SPACE",handler:"this.handleAutocompletion(); stop = true;"},{event:"ENTER",handler:"this.handleEnter(false, false)"},{event:"Ctrl+ENTER",handler:"this.handleEnter(true, false)"},{event:"Ctrl+Shift+ENTER",handler:"this.handleEnter(true, true)"},{event:"TAB",handler:"this.handleTab()"},{event:"Shift+TAB",handler:"this.handleShiftTab()"},{event:"DELETE",handler:"this.handleDelete()"},{event:"BACKSPACE",handler:"this.handleBackspace()"},{event:"Ctrl+B",handler:"this.handleStrongEmphasis()"},{event:"Ctrl+I",handler:"this.handleEmphasis()"},{event:"Ctrl+U",handler:"this.handleUnderline()"},{event:"Ctrl+K",handler:"this.handleStrike()"},{event:"Ctrl+Z",handler:"this.handleUndo()"},{event:"Ctrl+Y",handler:"this.handleRedo()"}] +}else{return[{event:"Ctrl+SPACE",handler:"this.handleAutocompletion(); stop = true;"},{event:"ENTER",handler:"this.handleEnter(false, false)"},{event:"Ctrl+ENTER",handler:"this.handleEnter(true, false)"},{event:"Ctrl+Shift+ENTER",handler:"this.handleEnter(true, true)"},{event:"TAB",handler:"this.handleTab()"},{event:"Shift+TAB",handler:"this.handleShiftTab()"},{event:"DELETE",handler:"this.handleDelete()"},{event:"BACKSPACE",handler:"this.handleBackspace()"},{event:"Ctrl+B",handler:"this.handleStrongEmphasis()"},{event:"Ctrl+I",handler:"this.handleEmphasis()"},{event:"Ctrl+U",handler:"this.handleUnderline()"},{event:"Ctrl+K",handler:"this.handleStrike()"},{event:"Ctrl+Z",handler:"this.handleUndo()"},{event:"Ctrl+Y",handler:"this.handleRedo()"}] +}}},_getDefaultTemplateProcessors:function(){return[{id:"predefinedKeywordProcessor",handler:function(C){var A=Date.get(); +var B={year:A.getFullYear(),month:A.getMonth()+1,date:A.getDate(),hour:A.getHours(),min:A.getMinutes(),sec:A.getSeconds()}; +return C.replace(/\{xq:(year|month|date|hour|min|sec)\}/img,function(E,D){return B[D]||D +}) +}}] +},addShortcut:function(A,B){this.config.shortcuts[A]={"event":new xq.Shortcut(A),"handler":B} +},addShortcuts:function(A){A.each(function(B){this.addShortcut(B.event,B.handler) +}.bind(this)) +},getShortcut:function(A){return this.config.shortcuts[A] +},getShortcuts:function(){return this.config.shortcuts +},removeShortcut:function(A){delete this.config.shortcuts[A] +},addAutocorrection:function(D,C,A){if(C.exec){var B=C; +C=function(E){return E.match(B) +}}this.config.autocorrections[D]={"criteria":C,"handler":A} +},addAutocorrections:function(A){A.each(function(B){this.addAutocorrection(B.id,B.criteria,B.handler) +}.bind(this)) +},getAutocorrection:function(A){return this.config.autocorrection[A] +},getAutocorrections:function(){return this.config.autocorrections +},removeAutocorrection:function(A){delete this.config.autocorrections[A] +},addAutocompletion:function(D,C,A){if(C.exec){var B=C; +C=function(F){var E=B.exec(F); +return E?E.index:-1 +}}this.config.autocompletions[D]={"criteria":C,"handler":A} +},addAutocompletions:function(A){A.each(function(B){this.addAutocompletion(B.id,B.criteria,B.handler) +}.bind(this)) +},getAutocompletion:function(A){return this.config.autocompletions[A] +},getAutocompletions:function(){return this.config.autocompletions +},removeAutocompletion:function(A){delete this.config.autocompletions[A] +},addTemplateProcessor:function(B,A){this.config.templateProcessors[B]={"handler":A} +},addTemplateProcessors:function(A){A.each(function(B){this.addTemplateProcessor(B.id,B.handler) +}.bind(this)) +},getTemplateProcessor:function(A){return this.config.templateProcessors[A] +},getTemplateProcessors:function(){return this.config.templateProcessors +},removeTemplateProcessor:function(A){delete this.config.templateProcessors[A] +},addContextMenuHandler:function(B,A){this.config.contextMenuHandlers[B]={"handler":A} +},addContextMenuHandlers:function(A){A.each(function(B){this.addContextMenuHandler(B.id,B.handler) +}.bind(this)) +},getContextMenuHandler:function(A){return this.config.contextMenuHandlers[A] +},getContextMenuHandlers:function(){return this.config.contextMenuHandlers +},removeContextMenuHandler:function(A){delete this.config.contextMenuHandlers[A] +},getCurrentEditMode:function(){return this.currentEditMode +},toggleSourceAndWysiwygMode:function(){var A=this.getCurrentEditMode(); +if(A=="readonly"){return +}this.setEditMode(A=="wysiwyg"?"source":"wysiwyg"); +return true +},setEditMode:function(B){if(this.currentEditMode==B){return +}var A=B!=false&&B!="readonly"&&!this.outmostWrapper; +if(A){this._createEditorFrame(); +this._registerEventHandlers(); +this.loadCurrentContentFromStaticContent(); +this.editHistory=new xq.EditHistory(this.rdom) +}if(B=="wysiwyg"){if(this.currentEditMode=="source"){this.setStaticContent(this.getSourceContent()) +}this.loadCurrentContentFromStaticContent(); +this.contentElement.style.display="none"; +this.sourceEditorDiv.style.display="none"; +this.wysiwygEditorDiv.style.display="block"; +this.outmostWrapper.style.display="block"; +this.currentEditMode=B; +if(!xq.Browser.isTrident){window.setTimeout(function(){if(this.getDoc().designMode=="On"){return +}this.getDoc().designMode="On"; +try{this.getDoc().execCommand("enableInlineTableEditing",false,"false") +}catch(C){}}.bind(this),0) +}this.enableToolbarButtons(); +if(!A){this.focus() +}}else{if(B=="source"){if(this.currentEditMode=="wysiwyg"){this.setStaticContent(this.getWysiwygContent()) +}this.loadCurrentContentFromStaticContent(); +this.contentElement.style.display="none"; +this.sourceEditorDiv.style.display="block"; +this.wysiwygEditorDiv.style.display="none"; +this.outmostWrapper.style.display="block"; +this.currentEditMode=B; +this.disableToolbarButtons(["html"]); +if(!A){this.focus() +}}else{this.setStaticContent(this.getCurrentContent()); +this.loadCurrentContentFromStaticContent(); +this.outmostWrapper.style.display="none"; +this.contentElement.style.display="block"; +this.currentEditMode=B +}}this._fireOnCurrentEditModeChanged(this,B) +},loadStylesheet:function(C){var A=this.editorDoc.getElementsByTagName("HEAD")[0]; +var B=this.editorDoc.createElement("LINK"); +B.rel="Stylesheet"; +B.type="text/css"; +B.href=C; +A.appendChild(B) +},loadCurrentContentFromStaticContent:function(){var A=this.validator.invalidate(this.getStaticContentAsDOM()); +A=this.removeUnnecessarySpaces(A); +if(A.blank()){this.rdom.clearRoot() +}else{this.rdom.getRoot().innerHTML=A +}this.rdom.wrapAllInlineOrTextNodesAs("P",this.rdom.getRoot(),true); +var B=this.getWysiwygContent(true,true); +this.sourceEditorTextarea.value=B; +if(xq.Browser.isWebkit){this.sourceEditorTextarea.innerHTML=B +}this._fireOnCurrentContentChanged(this) +},enableToolbarButtons:function(A){if(!this.toolbarContainer){return +}this._execForAllToolbarButtons(A,function(B,C){B.firstChild.className=!C?"":"disabled" +}); +if(xq.Browser.isIE6){this.toolbarContainer.style.display="none"; +setTimeout(function(){this.toolbarContainer.style.display="block" +}.bind(this),0) +}},disableToolbarButtons:function(A){this._execForAllToolbarButtons(A,function(B,C){B.firstChild.className=C?"":"disabled" +}) +},_execForAllToolbarButtons:function(B,A){if(!this.toolbarContainer){return +}B=B||[]; +$(this.toolbarContainer).select("li").each(function(C){var E=C.classNames().find(function(F){return F!="xq_separator" +}); +var D=B.include(E); +A(C,D) +}) +},_updateToolbarButtonStatus:function(C,B){var A=this.toolbarButtons.get(C); +if(A){A.firstChild.firstChild.className=B?"selected":"" +}},updateAllToolbarButtonsStatus:function(A){if(!this.toolbarContainer){return +}if(!this.toolbarButtons){var D=["emphasis","strongEmphasis","underline","strike","superscription","subscription","justifyLeft","justifyCenter","justifyRight","justifyBoth","unorderedList","orderedList","code","paragraph","heading1","heading2","heading3","heading4","heading5","heading6"]; +this.toolbarButtons=$H({}); +D.each(function(F){var G=$(this.toolbarContainer).getElementsBySelector("."+F); +var E=G&&G.length>0?G[0]:null; +if(E){this.toolbarButtons.set(F,E) +}}.bind(this)) +}var B=this.toolbarButtons; +var C=this.rdom.collectStructureAndStyle(A); +this._updateToolbarButtonStatus("emphasis",C.em); +this._updateToolbarButtonStatus("strongEmphasis",C.strong); +this._updateToolbarButtonStatus("underline",C.underline); +this._updateToolbarButtonStatus("strike",C.strike); +this._updateToolbarButtonStatus("superscription",C.superscription); +this._updateToolbarButtonStatus("subscription",C.subscription); +this._updateToolbarButtonStatus("justifyLeft",C.justification=="left"); +this._updateToolbarButtonStatus("justifyCenter",C.justification=="center"); +this._updateToolbarButtonStatus("justifyRight",C.justification=="right"); +this._updateToolbarButtonStatus("justifyBoth",C.justification=="justify"); +this._updateToolbarButtonStatus("orderedList",C.list=="OL"); +this._updateToolbarButtonStatus("unorderedList",C.list=="UL"); +this._updateToolbarButtonStatus("code",C.list=="CODE"); +this._updateToolbarButtonStatus("paragraph",C.block=="P"); +this._updateToolbarButtonStatus("heading1",C.block=="H1"); +this._updateToolbarButtonStatus("heading2",C.block=="H2"); +this._updateToolbarButtonStatus("heading3",C.block=="H3"); +this._updateToolbarButtonStatus("heading4",C.block=="H4"); +this._updateToolbarButtonStatus("heading5",C.block=="H5"); +this._updateToolbarButtonStatus("heading6",C.block=="H6") +},removeUnnecessarySpaces:function(A){var C=this.rdom.tree.getBlockTags().join("|"); +var B=new RegExp("\\s*<(/?)("+C+")>\\s*","img"); +return A.replace(B,"<$1$2>") +},getCurrentContent:function(A){if(this.getCurrentEditMode()=="source"){return this.getSourceContent(A) +}else{return this.getWysiwygContent(A) +}},getWysiwygContent:function(A,B){if(B||!A){return this.validator.validate(this.rdom.getRoot(),A) +}var C=this.editHistory.getLastModifiedDate(); +if(this._lastModified!=C){this._validContentCache=this.validator.validate(this.rdom.getRoot(),A); +this._lastModified=C +}return this._validContentCache +},getSourceContent:function(C){var B=this.sourceEditorTextarea[xq.Browser.isWebkit?"innerHTML":"value"]; +var A=document.createElement("div"); +A.innerHTML=this.removeUnnecessarySpaces(B); +var D=xq.RichDom.createInstance(); +D.setRoot(document.body); +D.wrapAllInlineOrTextNodesAs("P",A,true); +return this.validator.validate(A,C) +},setStaticContent:function(A){if(this.contentElement.nodeName=="TEXTAREA"){this.contentElement.value=A; +if(xq.Browser.isWebkit){this.contentElement.innerHTML=A +}}else{this.contentElement.innerHTML=A +}this._fireOnStaticContentChanged(this,A) +},getStaticContent:function(){var A; +if(this.contentElement.nodeName=="TEXTAREA"){A=this.contentElement[xq.Browser.isWebkit?"innerHTML":"value"] +}else{A=this.contentElement.innerHTML +}return A +},getStaticContentAsDOM:function(){if(this.contentElement.nodeName=="TEXTAREA"){var A=this.doc.createElement("DIV"); +A.innerHTML=this.contentElement[xq.Browser.isWebkit?"innerHTML":"value"]; +return A +}else{return this.contentElement +}},focus:function(){if(this.getCurrentEditMode()=="wysiwyg"){this.rdom.focus(); +window.setTimeout(function(){this.updateAllToolbarButtonsStatus(this.rdom.getCurrentElement()) +}.bind(this),0) +}else{if(this.getCurrentEditMode()=="source"){this.sourceEditorTextarea.focus() +}}},getFrame:function(){return this.editorFrame +},getWin:function(){return this.editorWin +},getDoc:function(){return this.editorDoc +},getOutmostWrapper:function(){return this.outmostWrapper +},getBody:function(){return this.editorBody +},_createEditorFrame:function(){this.outmostWrapper=this.doc.createElement("div"); +this.outmostWrapper.className="xquared"; +this.contentElement.parentNode.insertBefore(this.outmostWrapper,this.contentElement); +if(!this.toolbarContainer&&this.config.generateDefaultToolbar){this.toolbarContainer=this._generateDefaultToolbar(); +this.outmostWrapper.appendChild(this.toolbarContainer) +}this.sourceEditorDiv=this.doc.createElement("div"); +this.sourceEditorDiv.className="editor source_editor"; +this.sourceEditorDiv.style.display="none"; +this.outmostWrapper.appendChild(this.sourceEditorDiv); +this.sourceEditorTextarea=this.doc.createElement("textarea"); +this.sourceEditorDiv.appendChild(this.sourceEditorTextarea); +this.wysiwygEditorDiv=this.doc.createElement("div"); +this.wysiwygEditorDiv.className="editor wysiwyg_editor"; +this.wysiwygEditorDiv.style.display="none"; +this.outmostWrapper.appendChild(this.wysiwygEditorDiv); +this.editorFrame=this.doc.createElement("iframe"); +this.rdom.setAttributes(this.editorFrame,{"frameBorder":"0","marginWidth":"0","marginHeight":"0","leftMargin":"0","topMargin":"0","allowTransparency":"true"}); +this.wysiwygEditorDiv.appendChild(this.editorFrame); +var B=this.editorFrame.contentWindow.document; +if(xq.Browser.isTrident){B.designMode="On" +}B.open(); +B.write(""); +B.write(""); +B.write(""); +if(!xq.Browser.isTrident){B.write("") +}B.write(""); +B.write("XQuared"); +if(this.config.changeCursorOnLink){B.write("") +}B.write(""); +B.write("

    "+this.rdom.makePlaceHolderString()+"

    "); +B.write(""); +B.close(); +this.editorWin=this.editorFrame.contentWindow; +this.editorDoc=this.editorWin.document; +this.editorBody=this.editorDoc.body; +this.editorBody.className="xed"; +if(xq.Browser.isIE6){this.editorDoc.documentElement.style.overflowY="auto"; +this.editorDoc.documentElement.style.overflowX="hidden" +}this.rdom.setWin(this.editorWin); +this.rdom.setRoot(this.editorBody); +this.validator=xq.Validator.createInstance(this.doc.location.href,this.config.urlValidationMode,this.config.allowedTags,this.config.allowedAttributes); +if(this.config.automaticallyHookSubmitEvent&&this.contentElement.nodeName=="TEXTAREA"&&this.contentElement.form){var A=this.contentElement.form.onsubmit; +this.contentElement.form.onsubmit=function(){this.contentElement.value=this.getCurrentContent(true); +if(A){return A() +}else{return true +}}.bind(this) +}},_addStyleRule:function(A,C){if(!this.dynamicStyle){if(xq.Browser.isTrident){this.dynamicStyle=this.doc.createStyleSheet() +}else{var B=this.doc.createElement("style"); +this.doc.body.appendChild(B); +this.dynamicStyle=$A(this.doc.styleSheets).last() +}}if(xq.Browser.isTrident){this.dynamicStyle.addRule(A,C) +}else{this.dynamicStyle.insertRule(A+" {"+C+"}",this.dynamicStyle.cssRules.length) +}},_generateDefaultToolbar:function(){this._addStyleRule(".xquared div.toolbar","background-image: url("+this.config.imagePathForDefaultToobar+"toolbarBg.gif)"); +this._addStyleRule(".xquared ul.buttons li","background-image: url("+this.config.imagePathForDefaultToobar+"toolbarButtonBg.gif)"); +this._addStyleRule(".xquared ul.buttons li.xq_separator","background-image: url("+this.config.imagePathForDefaultToobar+"toolbarSeparator.gif)"); +var container=this.doc.createElement("div"); +container.className="toolbar"; +var buttons=this.doc.createElement("ul"); +buttons.className="buttons"; +container.appendChild(buttons); +var cancelMousedown=function(e){Event.stop(e); +return false +}; +var map=this.config.defaultToolbarButtonMap; +for(var i=0; +i0){this._contextMenuContainer.removeChild(this._contextMenuContainer.childNodes[0]) +}}for(var B=0; +B"+(B.title.toString().escapeHTML())+"" +}else{A.innerHTML=(B.title.toString().escapeHTML()) +}}if(B.className){A.className=B.className +}this._contextMenuContainer.appendChild(A); +return A +},_contextMenuClicked:function(e){this.hideContextMenu(); +if(!this._contextMenuContainer){return +}var node=Event.findElement(e,"LI"); +if(!node||!this.rdom.tree.isDescendantOf(this._contextMenuContainer,node)){return +}for(var i=0; +i-1,isGecko:navigator.userAgent.indexOf("Gecko")>-1&&navigator.userAgent.indexOf("KHTML")==-1,isKHTML:navigator.userAgent.indexOf("KHTML")!=-1,isPresto:navigator.appName=="Opera",isMac:navigator.userAgent.indexOf("Macintosh")!=-1,isUbuntu:navigator.userAgent.indexOf("Ubuntu")!=-1,isIE:navigator.appName=="Microsoft Internet Explorer",isIE6:navigator.userAgent.indexOf("MSIE 6")!=-1,isIE7:navigator.userAgent.indexOf("MSIE 7")!=-1}; +xq.Shortcut=Class.create({initialize:function(A){this.keymap=(typeof A=="string")?xq.Shortcut.interprete(A).keymap:A +},matches:function(A){var B=xq.Browser.isGecko&&xq.Browser.isMac?(A.keyCode+"_"+A.charCode):A.keyCode; +var D=(this.keymap.which==B)||(this.keymap.which==32&&B==25); +if(typeof A.metaKey=="undefined"){A.metaKey=false +}var C=(typeof this.keymap.shiftKey=="undefined"||this.keymap.shiftKey==A.shiftKey)&&(typeof this.keymap.altKey=="undefined"||this.keymap.altKey==A.altKey)&&(typeof this.keymap.ctrlKey=="undefined"||this.keymap.ctrlKey==A.ctrlKey)&&(typeof this.keymap.metaKey=="undefined"||this.keymap.metaKey==A.metaKey); +return C&&D +}}); +xq.Shortcut.interprete=function(G){G=G.toUpperCase(); +var F=xq.Shortcut._interpreteWhich(G.split("+").pop()); +var E=xq.Shortcut._interpreteModifier(G,"CTRL"); +var C=xq.Shortcut._interpreteModifier(G,"ALT"); +var B=xq.Shortcut._interpreteModifier(G,"SHIFT"); +var D=xq.Shortcut._interpreteModifier(G,"META"); +var A={}; +A.which=F; +if(typeof E!="undefined"){A.ctrlKey=E +}if(typeof C!="undefined"){A.altKey=C +}if(typeof B!="undefined"){A.shiftKey=B +}if(typeof D!="undefined"){A.metaKey=D +}return new xq.Shortcut(A) +}; +xq.Shortcut._interpreteModifier=function(A,B){return A.match("\\("+B+"\\)")?undefined:A.match(B)?true:false +}; +xq.Shortcut._interpreteWhich=function(A){var B=A.length==1?((xq.Browser.isMac&&xq.Browser.isGecko)?"0_"+A.toLowerCase().charCodeAt(0):A.charCodeAt(0)):xq.Shortcut._keyNames[A]; +if(typeof B=="undefined"){throw"Unknown special key name: ["+A+"]" +}return B +}; +xq.Shortcut._keyNames=xq.Browser.isMac&&xq.Browser.isGecko?{BACKSPACE:"8_0",TAB:"9_0",RETURN:"13_0",ENTER:"13_0",ESC:"27_0",SPACE:"0_32",LEFT:"37_0",UP:"38_0",RIGHT:"39_0",DOWN:"40_0",DELETE:"46_0",HOME:"36_0",END:"35_0",PAGEUP:"33_0",PAGEDOWN:"34_0",COMMA:"0_44",HYPHEN:"0_45",EQUAL:"0_61",PERIOD:"0_46",SLASH:"0_47",F1:"112_0",F2:"113_0",F3:"114_0",F4:"115_0",F5:"116_0",F6:"117_0",F7:"118_0",F8:"119_0"}:{BACKSPACE:8,TAB:9,RETURN:13,ENTER:13,ESC:27,SPACE:32,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46,HOME:36,END:35,PAGEUP:33,PAGEDOWN:34,COMMA:188,HYPHEN:xq.Browser.isTrident?189:109,EQUAL:xq.Browser.isTrident?187:61,PERIOD:190,SLASH:191,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123}; +xq.DomTree=Class.create({initialize:function(){this._blockTags=["DIV","DD","LI","ADDRESS","CAPTION","DT","H1","H2","H3","H4","H5","H6","HR","P","BODY","BLOCKQUOTE","PRE","PARAM","DL","OL","UL","TABLE","THEAD","TBODY","TR","TH","TD"]; +this._blockContainerTags=["DIV","DD","LI","BODY","BLOCKQUOTE","UL","OL","DL","TABLE","THEAD","TBODY","TR","TH","TD"]; +this._listContainerTags=["OL","UL","DL"]; +this._tableCellTags=["TH","TD"]; +this._blockOnlyContainerTags=["BODY","BLOCKQUOTE","UL","OL","DL","TABLE","THEAD","TBODY","TR"]; +this._atomicTags=["IMG","OBJECT","BR","HR"] +},getBlockTags:function(){return this._blockTags +},findCommonAncestorAndImmediateChildrenOf:function(E,C){if(E.parentNode==C.parentNode){return{left:E,right:C,parent:E.parentNode} +}else{var D=this.collectParentsOf(E,true); +var G=this.collectParentsOf(C,true); +var B=this.getCommonAncestor(D,G); +var F=D.find(function(H){return H.parentNode==B +}); +var A=G.find(function(H){return H.parentNode==B +}); +return{left:F,right:A,parent:B} +}},getLeavesAtEdge:function(C){if(!C.hasChildNodes()){return[null,null] +}var D=function(G){for(var F=0; +F0){for(var A=0; +AQ[L].length){C-=Q[L].length +}else{M=L; +break +}}if(R){return{text:P,textIndex:N,nodeIndex:M,breakPoint:C} +}if(C!=0){var I=B[M].splitText(C); +M++; +B.splice(M,0,I) +}var A=B[M]||H.firstChild; +var O=this.tree.findCommonAncestorAndImmediateChildrenOf(A,G); +var K=O.parent; +if(K){if(A.parentNode!=K){A=this.splitElementUpto(A,K,true) +}if(G.parentNode!=K){G=this.splitElementUpto(G,K,true) +}var D=A.previousSibling; +var J=G.nextSibling; +if(D&&D.nodeType==1&&this.isEmptyBlock(D)){this.deleteNode(D) +}if(J&&J.nodeType==1&&this.isEmptyBlock(J)){this.deleteNode(J) +}var E=this.insertNodeAt(this.createElement(S),A,"before"); +while(E.nextSibling!=G){E.appendChild(E.nextSibling) +}return E +}else{var E=this.insertNodeAt(this.createElement(S),G,"before"); +return E +}},wrapAllInlineOrTextNodesAs:function(A,B,E){var D=[]; +if(!E&&!this.tree.hasMixedContents(B)){return D +}var C=B.firstChild; +while(C){if(this.tree.isTextOrInlineNode(C)){var F=this.wrapInlineOrTextNodesAs(A,C); +D.push(F); +C=F.nextSibling +}else{C=C.nextSibling +}}return D +},wrapInlineOrTextNodesAs:function(A,B){var D=this.createElement(A); +var C=B; +C.parentNode.replaceChild(D,C); +D.appendChild(C); +while(D.nextSibling&&this.tree.isTextOrInlineNode(D.nextSibling)){D.appendChild(D.nextSibling) +}return D +},turnElementIntoListItem:function(C,D){D=D.toUpperCase(); +var B=this.createElement(D=="UL"?"UL":"OL"); +if(D=="CODE"){B.className="code" +}if(this.tree.isTableCell(C)){var E=this.wrapAllInlineOrTextNodesAs("P",C,true)[0]; +B=this.insertNodeAt(B,C,"start"); +var A=this.insertNodeAt(this.createElement("LI"),B,"start"); +A.appendChild(E) +}else{B=this.insertNodeAt(B,C,"after"); +var A=this.insertNodeAt(this.createElement("LI"),B,"start"); +A.appendChild(C) +}this.unwrapUnnecessaryParagraph(A); +this.mergeAdjustLists(B); +return A +},extractOutElementFromParent:function(B){if(B==this.root||this.root==B.parentNode||!B.offsetParent){return null +}if(B.nodeName=="LI"){this.wrapAllInlineOrTextNodesAs("P",B,true); +B=B.firstChild +}var A=B.parentNode; +var D=null; +if(A.nodeName=="LI"&&A.parentNode.parentNode.nodeName=="LI"){if(B.previousSibling){this.splitContainerOf(B,true); +this.correctEmptyElement(B) +}this.outdentListItem(B); +D=B +}else{if(A.nodeName=="LI"){if(this.tree.isListContainer(B.nextSibling)){var E=A.parentNode; +this.splitContainerOf(A,true); +this.correctEmptyElement(B); +D=A.firstChild; +while(A.firstChild){this.insertNodeAt(A.firstChild,E,"before") +}var C=E.previousSibling; +this.deleteNode(E); +if(C&&this.tree.isListContainer(C)){this.mergeAdjustLists(C) +}}else{this.splitContainerOf(B,true); +this.correctEmptyElement(B); +var E=this.splitContainerOf(A); +this.insertNodeAt(B,E.parentNode,"before"); +this.deleteNode(E.parentNode); +D=B +}}else{if(this.tree.isTableCell(A)||this.tree.isTableCell(B)){}else{this.splitContainerOf(B,true); +this.correctEmptyElement(B); +D=this.insertNodeAt(B,A,"before"); +this.deleteNode(A) +}}}return D +},insertNewBlockAround:function(E,D,B){var C=E.nodeName=="LI"||E.parentNode.nodeName=="LI"; +this.removeTrailingWhitespace(E); +if(this.isFirstLiWithNestedList(E)&&!B&&D){var A=this.getParentElementOf(E,["LI"]); +var F=this._insertNewBlockAround(A,D); +return F +}else{if(C&&!B){var A=this.getParentElementOf(E,["LI"]); +var F=this._insertNewBlockAround(E,D); +if(A!=E){F=this.splitContainerOf(F,false,"prev") +}return F +}else{if(this.tree.isBlockContainer(E)){this.wrapAllInlineOrTextNodesAs("P",E,true); +return this._insertNewBlockAround(E.firstChild,D,B) +}else{return this._insertNewBlockAround(E,D,this.tree.isHeading(E)?"P":B) +}}}},_insertNewBlockAround:function(B,C,A){var D=this.createElement(A||B.nodeName); +this.copyAttributes(B,D,false); +this.correctEmptyElement(D); +D=this.insertNodeAt(D,B,C?"before":"after"); +return D +},applyTagIntoElement:function(A,B){if(this.tree.isBlockOnlyContainer(A)){return this.wrapBlock(A,B) +}else{if(this.tree.isBlockContainer(B)){var C=this.createElement(A); +this.moveChildNodes(B,C); +return this.insertNodeAt(C,B,"start") +}else{if(this.tree.isBlockContainer(A)&&this.hasImportantAttributes(B)){return this.wrapBlock(A,B) +}else{return this.replaceTag(A,B) +}}}throw"IllegalArgumentException - ["+A+", "+B+"]" +},applyTagIntoElements:function(C,I,J){var E=[]; +if(this.tree.isBlockContainer(C)){var G=this.tree.findCommonAncestorAndImmediateChildrenOf(I,J); +var D=G.left; +var B=this.insertNodeAt(this.createElement(C),D,"before"); +var K=G.parent.nodeName=="LI"&&G.parent.parentNode.childNodes.length==1&&!G.left.previousSilbing&&!G.right.nextSibling; +if(K){var H=D.parentNode.parentNode; +this.insertNodeAt(B,H,"before"); +B.appendChild(H) +}else{while(D!=G.right){next=D.nextSibling; +B.appendChild(D); +D=next +}B.appendChild(G.right) +}E.push(B) +}else{var A=this.getBlockElementsBetween(I,J); +for(var F=0; +F=2&&this.isMarker(D.lastChild.previousSibling)&&D.lastChild.nodeType==3&&D.lastChild.nodeValue.length==1&&D.lastChild.nodeValue.charCodeAt(0)==160){this.deleteNode(D.lastChild) +}this.removePlaceHoldersAndEmptyNodes(D); +if(this.isEmptyBlock(D)){if(this.tree.isAtomic(D)){D=this.replaceTag("P",D) +}D=this.replaceTag(F.nodeName,D)||D; +D.innerHTML="" +}else{if(D.firstChild==D.lastChild&&this.isMarker(D.firstChild)){D=this.replaceTag(F.nodeName,D)||D +}}if(this.isEmptyBlock(F)){if(this.tree.isAtomic(F)){F=this.replaceTag("P",F) +}F.innerHTML="" +}this.moveChildNodes(F,D); +this.deleteNode(F); +return D +}finally{if(H&&this.isEmptyBlock(H)){this.deleteNode(H,true) +}if(G&&this.isEmptyBlock(G)){this.deleteNode(G,true) +}if(H){this.unwrapUnnecessaryParagraph(H) +}if(G){this.unwrapUnnecessaryParagraph(G) +}}},mergeAdjustLists:function(A,G,D){var F=A.previousSibling; +var C=F&&(F.nodeName==A.nodeName&&F.className==A.className); +if((!D||D.toLowerCase()=="prev")&&(C||(G&&this.tree.isListContainer(F)))){while(F.lastChild){this.insertNodeAt(F.lastChild,A,"start") +}this.deleteNode(F) +}var E=A.nextSibling; +var B=E&&(E.nodeName==A.nodeName&&E.className==A.className); +if((!D||D.toLowerCase()=="next")&&(B||(G&&this.tree.isListContainer(E)))){while(E.firstChild){this.insertNodeAt(E.firstChild,A,"end") +}this.deleteNode(E) +}},moveChildNodes:function(B,A){if(this.tree.isDescendantOf(B,A)||["HTML","HEAD"].include(A.nodeName)){throw"Illegal argument. Cannot move children of element["+B.nodeName+"] to element["+A.nodeName+"]" +}if(B==A){return +}while(B.firstChild){A.appendChild(B.firstChild) +}},copyAttributes:function(E,D,B){var A=E.attributes; +if(!A){return +}for(var C=0; +C0?D:E +},outdentElementsCode:function(A){if(A.tagName=="LI"){A=A.parentNode +}if(A.tagName=="OL"&&A.className=="code"){return true +}return false +},_outdentElements:function(C,F,E){for(var B=0; +B0; +var D=O.length>0; +var L=null; +if(E){L=H +}else{if(D){L=O +}else{L=B +}}for(var F=0; +F" +},makeEmptyParagraph:function(){return this.createElementFromHtml("


    ") +},isPlaceHolder:function(B){if(B.nodeType!=1){return false +}var A=B.nodeName=="BR"&&B.getAttribute("type")=="_moz"; +if(A){return true +}var C=B.nodeName=="BR"&&!this.getNextSibling(B); +if(C){return true +}return false +},selectElement:function(B,C){if(!B){throw"[element] is null" +}if(B.nodeType!=1){throw"[element] is not an element" +}try{if(!xq.Browser.isMac){this.doc.execCommand("SelectAll",false,null) +}}catch(A){}if(C){this.rng().selectNode(B) +}else{this.rng().selectNodeContents(B) +}}}); +xq.RichDomWebkit=Class.create(xq.RichDomW3,{makePlaceHolder:function(){var A=this.createElement("BR"); +A.className="webkit-block-placeholder"; +return A +},makePlaceHolderString:function(){return"
    " +},makeEmptyParagraph:function(){return this.createElementFromHtml("


    ") +},isPlaceHolder:function(A){return A.nodeName=="BR"&&A.className=="webkit-block-placeholder" +},rng:function(){var B=this.sel(); +var A=this.doc.createRange(); +if(!this._rng||this._anchorNode!=B.anchorNode||this._anchorOffset!=B.anchorOffset||this._focusNode!=B.focusNode||this._focusOffset!=B.focusOffset){if(B.type!="None"){A.setStart(B.anchorNode,B.anchorOffset); +A.setEnd(B.focusNode,B.focusOffset) +}this._anchorNode=B.anchorNode; +this._anchorOffset=B.anchorOffset; +this._focusNode=B.focusNode; +this._focusOffset=B.focusOffset; +this._rng=A +}return this._rng +},selectElement:function(B,C){if(!B){throw"[element] is null" +}if(B.nodeType!=1){throw"[element] is not an element" +}var A=this.rng(); +if(C){A.selectNode(B) +}else{A.selectNodeContents(B) +}this._setSelectionByRange(A) +},deleteSelection:function(){this.rng().deleteContents() +},collapseSelection:function(B){var A=this.rng(); +A.collapse(B); +this._setSelectionByRange(A) +},getSelectionAsHtml:function(){var B=this.createElement("div"); +var A=this.rng(); +var C=this.rng().cloneContents(); +if(C){B.appendChild(C) +}return B.innerHTML +},_setSelectionByRange:function(A){var B=this.sel(); +B.setBaseAndExtent(A.startContainer,A.startOffset,A.endContainer,A.endOffset); +this._anchorNode=B.anchorNode; +this._anchorOffset=B.anchorOffset; +this._focusNode=B.focusNode; +this._focusOffset=B.focusOffset +}}); +xq.RichDomTrident=Class.create(xq.RichDom,{makePlaceHolder:function(){return this.createTextNode(" ") +},makePlaceHolderString:function(){return" " +},makeEmptyParagraph:function(){return this.createElementFromHtml("

     

    ") +},isPlaceHolder:function(A){return false +},getOuterHTML:function(A){return A.outerHTML +},insertNode:function(B){if(this.hasSelection()){this.collapseSelection(true) +}this.rng().pasteHTML(""); +var A=this.$("xquared_temp"); +if(B.id=="xquared_temp"){return A +}A.replaceNode(B); +return B +},removeTrailingWhitespace:function(E){if(!E){return +}if(this.tree.isBlockContainer(E)){return +}if(this.isEmptyBlock(E)){return +}var D=E.innerText; +var B=D.charCodeAt(D.length-1); +if(D.length<=1||![32,160].include(B)){return +}var C=E; +while(C&&C.nodeType!=3){C=C.lastChild +}if(!C){return +}var A=C.nodeValue; +if(A.length<=1){this.deleteNode(C,true) +}else{C.nodeValue=A.substring(0,A.length-1) +}},correctEmptyElement:function(A){if(!A||A.nodeType!=1||this.tree.isAtomic(A)){return +}if(A.firstChild){this.correctEmptyElement(A.firstChild) +}else{A.innerHTML=" " +}},copyAttributes:function(C,B,A){B.mergeAttributes(C,!A) +},correctParagraph:function(){if(!this.hasFocus()){return false +}if(this.hasSelection()){return false +}var D=this.getCurrentElement(); +if(D.nodeName=="BODY"){D=this.insertNode(this.makeEmptyParagraph()); +var B=D.nextSibling; +if(this.tree.isAtomic(B)){D=this.insertNodeAt(D,B,"after"); +this.placeCaretAtStartOf(D); +var C=this.tree.findForward(D,function(E){return this.tree.isBlock(E)&&!this.tree.isBlockOnlyContainer(E) +}.bind(this)); +if(C){this.deleteNode(D); +this.placeCaretAtStartOf(C) +}return true +}else{var C=this.tree.findForward(D,function(E){return this.tree.isBlock(E)&&!this.tree.isBlockOnlyContainer(E) +}.bind(this)); +if(C){this.deleteNode(D); +this.placeCaretAtStartOf(C) +}return true +}}else{D=this.getCurrentBlockElement(); +if(D.nodeType==3){D=D.parentNode +}if(this.tree.hasMixedContents(D)){var A=this.pushMarker(); +this.wrapAllInlineOrTextNodesAs("P",D,true); +this.popMarker(true); +return true +}else{if((this.tree.isTextOrInlineNode(D.previousSibling)||this.tree.isTextOrInlineNode(D.nextSibling))&&this.tree.hasMixedContents(D.parentNode)){this.wrapAllInlineOrTextNodesAs("P",D.parentNode,true); +return true +}else{return false +}}}},execCommand:function(A,B){return this.doc.execCommand(A,false,B) +},applyBackgroundColor:function(A){this.execCommand("BackColor",A) +},applyEmphasis:function(){this.execCommand("Italic") +},applyStrongEmphasis:function(){this.execCommand("Bold") +},applyStrike:function(){this.execCommand("strikethrough") +},applyUnderline:function(){this.execCommand("underline") +},applyRemoveFormat:function(){this.execCommand("RemoveFormat"); +this.execCommand("Unlink") +},execHeading:function(A){this.execCommand("FormatBlock","") +},focus:function(){this.win.focus(); +if(!this._focusedBefore){this.correctParagraph(); +this.placeCaretAtStartOf(this.getCurrentBlockElement()); +this._focusedBefore=true +}},sel:function(){return this.doc.selection +},rng:function(){try{var B=this.sel(); +return(B==null)?null:B.createRange() +}catch(A){return null +}},hasSelection:function(){var A=this.sel().type.toLowerCase(); +if("none"==A){return false +}if("text"==A&&this.getSelectionAsHtml().length==0){return false +}return true +},deleteSelection:function(){if(this.getSelectionAsText()!=""){this.sel().clear() +}},placeCaretAtStartOf:function(A){var B=this.insertNodeAt(this.createElement("SPAN"),A,"start"); +this.selectElement(B); +this.collapseSelection(false); +this.deleteNode(B) +},selectElement:function(B,C){if(!B){throw"[element] is null" +}if(B.nodeType!=1){throw"[element] is not an element" +}var A=this.rng(); +A.moveToElementText(B); +A.select() +},selectBlocksBetween:function(D,B){var A=this.rng(); +var C=this.rng(); +C.moveToElementText(D); +A.setEndPoint("StartToStart",C); +C.moveToElementText(B); +A.setEndPoint("EndToEnd",C); +A.select() +},collapseSelection:function(B){var A=this.rng(); +A.collapse(B); +A.select() +},getSelectionAsHtml:function(){var A=this.rng(); +return A&&A.htmlText?A.htmlText:"" +},getSelectionAsText:function(){var A=this.rng(); +return A&&A.text?A.text:"" +},hasImportantAttributes:function(A){return !!(A.id||A.className||A.style.cssText) +},isEmptyBlock:function(A){if(!A.hasChildNodes()){return true +}if(A.nodeType==3&&!A.nodeValue){return true +}if([" "," ",""].include(A.innerHTML)){return true +}return false +},getLastChild:function(C){if(!C||!C.hasChildNodes()){return null +}var A=$A(C.childNodes).reverse(); +for(var B=0; +BA)?B.cells[A]:null +},getRowAt:function(A){if(this.hasHeadingAtTop()){return A==0?this.table.tHead.rows[0]:this.table.tBodies[0].rows[A-1] +}else{var B=this.table.tBodies[0].rows; +return(B.length>A)?B[A]:null +}},getDom:function(){return this.table +},hasHeadingAtTop:function(){return !!(this.table.tHead&&this.table.tHead.rows[0]) +},hasHeadingAtLeft:function(){return this.table.tBodies[0].rows[0].cells[0].nodeName=="TH" +},correctEmptyCells:function(){var A=$A(this.table.getElementsByTagName("TH")); +A.push($A(this.table.getElementsByTagName("TD"))); +A=A.flatten(); +for(var B=0; +B"); +if(I){F.push(""); +for(var D=0; +D") +}F.push(""); +J-=1 +}F.push(""); +for(var D=0; +D"); +for(var B=0; +B") +}else{F.push("") +}}F.push("") +}F.push(""); +F.push(""); +var A=E.createElement("div"); +A.innerHTML=F.join(""); +var H=new xq.RichTable(E,A.firstChild); +H.correctEmptyCells(); +return H +}; +xq.Validator=Class.create({initialize:function(C,A,D,B){this.allowedTags=(D||["a","abbr","acronym","address","blockquote","br","caption","cite","code","dd","dfn","div","dl","dt","em","h1","h2","h3","h4","h5","h6","hr","img","kbd","li","ol","p","pre","q","samp","span","sup","sub","strong","table","thead","tbody","td","th","tr","ul","var"]).join(" ")+" "; +this.allowedAttrs=(B||["alt","cite","class","datetime","height","href","id","rel","rev","src","style","title","width"]).join(" ")+" "; +this.curUrl=C; +this.curUrlParts=C?C.parseURL():null; +this.urlValidationMode=A +},validate:function(B,A){throw"Not implemented" +},invalidate:function(A){throw"Not implemented" +},validateStrike:function(A){A=A.replace(/|\s+[^>]*>)/ig,"/ig,""); +return A +},validateUnderline:function(A){A=A.replace(/|\s+[^>]*>)/ig,"/ig,""); +return A +},replaceTag:function(A,C,B){return A.replace(new RegExp("(|\\s+[^>]*>)","ig"),"$1"+B+"$2") +},validateSelfClosingTags:function(A){return A.replace(/<(br|hr|img)([^>]*?)>/img,function(D,B,C){return"<"+B+C+" />" +}) +},removeComments:function(A){return A.replace(//img,"") +},removeDangerousElements:function(C){var A=$A(C.getElementsByTagName("SCRIPT")).reverse(); +for(var B=0; +B]+?)(>|\\s+([^>]*?)(\\s?/?)>)","g"),function(H,K,M,G,L,I){if(C.indexOf(M)==-1){return"" +}if(L){L=L.replace(/(^|\s")([^"=]+)(\s|$)/g,"$1$2=\"$2\"$3"); +var J=[]; +var E=L.match(/([^=]+)="[^"]*?"/g); +for(var F=0; +F" +}else{return H +}}) +},makeUrlsRelative:function(A){var B=this.curUrl; +var C=this.curUrlParts; +return A.replace(/(<\w+\s+)(\/|([^>]+?)(\/?))>/g,function(H,G,D,F,E){if(F){F=F.replace(/(href|src)="([^"]+)"/g,function(M,L,K){var J=null; +if(K.charAt(0)=="#"){J=C.includeQuery+K +}else{if(K.charAt(0)=="?"){J=C.includePath+K +}else{if(K.charAt(0)=="/"){J=C.includeHost+K +}else{if(K.match(/^\w+:\/\//)){J=K +}else{J=C.includeBase+K +}}}}var I=J; +if(J.indexOf(C.includeQuery)==0){I=J.substring(C.includeQuery.length) +}else{if(J.indexOf(C.includePath)==0){I=J.substring(C.includePath.length) +}else{if(J.indexOf(C.includeBase)==0){I=J.substring(C.includeBase.length) +}else{if(J.indexOf(C.includeHost)==0){I=J.substring(C.includeHost.length) +}}}}if(I==""){I="#" +}return L+"=\""+I+"\"" +}); +return G+F+E+">" +}else{return H +}}); +return A +},makeUrlsHostRelative:function(A){var B=this.curUrl; +var C=this.curUrlParts; +return A.replace(/(<\w+\s+)(\/|([^>]+?)(\/?))>/g,function(H,G,D,F,E){if(F){F=F.replace(/(href|src)="([^"]+)"/g,function(M,L,K){var J=null; +if(K.charAt(0)=="#"){J=C.includeQuery+K +}else{if(K.charAt(0)=="?"){J=C.includePath+K +}else{if(K.charAt(0)=="/"){J=C.includeHost+K +}else{if(K.match(/^\w+:\/\//)){J=K +}else{J=C.includeBase+K +}}}}var I=J; +if(J.indexOf(C.includeHost)==0){I=J.substring(C.includeHost.length) +}if(I==""){I="#" +}return L+"=\""+I+"\"" +}); +return G+F+E+">" +}else{return H +}}); +return A +},makeUrlsAbsolute:function(A){var B=this.curUrl; +var C=this.curUrlParts; +return A.replace(/(<\w+\s+)(\/|([^>]+?)(\/?))>/g,function(H,G,D,F,E){if(F){F=F.replace(/(href|src)="([^"]+)"/g,function(L,K,J){var I=null; +if(J.charAt(0)=="#"){I=C.includeQuery+J +}else{if(J.charAt(0)=="?"){I=C.includePath+J +}else{if(J.charAt(0)=="/"){I=C.includeHost+J +}else{if(J.match(/^\w+:\/\//)){I=J +}else{I=C.includeBase+J +}}}}return K+"=\""+I+"\"" +}); +return G+F+E+">" +}else{return H +}}) +}}); +xq.Validator.createInstance=function(C,A,D,B){if(xq.Browser.isTrident){return new xq.ValidatorTrident(C,A,D,B) +}else{if(xq.Browser.isWebkit){return new xq.ValidatorWebkit(C,A,D,B) +}else{return new xq.ValidatorGecko(C,A,D,B) +}}}; +xq.ValidatorW3=Class.create(xq.Validator,{validate:function(C,B){C=C.cloneNode(true); +var F=xq.RichDom.createInstance(); +F.setRoot(C); +F.removePlaceHoldersAndEmptyNodes(C); +this.removeDangerousElements(C); +this.validateFontColor(C); +var E=C.innerHTML; +try{E=this.replaceTag(E,"b","strong"); +E=this.replaceTag(E,"i","em"); +E=this.validateStrike(E); +E=this.validateUnderline(E); +E=this.addNbspToEmptyBlocks(E); +if(B){E=this.performFullValidation(E) +}}catch(A){}var G=F.tree.getBlockTags().join("|"); +var D=new RegExp("([^\n])","img"); +E=E.replace(D,"\n$2"); +return E +},invalidate:function(C){var F=xq.RichDom.createInstance(); +F.setRoot(C); +var E=F.findByAttribute("class","strike"); +for(var B=0; +B\\s*?","img"); +return B.replace(A,"<$1> ") +},replaceNbspToBr:function(B){var D=new xq.DomTree().getBlockTags().join("|"); +var A=new RegExp("<("+D+")>( )?","img"); +var C=xq.RichDom.createInstance(); +return B.replace(A,"<$1>"+C.makePlaceHolderString()+"") +}}); +xq.ValidatorGecko=Class.create(xq.ValidatorW3,{}); +xq.ValidatorWebkit=Class.create(xq.ValidatorW3,{}); +xq.ValidatorTrident=Class.create(xq.Validator,{validate:function(C,B){C=C.cloneNode(true); +this.removeDangerousElements(C); +this.validateFontColor(C); +this.validateBackgroundColor(C); +var D=C.innerHTML; +try{D=this.validateStrike(D); +D=this.validateUnderline(D); +if(B){D=this.performFullValidation(D) +}}catch(A){}return D +},invalidate:function(C){var F=xq.RichDom.createInstance(); +F.setRoot(C); +this.invalidateFontColor(C); +this.invalidateBackgroundColor(C); +var E=F.findByAttribute("className","strike"); +for(var B=0; +B]*?)>/img,function(E,B,D,C){return"<"+B+D.toLowerCase()+this.correctHtmlAttrQuotation(C)+">" +}.bind(this)); +return A +},correctHtmlAttrQuotation:function(A){A=A.replace(/\s(\w+?)=\s+"([^"]+)"/mg,function(D,B,C){return" "+B.toLowerCase()+"=\""+C+"\"" +}); +A=A.replace(/\s(\w+?)=([^ "]+)/mg,function(D,B,C){return" "+B.toLowerCase()+"=\""+C+"\"" +}); +return A +}}); +xq.EditHistory=Class.create({initialize:function(B,A){if(!B){throw"IllegalArgumentException" +}this.disabled=false; +this.max=A||100; +this.rdom=B; +this.root=B.getRoot(); +this.clear(); +this.lastModified=Date.get() +},getLastModifiedDate:function(){return this.lastModified +},isUndoable:function(){return this.queue.length>0&&this.index>0 +},isRedoable:function(){return this.queue.length>0&&this.index0){var A=B.html.substring(0,B.caret)+""+B.html.substring(B.caret); +this.root.innerHTML=A +}else{this.root.innerHTML=B.html +}this.restoreCaret() +},pushContent:function(B){if(xq.Browser.isTrident&&!B&&!this.rdom.hasFocus()){return false +}if(!this.rdom.getCurrentElement()){return false +}var A=this.root.innerHTML; +if(A==(this.queue[this.index]?this.queue[this.index].html:null)){return false +}var C=B?-1:this.saveCaret(); +if(this.queue.length>=this.max){this.queue.shift() +}else{this.index++ +}this.queue.splice(this.index,this.queue.length-this.index,{html:A,caret:C}); +return true +},clear:function(){this.index=-1; +this.queue=[]; +this.pushContent(true) +},saveCaret:function(){if(this.rdom.hasSelection()){return null +}var A=this.rdom.pushMarker(); +var C=xq.Browser.isTrident?"0){D[0].focus() +}if(C.cancelOnEsc){Event.observe(this.form,"keydown",function(F){if(F.keyCode==27){this.onCloseHandler(); +this.close() +}return false +}.bind(this)) +}this.onLoadHandler(this) +},close:function(){this.form.parentNode.removeChild(this.form) +},setPosition:function(G){var D; +if(G=="centerOfWindow"){D=document.documentElement +}else{if(G=="centerOfEditor"){D=this.xed.getDoc()[xq.Browser.isTrident?"body":"documentElement"] +}else{if(G=="nearbyCaret"){throw"Not implemented yet" +}else{throw"Invalid argument: "+G +}}}var E=D.clientWidth; +var B=D.clientHeight; +var F=this.form.clientWidth; +var C=this.form.clientHeight; +var A=parseInt((E-F)/2); +var H=parseInt((B-C)/2); +this.form.style.left=A+"px"; +this.form.style.top=H+"px" +}}); +xq.controls.QuickSearchDialog=Class.create({initialize:function(A,B){this.xed=A; +this.rdom=xq.RichDom.createInstance(); +this.rdom.setRoot(document.body); +this.param=B; +if(!this.param.renderItem){this.param.renderItem=function(C){return this.rdom.getInnerText(C) +}.bind(this) +}this.container=null +},getQuery:function(){if(!this.container){return"" +}return this._getInputField().value +},onSubmit:function(A){if(this.matchCount()>0){this.param.onSelect(this.xed,this.list[this._getSelectedIndex()]) +}this.close(); +Event.stop(A); +return false +},onCancel:function(A){if(this.param.onCancel){this.param.onCancel(this.xed) +}this.close() +},onBlur:function(A){setTimeout(function(){this.onCancel(A) +}.bind(this),400) +},onKey:function(C){var B=new xq.Shortcut("ESC"); +var D=new xq.Shortcut("ENTER"); +var A=new xq.Shortcut("UP"); +var E=new xq.Shortcut("DOWN"); +if(B.matches(C)){this.onCancel(C) +}else{if(D.matches(C)){this.onSubmit(C) +}else{if(A.matches(C)){this._moveSelectionUp() +}else{if(E.matches(C)){this._moveSelectionDown() +}else{this.updateList() +}}}}},onClick:function(C){var B=C.srcElement||C.target; +if(B.nodeName=="LI"){var A=this._getIndexOfLI(B); +this.param.onSelect(this.xed,this.list[A]) +}},onList:function(A){this.list=A; +this.renderList(A) +},updateList:function(){window.setTimeout(function(){this.param.listProvider(this.getQuery(),this.xed,this.onList.bind(this)) +}.bind(this),0) +},renderList:function(D){var B=this._getListContainer(); +B.innerHTML=""; +for(var C=0; +C=C){B=0 +}A.childNodes[B].className="selected" +}}); +if(!xq){xq={} +}if(!xq.ui_templates){xq.ui_templates={} +}xq.ui_templates.basicColorPickerDialog="
    \n\t\t
    \n\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\tYellow\n\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\tPink\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t
    \n\t
    "; +if(!xq){xq={} +}if(!xq.ui_templates){xq.ui_templates={} +}xq.ui_templates.basicLinkDialog="
    \n\t\t

    Link

    \n\t\t
    \n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t
    \n\t
    " diff --git a/modules/editor/skins/xquared/js/xquared.js b/modules/editor/skins/xquared/js/xquared.js new file mode 100644 index 000000000..1e010f684 --- /dev/null +++ b/modules/editor/skins/xquared/js/xquared.js @@ -0,0 +1,7139 @@ +/** + * Namespace for entire Xquared classes + */ +var xq = { + majorVersion: '0.1', + minorVersion: '2007119' +}; + +/** + * Make given object as event source + * + * @param {Object} object target object + * @param {String} prefix prefix for generated functions + * @param {Array} events array of string which contains name of events + */ +xq.asEventSource = function(object, prefix, events) { + object._listeners = [] + object._registerEventFirer = function(prefix, name) { + this["_fireOn" + name] = function() { + for(var i = 0; i < this._listeners.length; i++) { + var listener = this._listeners[i]; + var func = listener["on" + prefix + name]; + if(func) func.apply(listener, $A(arguments)); + } + } + } + object.addListener = function(l) { + this._listeners.push(l); + } + + for(var i = 0; i < events.length; i++) { + object._registerEventFirer(prefix, events[i]); + } +} + +/** + * Returns the index of given element + * + * @returns {Number} index or -1 + */ +Array.prototype.indexOf = function(n) { + for(var i = 0; i < this.length; i++) { + if(this[i] == n) return i; + } + + return -1; +} + +Date.preset = null; +Date.pass = function(msec) { + if(Date.preset == null) return; + Date.preset = new Date(Date.preset.getTime() + msec); +} +Date.get = function() { + return Date.preset == null ? new Date() : Date.preset; +} +Date.prototype.elapsed = function(msec) { + return Date.get().getTime() - this.getTime() >= msec; +} + +String.prototype.merge = function(data) { + var newString = this; + for(k in data) { + newString = newString.replace("{" + k + "}", data[k]); + } + return newString; +} + +String.prototype.parseURL = function() { + var m = this.match(/((((\w+):\/\/(((([^@:]+)(:([^@]+))?)@)?([^:\/\?#]+)?(:(\d+))?))?([^\?#]+)?)(\?([^#]+))?)(#(.+))?/); + + var includeAnchor = m[0]; + var includeQuery = m[1] || undefined; + var includePath = m[2] || undefined; + var includeHost = m[3] || undefined; + var includeBase = null; + var protocol = m[4] || undefined; + var user = m[8] || undefined; + var password = m[10] || undefined; + var domain = m[11] || undefined; + var port = m[13] || undefined; + var path = m[14] || undefined; + var query = m[16] || undefined; + var anchor = m[18] || undefined; + + if(!path || path == '/') { + includeBase = includeHost + '/'; + } else { + var index = path.lastIndexOf('/'); + includeBase = includeHost + path.substring(0, index + 1); + } + + return { + includeAnchor: includeAnchor, + includeQuery: includeQuery, + includePath: includePath, + includeBase: includeBase, + includeHost: includeHost, + protocol: protocol, + user: user, + password: password, + domain: domain, + port: port, + path: path, + query: query, + anchor: anchor + }; +} + +xq.findXquaredScript = function() { + return $A(document.getElementsByTagName("script")).find(function(script) { + return script.src && script.src.match(/xquared\.js/i); + }); +} +xq.shouldLoadOthers = function() { + var script = xq.findXquaredScript(); + return script && !!script.src.match(/xquared\.js\?load_others=1/i); +} +xq.loadScript = function(url) { + document.write(''); +} +xq.loadOthers = function() { + var script = xq.findXquaredScript(); + var basePath = script.src.match(/(.*\/)xquared\.js.*/i)[1]; + var others = [ + 'Editor.js', + 'Browser.js', + 'Shortcut.js', + 'DomTree.js', + 'RichDom.js', + 'RichDomW3.js', + 'RichDomGecko.js', + 'RichDomWebkit.js', + 'RichDomTrident.js', + 'RichTable.js', + 'Validator.js', + 'ValidatorW3.js', + 'ValidatorGecko.js', + 'ValidatorWebkit.js', + 'ValidatorTrident.js', + 'EditHistory.js', + 'Controls.js', + '_ui_templates.js' + ]; + others.each(function(name) { + xq.loadScript(basePath + name); + }); +} + +if(xq.shouldLoadOthers()) xq.loadOthers(); +/** + * @fileOverview xq.Editor manages configurations such as autocompletion and autocorrection, edit mode/normal mode switching, handles editing commands, keyboard shortcuts and other events. + */ +xq.Editor = Class.create({ + /** + * Initialize editor but it doesn't automatically start designMode. setEditMode should be called after initialization. + * + * @constructor + * @param {Element} contentElement HTML element(TEXTAREA or normal block element such as DIV) to be replaced with editable area + * @param {Element} toolbarContainer HTML element which contains toolbar icons + */ + initialize: function(contentElement, toolbarContainer) { + if(!contentElement) throw "[contentElement] is null"; + if(contentElement.nodeType != 1) throw "[contentElement] is not an element"; + + xq.asEventSource(this, "Editor", ["ElementChanged", "BeforeEvent", "AfterEvent", "CurrentContentChanged", "StaticContentChanged", "CurrentEditModeChanged"]); + + /** + * Editor's configuration + * @type object + */ + this.config = {}; + this.config.enableLinkClick = false; + this.config.changeCursorOnLink = false; + this.config.generateDefaultToolbar = true; + this.config.defaultToolbarButtonMap = [ + [ + {className:"foregroundColor", title:"Foreground color", handler:"xed.handleForegroundColor()"}, + {className:"backgroundColor", title:"Background color", handler:"xed.handleBackgroundColor()"} + ], + [ + {className:"link", title:"Link", handler:"xed.handleLink()"}, + {className:"strongEmphasis", title:"Strong emphasis", handler:"xed.handleStrongEmphasis()"}, + {className:"emphasis", title:"Emphasis", handler:"xed.handleEmphasis()"}, + {className:"underline", title:"Underline", handler:"xed.handleUnderline()"}, + {className:"strike", title:"Strike", handler:"xed.handleStrike()"}, + {className:"superscription", title:"Superscription", handler:"xed.handleSuperscription()"}, + {className:"subscription", title:"Subscription", handler:"xed.handleSubscription()"} + ], + [ + {className:"removeFormat", title:"Remove format", handler:"xed.handleRemoveFormat()"} + ], + [ + {className:"justifyLeft", title:"Justify left", handler:"xed.handleJustify('left')"}, + {className:"justifyCenter", title:"Justify center", handler:"xed.handleJustify('center')"}, + {className:"justifyRight", title:"Justify right", handler:"xed.handleJustify('right')"}, + {className:"justifyBoth", title:"Justify both", handler:"xed.handleJustify('both')"} + ], + [ + {className:"indent", title:"Indent", handler:"xed.handleIndent()"}, + {className:"outdent", title:"Outdent", handler:"xed.handleOutdent()"} + ], + [ + {className:"unorderedList", title:"Unordered list", handler:"xed.handleList('UL')"}, + {className:"orderedList", title:"Ordered list", handler:"xed.handleList('OL')"} + ], + [ + {className:"paragraph", title:"Paragraph", handler:"xed.handleApplyBlock('P')"}, + {className:"heading1", title:"Heading 1", handler:"xed.handleApplyBlock('H1')"}, + {className:"blockquote", title:"Blockquote", handler:"xed.handleApplyBlock('BLOCKQUOTE')"}, + {className:"code", title:"Code", handler:"xed.handleList('CODE')"}, + {className:"division", title:"Division", handler:"xed.handleApplyBlock('DIV')"} + ], + [ + {className:"table", title:"Table", handler:"xed.handleTable(3,3,'tl')"}, + {className:"separator", title:"Separator", handler:"xed.handleSeparator()"} + ], + [ + {className:"html", title:"Edit source", handler:"xed.toggleSourceAndWysiwygMode()"} + ], + [ + {className:"undo", title:"Undo", handler:"xed.handleUndo()"}, + {className:"redo", title:"Redo", handler:"xed.handleRedo()"} + ] + ]; + + this.config.imagePathForDefaultToobar = request_uri+editor_path.substring(1)+'examples/img/toolbar/'; + + // relative | host_relative | absolute | browser_default + this.config.urlValidationMode = 'absolute'; + + this.config.automaticallyHookSubmitEvent = true; + + this.config.allowedTags = ['a', 'abbr', 'acronym', 'address', 'blockquote', 'br', 'caption', 'cite', 'code', 'dd', 'dfn', 'div', 'dl', 'dt', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'img', 'kbd', 'li', 'ol', 'p', 'pre', 'q', 'samp', 'span', 'sup', 'sub', 'strong', 'table', 'thead', 'tbody', 'td', 'th', 'tr', 'ul', 'var']; + this.config.allowedAttributes = ['alt', 'cite', 'class', 'datetime', 'height', 'href', 'id', 'rel', 'rev', 'src', 'style', 'title', 'width']; + + this.config.shortcuts = {}; + this.config.autocorrections = {}; + this.config.autocompletions = {}; + this.config.templateProcessors = {}; + this.config.contextMenuHandlers = {}; + + /** + * Original content element + * @type Element + */ + this.contentElement = contentElement; + + /** + * Owner document of content element + * @type Document + */ + this.doc = this.contentElement.ownerDocument; + + /** + * Body of content element + * @type Element + */ + this.body = this.doc.body; + + /** + * False or 'readonly' means read-only mode, true or 'wysiwyg' means WYSIWYG editing mode, and 'source' means source editing mode. + * @type Object + */ + this.currentEditMode = 'readonly'; + + /** + * RichDom instance + * @type xq.RichDom + */ + this.rdom = xq.RichDom.createInstance(); + + /** + * Validator instance + * @type xq.Validator + */ + this.validator = null; + + /** + * Outmost wrapper div + * @type Element + */ + this.outmostWrapper = null; + + /** + * Source editor container + * @type Element + */ + this.sourceEditorDiv = null; + + /** + * Source editor textarea + * @type Element + */ + this.sourceEditorTextarea = null; + + /** + * WYSIWYG editor container + * @type Element + */ + this.wysiwygEditorDiv = null; + + /** + * Design mode iframe + * @type IFrame + */ + this.editorFrame = null; + + /** + * Window that contains design mode iframe + * @type Window + */ + this.editorWin = null; + + /** + * Document that contained by design mode iframe + * @type Document + */ + this.editorDoc = null; + + /** + * Body that contained by design mode iframe + * @type Element + */ + this.editorBody = null; + + /** + * Toolbar container + * @type Element + */ + this.toolbarContainer = toolbarContainer; + + /** + * Toolbar buttons + * @type Array + */ + this.toolbarButtons = null; + + /** + * Undo/redo manager + * @type xq.EditHistory + */ + this.editHistory = null; + + this._contextMenuContainer = null; + this._contextMenuItems = null; + + this._validContentCache = null; + this._lastModified = null; + + this.addShortcuts(this._getDefaultShortcuts()); + this.addTemplateProcessors(this._getDefaultTemplateProcessors()); + + this.addListener({ + onEditorCurrentContentChanged: function(xed) { + var curFocusElement = xed.rdom.getCurrentElement(); + if(!curFocusElement) return; + + if(xed._lastFocusElement != curFocusElement) { + if(!xed.rdom.tree.isBlockOnlyContainer(xed._lastFocusElement) && xed.rdom.tree.isBlock(xed._lastFocusElement)) { + xed.rdom.removeTrailingWhitespace(xed._lastFocusElement); + } + xed._fireOnElementChanged(xed._lastFocusElement, curFocusElement); + xed._lastFocusElement = curFocusElement; + } + + xed.updateAllToolbarButtonsStatus(curFocusElement); + } + }); + }, + + + + ///////////////////////////////////////////// + // Configuration Management + + _getDefaultShortcuts: function() { + if(xq.Browser.isMac) { + // Mac FF & Safari + return [ + {event:"Ctrl+Shift+SPACE", handler:"this.handleAutocompletion(); stop = true;"}, + {event:"ENTER", handler:"this.handleEnter(false, false)"}, + {event:"Ctrl+ENTER", handler:"this.handleEnter(true, false)"}, + {event:"Ctrl+Shift+ENTER", handler:"this.handleEnter(true, true)"}, + {event:"TAB", handler:"this.handleTab()"}, + {event:"Shift+TAB", handler:"this.handleShiftTab()"}, + {event:"DELETE", handler:"this.handleDelete()"}, + {event:"BACKSPACE", handler:"this.handleBackspace()"}, + + {event:"Ctrl+B", handler:"this.handleStrongEmphasis()"}, + {event:"Ctrl+I", handler:"this.handleEmphasis()"}, + {event:"Ctrl+U", handler:"this.handleUnderline()"}, + {event:"Ctrl+K", handler:"this.handleStrike()"}, + {event:"Meta+Z", handler:"this.handleUndo()"}, + {event:"Meta+Shift+Z", handler:"this.handleRedo()"}, + {event:"Meta+Y", handler:"this.handleRedo()"} + ]; + } else if(xq.Browser.isUbuntu) { + // Ubunto FF + return [ + {event:"Ctrl+SPACE", handler:"this.handleAutocompletion(); stop = true;"}, + {event:"ENTER", handler:"this.handleEnter(false, false)"}, + {event:"Ctrl+ENTER", handler:"this.handleEnter(true, false)"}, + {event:"Ctrl+Shift+ENTER", handler:"this.handleEnter(true, true)"}, + {event:"TAB", handler:"this.handleTab()"}, + {event:"Shift+TAB", handler:"this.handleShiftTab()"}, + {event:"DELETE", handler:"this.handleDelete()"}, + {event:"BACKSPACE", handler:"this.handleBackspace()"}, + + {event:"Ctrl+B", handler:"this.handleStrongEmphasis()"}, + {event:"Ctrl+I", handler:"this.handleEmphasis()"}, + {event:"Ctrl+U", handler:"this.handleUnderline()"}, + {event:"Ctrl+K", handler:"this.handleStrike()"}, + {event:"Ctrl+Z", handler:"this.handleUndo()"}, + {event:"Ctrl+Y", handler:"this.handleRedo()"} + ]; + } else { + // Win IE & FF + return [ + {event:"Ctrl+SPACE", handler:"this.handleAutocompletion(); stop = true;"}, + {event:"ENTER", handler:"this.handleEnter(false, false)"}, + {event:"Ctrl+ENTER", handler:"this.handleEnter(true, false)"}, + {event:"Ctrl+Shift+ENTER", handler:"this.handleEnter(true, true)"}, + {event:"TAB", handler:"this.handleTab()"}, + {event:"Shift+TAB", handler:"this.handleShiftTab()"}, + {event:"DELETE", handler:"this.handleDelete()"}, + {event:"BACKSPACE", handler:"this.handleBackspace()"}, + + {event:"Ctrl+B", handler:"this.handleStrongEmphasis()"}, + {event:"Ctrl+I", handler:"this.handleEmphasis()"}, + {event:"Ctrl+U", handler:"this.handleUnderline()"}, + {event:"Ctrl+K", handler:"this.handleStrike()"}, + {event:"Ctrl+Z", handler:"this.handleUndo()"}, + {event:"Ctrl+Y", handler:"this.handleRedo()"} + ]; + } + }, + + _getDefaultTemplateProcessors: function() { + return [ + { + id:"predefinedKeywordProcessor", + handler:function(html) { + var today = Date.get(); + var keywords = { + year: today.getFullYear(), + month: today.getMonth() + 1, + date: today.getDate(), + hour: today.getHours(), + min: today.getMinutes(), + sec: today.getSeconds() + }; + + return html.replace(/\{xq:(year|month|date|hour|min|sec)\}/img, function(text, keyword) { + return keywords[keyword] || keyword; + }); + } + } + ]; + }, + + /** + * Adds or replaces keyboard shortcut. + * + * @param {String} shortcut keymap expression like "CTRL+Space" + * @param {Object} handler string or function to be evaluated or called + */ + addShortcut: function(shortcut, handler) { + this.config.shortcuts[shortcut] = {"event":new xq.Shortcut(shortcut), "handler":handler}; + }, + + /** + * Adds several keyboard shortcuts at once. + * + * @param {Array} list of shortcuts. each element should have following structure: {event:"keymap expression", handler:handler} + */ + addShortcuts: function(list) { + list.each(function(shortcut) { + this.addShortcut(shortcut.event, shortcut.handler); + }.bind(this)); + }, + + /** + * Returns keyboard shortcut matches with given keymap expression. + * + * @param {String} shortcut keymap expression like "CTRL+Space" + */ + getShortcut: function(shortcut) {return this.config.shortcuts[shortcut];}, + + /** + * Returns entire keyboard shortcuts' map + */ + getShortcuts: function() {return this.config.shortcuts;}, + + /** + * Remove keyboard shortcut matches with given keymap expression. + * + * @param {String} shortcut keymap expression like "CTRL+Space" + */ + removeShortcut: function(shortcut) {delete this.config.shortcuts[shortcut];}, + + /** + * Adds or replaces autocorrection handler. + * + * @param {String} id unique identifier + * @param {Object} criteria regex pattern or function to be used as a criterion for match + * @param {Object} handler string or function to be evaluated or called when criteria met + */ + addAutocorrection: function(id, criteria, handler) { + if(criteria.exec) { + var pattern = criteria; + criteria = function(text) {return text.match(pattern)}; + } + this.config.autocorrections[id] = {"criteria":criteria, "handler":handler}; + }, + + /** + * Adds several autocorrection handlers at once. + * + * @param {Array} list of autocorrection. each element should have following structure: {id:"identifier", criteria:criteria, handler:handler} + */ + addAutocorrections: function(list) { + list.each(function(ac) { + this.addAutocorrection(ac.id, ac.criteria, ac.handler); + }.bind(this)); + }, + + /** + * Returns autocorrection handler matches with given id + * + * @param {String} id unique identifier + */ + getAutocorrection: function(id) {return this.config.autocorrection[id];}, + + /** + * Returns entire autocorrections' map + */ + getAutocorrections: function() {return this.config.autocorrections;}, + + /** + * Removes autocorrection handler matches with given id + * + * @param {String} id unique identifier + */ + removeAutocorrection: function(id) {delete this.config.autocorrections[id];}, + + /** + * Adds or replaces autocompletion handler. + * + * @param {String} id unique identifier + * @param {Object} criteria regex pattern or function to be used as a criterion for match + * @param {Object} handler string or function to be evaluated or called when criteria met + */ + addAutocompletion: function(id, criteria, handler) { + if(criteria.exec) { + var pattern = criteria; + criteria = function(text) { + var m = pattern.exec(text); + return m ? m.index : -1; + }; + } + this.config.autocompletions[id] = {"criteria":criteria, "handler":handler}; + }, + + /** + * Adds several autocompletion handlers at once. + * + * @param {Array} list of autocompletion. each element should have following structure: {id:"identifier", criteria:criteria, handler:handler} + */ + addAutocompletions: function(list) { + list.each(function(ac) { + this.addAutocompletion(ac.id, ac.criteria, ac.handler); + }.bind(this)); + }, + + /** + * Returns autocompletion handler matches with given id + * + * @param {String} id unique identifier + */ + getAutocompletion: function(id) {return this.config.autocompletions[id];}, + + /** + * Returns entire autocompletions' map + */ + getAutocompletions: function() {return this.config.autocompletions;}, + + /** + * Removes autocompletion handler matches with given id + * + * @param {String} id unique identifier + */ + removeAutocompletion: function(id) {delete this.config.autocompletions[id];}, + + /** + * Adds or replaces template processor. + * + * @param {String} id unique identifier + * @param {Object} handler string or function to be evaluated or called when template inserted + */ + addTemplateProcessor: function(id, handler) { + this.config.templateProcessors[id] = {"handler":handler}; + }, + + /** + * Adds several template processors at once. + * + * @param {Array} list of template processors. Each element should have following structure: {id:"identifier", handler:handler} + */ + addTemplateProcessors: function(list) { + list.each(function(tp) { + this.addTemplateProcessor(tp.id, tp.handler); + }.bind(this)); + }, + + /** + * Returns template processor matches with given id + * + * @param {String} id unique identifier + */ + getTemplateProcessor: function(id) {return this.config.templateProcessors[id];}, + + /** + * Returns entire template processors' map + */ + getTemplateProcessors: function() {return this.config.templateProcessors;}, + + /** + * Removes template processor matches with given id + * + * @param {String} id unique identifier + */ + removeTemplateProcessor: function(id) {delete this.config.templateProcessors[id];}, + + + + /** + * Adds or replaces context menu handler. + * + * @param {String} id unique identifier + * @param {Object} handler string or function to be evaluated or called when onContextMenu occured + */ + addContextMenuHandler: function(id, handler) { + this.config.contextMenuHandlers[id] = {"handler":handler}; + }, + + /** + * Adds several context menu handlers at once. + * + * @param {Array} list of handlers. Each element should have following structure: {id:"identifier", handler:handler} + */ + addContextMenuHandlers: function(list) { + list.each(function(mh) { + this.addContextMenuHandler(mh.id, mh.handler); + }.bind(this)); + }, + + /** + * Returns context menu handler matches with given id + * + * @param {String} id unique identifier + */ + getContextMenuHandler: function(id) {return this.config.contextMenuHandlers[id];}, + + /** + * Returns entire context menu handlers' map + */ + getContextMenuHandlers: function() {return this.config.contextMenuHandlers;}, + + /** + * Removes context menu handler matches with given id + * + * @param {String} id unique identifier + */ + removeContextMenuHandler: function(id) {delete this.config.contextMenuHandlers[id];}, + + + + ///////////////////////////////////////////// + // Edit mode management + + /** + * Returns current edit mode - readonly, wysiwyg, source + */ + getCurrentEditMode: function() { + return this.currentEditMode; + }, + + toggleSourceAndWysiwygMode: function() { + var mode = this.getCurrentEditMode(); + if(mode == 'readonly') return; + this.setEditMode(mode == 'wysiwyg' ? 'source' : 'wysiwyg'); + + return true; + }, + + /** + * Switches between edit-mode/normal mode. + * + * @param {Object} mode false or 'readonly' means read-only mode, true or 'wysiwyg' means WYSIWYG editing mode, and 'source' means source editing mode. + */ + setEditMode: function(mode) { + if(this.currentEditMode == mode) return; + + var firstCall = mode != false && mode != 'readonly' && !this.outmostWrapper; + if(firstCall) { + // Create editor element if needed + this._createEditorFrame(); + this._registerEventHandlers(); + + this.loadCurrentContentFromStaticContent(); + this.editHistory = new xq.EditHistory(this.rdom); + } + + if(mode == 'wysiwyg') { + // Update contents + if(this.currentEditMode == 'source') this.setStaticContent(this.getSourceContent()); + this.loadCurrentContentFromStaticContent(); + + // Make static content invisible + this.contentElement.style.display = "none"; + + // Make WYSIWYG editor visible + this.sourceEditorDiv.style.display = "none"; + this.wysiwygEditorDiv.style.display = "block"; + this.outmostWrapper.style.display = "block"; + + this.currentEditMode = mode; + + if(!xq.Browser.isTrident) { + window.setTimeout(function() { + if(this.getDoc().designMode == 'On') return; + + // Without it, Firefox doesn't display embedded SWF + this.getDoc().designMode = 'On'; + + // turn off Firefox's table editing feature + try {this.getDoc().execCommand("enableInlineTableEditing", false, "false")} catch(ignored) {} + }.bind(this), 0); + } + + this.enableToolbarButtons(); + if(!firstCall) this.focus(); + } else if(mode == 'source') { + // Update contents + if(this.currentEditMode == 'wysiwyg') this.setStaticContent(this.getWysiwygContent()); + this.loadCurrentContentFromStaticContent(); + + // Make static content invisible + this.contentElement.style.display = "none"; + + // Make source editor visible + this.sourceEditorDiv.style.display = "block"; + this.wysiwygEditorDiv.style.display = "none"; + this.outmostWrapper.style.display = "block"; + + this.currentEditMode = mode; + + this.disableToolbarButtons(['html']); + if(!firstCall) this.focus(); + } else { + // Update contents + this.setStaticContent(this.getCurrentContent()); + this.loadCurrentContentFromStaticContent(); + + // Make editor and toolbar invisible + this.outmostWrapper.style.display = "none"; + + // Make static content visible + this.contentElement.style.display = "block"; + + this.currentEditMode = mode; + } + + this._fireOnCurrentEditModeChanged(this, mode); + }, + + /** + * Load CSS into editing-mode document + * + * @param {string} path URL + */ + loadStylesheet: function(path) { + var head = this.editorDoc.getElementsByTagName("HEAD")[0]; + var link = this.editorDoc.createElement("LINK"); + link.rel = "Stylesheet"; + link.type = "text/css"; + link.href = path; + head.appendChild(link); + }, + + /** + * Sets editor's dynamic content from static content + */ + loadCurrentContentFromStaticContent: function() { + // update WYSIWYG editor + var html = this.validator.invalidate(this.getStaticContentAsDOM()); + html = this.removeUnnecessarySpaces(html); + + if(html.blank()) { + this.rdom.clearRoot(); + } else { + this.rdom.getRoot().innerHTML = html; + } + this.rdom.wrapAllInlineOrTextNodesAs("P", this.rdom.getRoot(), true); + + // update source editor + var source = this.getWysiwygContent(true, true); + + this.sourceEditorTextarea.value = source; + if(xq.Browser.isWebkit) { + this.sourceEditorTextarea.innerHTML = source; + } + + this._fireOnCurrentContentChanged(this); + }, + + /** + * Enables all toolbar buttons + * + * @param {Array} [exceptions] array of string containing classnames to exclude + */ + enableToolbarButtons: function(exceptions) { + if(!this.toolbarContainer) return; + + this._execForAllToolbarButtons(exceptions, function(li, exception) { + li.firstChild.className = !exception ? '' : 'disabled'; + }); + + // Toolbar image icon disappears without following code: + if(xq.Browser.isIE6) { + this.toolbarContainer.style.display = 'none'; + setTimeout(function() {this.toolbarContainer.style.display = 'block';}.bind(this), 0); + } + }, + + /** + * Disables all toolbar buttons + * + * @param {Array} [exceptions] array of string containing classnames to exclude + */ + disableToolbarButtons: function(exceptions) { + this._execForAllToolbarButtons(exceptions, function(li, exception) { + li.firstChild.className = exception ? '' : 'disabled'; + }); + }, + + _execForAllToolbarButtons: function(exceptions, exec) { + if(!this.toolbarContainer) return; + exceptions = exceptions || []; + + $(this.toolbarContainer).select('li').each(function(li) { + var buttonsClassName = li.classNames().find(function(name) {return name != 'xq_separator'}); + var exception = exceptions.include(buttonsClassName); + exec(li, exception); + }); + }, + + _updateToolbarButtonStatus: function(buttonClassName, selected) { + var button = this.toolbarButtons.get(buttonClassName); + if(button) button.firstChild.firstChild.className = selected ? 'selected' : ''; + }, + + updateAllToolbarButtonsStatus: function(element) { + if(!this.toolbarContainer) return; + if(!this.toolbarButtons) { + var classNames = [ + "emphasis", "strongEmphasis", "underline", "strike", "superscription", "subscription", + "justifyLeft", "justifyCenter", "justifyRight", "justifyBoth", + "unorderedList", "orderedList", "code", + "paragraph", "heading1", "heading2", "heading3", "heading4", "heading5", "heading6" + ]; + + this.toolbarButtons = $H({}); + + classNames.each(function(className) { + var found = $(this.toolbarContainer).getElementsBySelector("." + className); + var button = found && found.length > 0 ? found[0] : null; + if(button) this.toolbarButtons.set(className, button); + }.bind(this)); + } + + var buttons = this.toolbarButtons; + + var info = this.rdom.collectStructureAndStyle(element); + + this._updateToolbarButtonStatus('emphasis', info.em); + this._updateToolbarButtonStatus('strongEmphasis', info.strong); + this._updateToolbarButtonStatus('underline', info.underline); + this._updateToolbarButtonStatus('strike', info.strike); + this._updateToolbarButtonStatus('superscription', info.superscription); + this._updateToolbarButtonStatus('subscription', info.subscription); + + this._updateToolbarButtonStatus('justifyLeft', info.justification == 'left'); + this._updateToolbarButtonStatus('justifyCenter', info.justification == 'center'); + this._updateToolbarButtonStatus('justifyRight', info.justification == 'right'); + this._updateToolbarButtonStatus('justifyBoth', info.justification == 'justify'); + + this._updateToolbarButtonStatus('orderedList', info.list == 'OL'); + this._updateToolbarButtonStatus('unorderedList', info.list == 'UL'); + this._updateToolbarButtonStatus('code', info.list == 'CODE'); + + this._updateToolbarButtonStatus('paragraph', info.block == 'P'); + this._updateToolbarButtonStatus('heading1', info.block == 'H1'); + this._updateToolbarButtonStatus('heading2', info.block == 'H2'); + this._updateToolbarButtonStatus('heading3', info.block == 'H3'); + this._updateToolbarButtonStatus('heading4', info.block == 'H4'); + this._updateToolbarButtonStatus('heading5', info.block == 'H5'); + this._updateToolbarButtonStatus('heading6', info.block == 'H6'); + }, + + removeUnnecessarySpaces: function(html) { + var blocks = this.rdom.tree.getBlockTags().join("|"); + var regex = new RegExp("\\s*<(/?)(" + blocks + ")>\\s*", "img"); + return html.replace(regex, '<$1$2>'); + }, + + /** + * Gets editor's dynamic content from current editor(source or WYSIWYG) + * + * @return {Object} HTML String + */ + getCurrentContent: function(performFullValidation) { + if(this.getCurrentEditMode() == 'source') { + return this.getSourceContent(performFullValidation); + } else { + return this.getWysiwygContent(performFullValidation); + } + }, + + /** + * Gets editor's dynamic content from WYSIWYG editor + * + * @return {Object} HTML String + */ + getWysiwygContent: function(performFullValidation, dontUseCache) { + if(dontUseCache || !performFullValidation) return this.validator.validate(this.rdom.getRoot(), performFullValidation); + + var lastModified = this.editHistory.getLastModifiedDate(); + if(this._lastModified != lastModified) { + this._validContentCache = this.validator.validate(this.rdom.getRoot(), performFullValidation); + this._lastModified = lastModified; + } + return this._validContentCache; + }, + + /** + * Gets editor's dynamic content from source editor + * + * @return {Object} HTML String + */ + getSourceContent: function(performFullValidation) { + var raw = this.sourceEditorTextarea[xq.Browser.isWebkit ? 'innerHTML' : 'value']; + var tempDiv = document.createElement('div'); + tempDiv.innerHTML = this.removeUnnecessarySpaces(raw); + + var rdom = xq.RichDom.createInstance(); + rdom.setRoot(document.body); + rdom.wrapAllInlineOrTextNodesAs("P", tempDiv, true); + + return this.validator.validate(tempDiv, performFullValidation); + }, + + /** + * Sets editor's original content + * + * @param {Object} content HTML String + */ + setStaticContent: function(content) { + if(this.contentElement.nodeName == 'TEXTAREA') { + this.contentElement.value = content; + if(xq.Browser.isWebkit) { + this.contentElement.innerHTML = content; + } + } else { + this.contentElement.innerHTML = content; + } + this._fireOnStaticContentChanged(this, content); + }, + + /** + * Gets editor's original content + * + * @return {Object} HTML String + */ + getStaticContent: function() { + var content; + if(this.contentElement.nodeName == 'TEXTAREA') { + content = this.contentElement[xq.Browser.isWebkit ? 'innerHTML' : 'value']; + } else { + content = this.contentElement.innerHTML; + } + return content; + }, + + /** + * Gets editor's original content as DOM node + * + * @return {Object} HTML String + */ + getStaticContentAsDOM: function() { + if(this.contentElement.nodeName == 'TEXTAREA') { + var div = this.doc.createElement('DIV'); + div.innerHTML = this.contentElement[xq.Browser.isWebkit ? 'innerHTML' : 'value']; + return div; + } else { + return this.contentElement; + } + }, + + /** + * Gives focus to editor + */ + focus: function() { + if(this.getCurrentEditMode() == 'wysiwyg') { + this.rdom.focus(); + window.setTimeout(function() { + this.updateAllToolbarButtonsStatus(this.rdom.getCurrentElement()); + }.bind(this), 0); + } else if(this.getCurrentEditMode() == 'source') { + this.sourceEditorTextarea.focus(); + } + }, + + /** + * Returns designmode iframe object + */ + getFrame: function() { + return this.editorFrame; + }, + + /** + * Returns designmode window object + */ + getWin: function() { + return this.editorWin; + }, + + /** + * Returns designmode document object + */ + getDoc: function() { + return this.editorDoc; + }, + + /** + * Returns outmost wrapper element + */ + getOutmostWrapper: function() { + return this.outmostWrapper; + }, + + /** + * Returns designmode body object + */ + getBody: function() { + return this.editorBody; + }, + + _createEditorFrame: function() { + // create outer DIV + this.outmostWrapper = this.doc.createElement('div'); + this.outmostWrapper.className = "xquared"; + + this.contentElement.parentNode.insertBefore(this.outmostWrapper, this.contentElement); + + // create toolbar is needed + if(!this.toolbarContainer && this.config.generateDefaultToolbar) { + this.toolbarContainer = this._generateDefaultToolbar(); + this.outmostWrapper.appendChild(this.toolbarContainer); + } + + // create source editor div + this.sourceEditorDiv = this.doc.createElement('div'); + this.sourceEditorDiv.className = "editor source_editor"; //TODO: remove editor + this.sourceEditorDiv.style.display = "none"; + this.outmostWrapper.appendChild(this.sourceEditorDiv); + + // create TEXTAREA for source editor + this.sourceEditorTextarea = this.doc.createElement('textarea'); + this.sourceEditorDiv.appendChild(this.sourceEditorTextarea); + + // create WYSIWYG editor div + this.wysiwygEditorDiv = this.doc.createElement('div'); + this.wysiwygEditorDiv.className = "editor wysiwyg_editor"; //TODO: remove editor + this.wysiwygEditorDiv.style.display = "none"; + this.outmostWrapper.appendChild(this.wysiwygEditorDiv); + + // create designmode iframe for WYSIWYG editor + this.editorFrame = this.doc.createElement('iframe'); + this.rdom.setAttributes(this.editorFrame, { + "frameBorder": "0", + "marginWidth": "0", + "marginHeight": "0", + "leftMargin": "0", + "topMargin": "0", + "allowTransparency": "true" + }); + this.wysiwygEditorDiv.appendChild(this.editorFrame); + + var doc = this.editorFrame.contentWindow.document; + if(xq.Browser.isTrident) doc.designMode = 'On'; + + doc.open(); + doc.write(''); + doc.write(''); + doc.write(''); + + // it is needed to force href of pasted content to be an absolute url + if(!xq.Browser.isTrident) doc.write(''); + + doc.write(''); + doc.write('XQuared'); + if(this.config.changeCursorOnLink) doc.write(''); + doc.write(''); + doc.write('

    ' + this.rdom.makePlaceHolderString() + '

    '); + doc.write(''); + doc.close(); + + this.editorWin = this.editorFrame.contentWindow; + this.editorDoc = this.editorWin.document; + this.editorBody = this.editorDoc.body; + this.editorBody.className = "xed"; + + // it is needed to fix IE6 horizontal scrollbar problem + if(xq.Browser.isIE6) { + this.editorDoc.documentElement.style.overflowY='auto'; + this.editorDoc.documentElement.style.overflowX='hidden'; + } + + this.rdom.setWin(this.editorWin); + this.rdom.setRoot(this.editorBody); + this.validator = xq.Validator.createInstance(this.doc.location.href, this.config.urlValidationMode, this.config.allowedTags, this.config.allowedAttributes); + + // hook onsubmit of form + if(this.config.automaticallyHookSubmitEvent && this.contentElement.nodeName == 'TEXTAREA' && this.contentElement.form) { + var original = this.contentElement.form.onsubmit; + + this.contentElement.form.onsubmit = function() { + this.contentElement.value = this.getCurrentContent(true); + if(original) { + return original(); + } else { + return true; + } + }.bind(this); + } + }, + + _addStyleRule: function(selector, rule) { + if(!this.dynamicStyle) { + if(xq.Browser.isTrident) { + this.dynamicStyle = this.doc.createStyleSheet(); + } else { + var style = this.doc.createElement('style'); + this.doc.body.appendChild(style); + this.dynamicStyle = $A(this.doc.styleSheets).last(); + } + } + + if(xq.Browser.isTrident) { + this.dynamicStyle.addRule(selector, rule); + } else { + this.dynamicStyle.insertRule(selector + " {" + rule + "}", this.dynamicStyle.cssRules.length); + } + }, + + _generateDefaultToolbar: function() { + // override image path + this._addStyleRule(".xquared div.toolbar", "background-image: url(" + this.config.imagePathForDefaultToobar + "toolbarBg.gif)"); + this._addStyleRule(".xquared ul.buttons li", "background-image: url(" + this.config.imagePathForDefaultToobar + "toolbarButtonBg.gif)"); + this._addStyleRule(".xquared ul.buttons li.xq_separator", "background-image: url(" + this.config.imagePathForDefaultToobar + "toolbarSeparator.gif)"); + + // outmost container + var container = this.doc.createElement('div'); + container.className = 'toolbar'; + + // button container + var buttons = this.doc.createElement('ul'); + buttons.className = 'buttons'; + container.appendChild(buttons); + + // Generate buttons from map and append it to button container + var cancelMousedown = function(e) {Event.stop(e); return false}; + var map = this.config.defaultToolbarButtonMap; + for(var i = 0; i < map.length; i++) { + for(var j = 0; j < map[i].length; j++) { + var buttonConfig = map[i][j]; + + var li = this.doc.createElement('li'); + buttons.appendChild(li); + li.className = buttonConfig.className; + + var span = this.doc.createElement('span'); + li.appendChild(span); + + var a = this.doc.createElement('a'); + span.appendChild(a); + a.href = '#'; + a.title = buttonConfig.title; + a.handler = buttonConfig.handler; + a.xed = this; + Event.observe(a, 'mousedown', cancelMousedown); + Event.observe(a, 'click', function(e) { + var xed = this.xed; + + if($(this.parentNode).hasClassName('disabled') || xed.toolbarContainer.hasClassName('disabled')) { + Event.stop(e); + return false; + } + + if(xq.Browser.isTrident) xed.focus(); + + var handler = this.handler; + var stop = (typeof handler == "function") ? handler(xed) : eval(handler); + if(stop) { + Event.stop(e); + return false; + } else { + return true; + } + }.bind(a)); + + var img = this.doc.createElement('img'); + a.appendChild(img); + img.src = this.config.imagePathForDefaultToobar + buttonConfig.className + '.gif'; + + if(j == 0 && i != 0) li.className += ' xq_separator'; + } + } + + return container; + }, + + + + ///////////////////////////////////////////// + // Event Management + + _registerEventHandlers: function() { + var events = ['keydown', 'click', 'keyup', 'mouseup', 'contextmenu', 'scroll']; + + if(xq.Browser.isTrident && this.config.changeCursorOnLink) events.push('mousemove'); + if(xq.Browser.isMac && xq.Browser.isGecko) events.push('keypress'); + + for(var i = 0; i < events.length; i++) { + Event.observe(this.getDoc(), events[i], this._handleEvent.bindAsEventListener(this)); + } + }, + + _handleEvent: function(e) { + this._fireOnBeforeEvent(this, e); + + var stop = false; + + var modifiedByCorrection = false; + + if(e.type == 'mousemove' && this.config.changeCursorOnLink) { + // Trident only + var link = !!this.rdom.getParentElementOf(e.srcElement, ["A"]); + if(this.editorBody.contentEditable != link && !this.rdom.hasSelection()) this.editorBody.contentEditable = !link; + } else if(e.type == 'click' && e.button == 0 && this.config.enableLinkClick) { + var a = this.rdom.getParentElementOf(e.target || e.srcElement, ["A"]); + if(a) stop = this.handleClick(e, a); + } else if(e.type == (xq.Browser.isMac && xq.Browser.isGecko ? "keypress" : "keydown")) { + var undoPerformed = false; + + modifiedByCorrection = this.rdom.correctParagraph(); + for(var key in this.config.shortcuts) { + if(!this.config.shortcuts[key].event.matches(e)) continue; + + var handler = this.config.shortcuts[key].handler; + var xed = this; + stop = (typeof handler == "function") ? handler(this) : eval(handler); + + if(key == "undo") undoPerformed = true; + } + } else if(["mouseup", "keyup"].include(e.type)) { + modifiedByCorrection = this.rdom.correctParagraph(); + } else if(["contextmenu"].include(e.type)) { + this._handleContextMenu(e); + } + + if(stop) Event.stop(e); + + this._fireOnCurrentContentChanged(this); + this._fireOnAfterEvent(this, e); + + if(!undoPerformed && !modifiedByCorrection) this.editHistory.onEvent(e); + + return !stop; + }, + + /** + * TODO: remove dup with handleAutocompletion + */ + handleAutocorrection: function() { + var block = this.rdom.getCurrentBlockElement(); + + // TODO: use complete unescape algorithm + var text = this.rdom.getInnerText(block).replace(/ /gi, " "); + + var acs = this.config.autocorrections; + var performed = false; + + var stop = false; + for(var key in acs) { + var ac = acs[key]; + if(ac.criteria(text)) { + try { + this.editHistory.onCommand(); + this.editHistory.disable(); + if(typeof ac.handler == "String") { + var xed = this; + var rdom = this.rdom; + eval(ac.handler); + } else { + stop = ac.handler(this, this.rdom, block, text); + } + this.editHistory.enable(); + } catch(ignored) {} + + block = this.rdom.getCurrentBlockElement(); + text = this.rdom.getInnerText(block); + + performed = true; + if(stop) break; + } + } + + return stop; + }, + + /** + * TODO: remove dup with handleAutocorrection + */ + handleAutocompletion: function() { + var acs = $H(this.config.autocompletions); + if(acs.size() == 0) return; + + if(this.rdom.hasSelection()) { + var text = this.rdom.getSelectionAsText(); + this.rdom.deleteSelection(); + var wrapper = this.rdom.insertNode(this.rdom.createElement("SPAN")); + wrapper.innerHTML = text; + + var marker = this.rdom.pushMarker(); + + var filtered = + acs.map(function(pair) { + return [pair.key, pair.value.criteria(text)]; + }.bind(this)).findAll(function(elem) { + return elem[1] != -1; + }).sortBy(function(elem) { + return elem[1]; + }); + + if(filtered.length == 0) { + this.rdom.popMarker(true); + return; + } + var ac = acs.get(filtered[0][0]); + + this.editHistory.disable(); + } else { + var marker = this.rdom.pushMarker(); + + var filtered = + acs.map(function(pair) { + return [pair.key, this.rdom.testSmartWrap(marker, pair.value.criteria).textIndex]; + }.bind(this)).findAll(function(elem) { + return elem[1] != -1; + }).sortBy(function(elem) { + return elem[1]; + }); + + if(filtered.length == 0) { + this.rdom.popMarker(true); + return; + } + + var ac = acs.get(filtered[0][0]); + + this.editHistory.disable(); + + var wrapper = this.rdom.smartWrap(marker, "SPAN", ac.criteria); + } + + var block = this.rdom.getCurrentBlockElement(); + + // TODO: use complete unescape algorithm + var text = this.rdom.getInnerText(wrapper).replace(/ /gi, " "); + + try { + // call handler + if(typeof ac.handler == "String") { + var xed = this; + var rdom = this.rdom; + eval(ac.handler); + } else { + ac.handler(this, this.rdom, block, wrapper, text); + } + } catch(ignored) {} + + try { + this.rdom.unwrapElement(wrapper); + } catch(ignored) {} + + + if(this.rdom.isEmptyBlock(block)) this.rdom.correctEmptyElement(block); + + this.editHistory.enable(); + this.editHistory.onCommand(); + + this.rdom.popMarker(true); + }, + + /** + * Handles click event + * + * @param {Event} e click event + * @param {Element} target target element(usually has A tag) + */ + handleClick: function(e, target) { + var href = decodeURI(target.href); + if(!xq.Browser.isTrident) { + if(!e.ctrlKey && !e.shiftKey && e.button != 1) { + window.location.href = href; + return true; + } + } else { + if(e.shiftKey) { + window.open(href, "_blank"); + } else { + window.location.href = href; + } + return true; + } + + return false; + }, + + /** + * Show link dialog + * + * TODO: should support modify/unlink + */ + handleLink: function() { + var text = this.rdom.getSelectionAsText() || ''; + var dialog = new xq.controls.FormDialog( + this, + xq.ui_templates.basicLinkDialog, + function(dialog) { + if(text) { + dialog.form.text.value = text; + dialog.form.url.focus(); + dialog.form.url.select(); + } + }, + function(data) { + this.focus(); + + if(xq.Browser.isTrident) { + var rng = this.rdom.rng(); + rng.moveToBookmark(bm); + rng.select(); + } + + if(!data) return; + this.handleInsertLink(false, data.url, data.text, data.text); + }.bind(this) + ); + + if(xq.Browser.isTrident) var bm = this.rdom.rng().getBookmark(); + + dialog.show({position: 'centerOfEditor'}); + + return true; + }, + + /** + * Inserts link or apply link into selected area + * + * @param {boolean} autoSelection if set true and there's no selection, automatically select word to link(if possible) + * @param {String} url url + * @param {String} title title of link + * @param {String} text text of link. If there's a selection(manually or automatically), it will be replaced with this text + * + * @returns {Element} created element + */ + handleInsertLink: function(autoSelection, url, title, text) { + if(autoSelection && !this.rdom.hasSelection()) { + var marker = this.rdom.pushMarker(); + var a = this.rdom.smartWrap(marker, "A", function(text) { + var index = text.lastIndexOf(" "); + return index == -1 ? index : index + 1; + }); + a.href = url; + a.title = title; + if(text) { + a.innerHTML = "" + a.appendChild(this.rdom.createTextNode(text)); + } else if(!a.hasChildNodes()) { + this.rdom.deleteNode(a); + } + this.rdom.popMarker(true); + } else { + text = text || (this.rdom.hasSelection() ? this.rdom.getSelectionAsText() : null); + if(!text) return; + + this.rdom.deleteSelection(); + + var a = this.rdom.createElement('A'); + a.href = url; + a.title = title; + a.appendChild(this.rdom.createTextNode(text)); + this.rdom.insertNode(a); + } + + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + + return true; + }, + + /** + * Called when enter key pressed. + * + * @param {boolean} skipAutocorrection if set true, skips autocorrection + * @param {boolean} forceInsertParagraph if set true, inserts paragraph + */ + handleEnter: function(skipAutocorrection, forceInsertParagraph) { + // If it has selection, perform default action. + if(this.rdom.hasSelection()) return false; + + // Perform autocorrection + if(!skipAutocorrection && this.handleAutocorrection()) return true; + + var atEmptyBlock = this.rdom.isCaretAtEmptyBlock(); + var atStart = atEmptyBlock || this.rdom.isCaretAtBlockStart(); + var atEnd = atEmptyBlock || (!atStart && this.rdom.isCaretAtBlockEnd()); + var atEdge = atEmptyBlock || atStart || atEnd; + + if(!atEdge) { + var block = this.rdom.getCurrentBlockElement(); + var marker = this.rdom.pushMarker(); + + if(this.rdom.isFirstLiWithNestedList(block) && !forceInsertParagraph) { + var parent = block.parentNode; + this.rdom.unwrapElement(block); + block = parent; + } else if(block.nodeName != "LI" && this.rdom.tree.isBlockContainer(block)) { + block = this.rdom.wrapAllInlineOrTextNodesAs("P", block, true).first(); + } + this.rdom.splitElementUpto(marker, block); + + this.rdom.popMarker(true); + } else if(atEmptyBlock) { + this._handleEnterAtEmptyBlock(); + } else { + this._handleEnterAtEdge(atStart, forceInsertParagraph); + } + + return true; + }, + + /** + * Moves current block upward or downward + * + * @param {boolean} up moves current block upward + */ + handleMoveBlock: function(up) { + var block = this.rdom.moveBlock(this.rdom.getCurrentBlockElement(), up); + if(block) { + this.rdom.selectElement(block, false); + block.scrollIntoView(false); + + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + } + return true; + }, + + /** + * Called when tab key pressed + */ + handleTab: function() { + var hasSelection = this.rdom.hasSelection(); + var table = this.rdom.getParentElementOf(this.rdom.getCurrentBlockElement(), ["TABLE"]); + + if(hasSelection) { + this.handleIndent(); + } else if (table && table.className == "datatable") { + this.handleMoveToNextCell(); + } else if (this.rdom.isCaretAtBlockStart()) { + this.handleIndent(); + } else { + this.handleInsertTab(); + } + + return true; + }, + + /** + * Called when shift+tab key pressed + */ + handleShiftTab: function() { + var hasSelection = this.rdom.hasSelection(); + var table = this.rdom.getParentElementOf(this.rdom.getCurrentBlockElement(), ["TABLE"]); + + if(hasSelection) { + this.handleOutdent(); + } else if (table && table.className == "datatable") { + this.handleMoveToPreviousCell(); + } else { + this.handleOutdent(); + } + + return true; + }, + + /** + * Inserts three non-breaking spaces + */ + handleInsertTab: function() { + this.rdom.insertHtml(' '); + this.rdom.insertHtml(' '); + this.rdom.insertHtml(' '); + + return true; + }, + + /** + * Called when delete key pressed + */ + handleDelete: function() { + if(this.rdom.hasSelection() || !this.rdom.isCaretAtBlockEnd()) return false; + return this._handleMerge(true); + }, + + /** + * Called when backspace key pressed + */ + handleBackspace: function() { + if(this.rdom.hasSelection() || !this.rdom.isCaretAtBlockStart()) return false; + return this._handleMerge(false); + }, + + _handleMerge: function(withNext) { + var block = this.rdom.getCurrentBlockElement(); + + // save caret position; + var marker = this.rdom.pushMarker(); + + // perform merge + var merged = this.rdom.mergeElement(block, withNext, withNext); + if(!merged && !withNext) this.rdom.extractOutElementFromParent(block); + + // restore caret position + this.rdom.popMarker(true); + if(merged) this.rdom.correctEmptyElement(merged); + + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + + return !!merged; + }, + + /** + * (in table) Moves caret to the next cell + */ + handleMoveToNextCell: function() { + this._handleMoveToCell("next"); + }, + + /** + * (in table) Moves caret to the previous cell + */ + handleMoveToPreviousCell: function() { + this._handleMoveToCell("prev"); + }, + + /** + * (in table) Moves caret to the above cell + */ + handleMoveToAboveCell: function() { + this._handleMoveToCell("above"); + }, + + /** + * (in table) Moves caret to the below cell + */ + handleMoveToBelowCell: function() { + this._handleMoveToCell("below"); + }, + + _handleMoveToCell: function(dir) { + var block = this.rdom.getCurrentBlockElement(); + var cell = this.rdom.getParentElementOf(block, ["TD", "TH"]); + var table = this.rdom.getParentElementOf(cell, ["TABLE"]); + var rtable = new xq.RichTable(this.rdom, table); + var target = null; + + if(["next", "prev"].include(dir)) { + var toNext = dir == "next"; + target = toNext ? rtable.getNextCellOf(cell) : rtable.getPreviousCellOf(cell); + } else { + var toBelow = dir == "below"; + target = toBelow ? rtable.getBelowCellOf(cell) : rtable.getAboveCellOf(cell); + } + + if(!target) { + var finder = function(node) {return !['TD', 'TH'].include(node.nodeName) && this.tree.isBlock(node) && !this.tree.hasBlocks(node);}.bind(this.rdom); + var exitCondition = function(node) {return this.tree.isBlock(node) && !this.tree.isDescendantOf(this.getRoot(), node)}.bind(this.rdom); + + target = (toNext || toBelow) ? + this.rdom.tree.findForward(cell, finder, exitCondition) : + this.rdom.tree.findBackward(table, finder, exitCondition); + } + + if(target) this.rdom.placeCaretAtStartOf(target); + }, + + /** + * Applies STRONG tag + */ + handleStrongEmphasis: function() { + this.rdom.applyStrongEmphasis(); + + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + + return true; + }, + + /** + * Applies EM tag + */ + handleEmphasis: function() { + this.rdom.applyEmphasis(); + + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + + return true; + }, + + /** + * Applies EM.underline tag + */ + handleUnderline: function() { + this.rdom.applyUnderline(); + + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + + return true; + }, + + /** + * Applies SPAN.strike tag + */ + handleStrike: function() { + this.rdom.applyStrike(); + + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + + return true; + }, + + /** + * Removes all style + */ + handleRemoveFormat: function() { + this.rdom.applyRemoveFormat(); + + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + + return true; + }, + + /** + * Inserts table + * + * @param {Number} cols number of columns + * @param {Number} rows number of rows + * @param {String} headerPosition position of THs. "T" or "L" or "TL". "T" means top, "L" means left. + */ + handleTable: function(cols, rows, headerPositions) { + var cur = this.rdom.getCurrentBlockElement(); + if(this.rdom.getParentElementOf(cur, ["TABLE"])) return true; + + var rtable = xq.RichTable.create(this.rdom, cols, rows, headerPositions); + if(this.rdom.tree.isBlockContainer(cur)) { + var wrappers = this.rdom.wrapAllInlineOrTextNodesAs("P", cur, true); + cur = wrappers.last(); + } + var tableDom = this.rdom.insertNodeAt(rtable.getDom(), cur, "after"); + this.rdom.placeCaretAtStartOf(rtable.getCellAt(0, 0)); + + if(this.rdom.isEmptyBlock(cur)) this.rdom.deleteNode(cur, true); + + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + + return true; + }, + + handleInsertNewRowAt: function(where) { + var cur = this.rdom.getCurrentBlockElement(); + var tr = this.rdom.getParentElementOf(cur, ["TR"]); + if(!tr) return true; + + var table = this.rdom.getParentElementOf(tr, ["TABLE"]); + var rtable = new xq.RichTable(this.rdom, table); + var row = rtable.insertNewRowAt(tr, where); + + this.rdom.placeCaretAtStartOf(row.cells[0]); + return true; + }, + handleInsertNewColumnAt: function(where) { + var cur = this.rdom.getCurrentBlockElement(); + var td = this.rdom.getParentElementOf(cur, ["TD"], true); + if(!td) return true; + + var table = this.rdom.getParentElementOf(td, ["TABLE"]); + var rtable = new xq.RichTable(this.rdom, table); + rtable.insertNewCellAt(td, where); + + this.rdom.placeCaretAtStartOf(cur); + return true; + }, + + handleDeleteRow: function() { + var cur = this.rdom.getCurrentBlockElement(); + var tr = this.rdom.getParentElementOf(cur, ["TR"]); + if(!tr) return true; + + var table = this.rdom.getParentElementOf(tr, ["TABLE"]); + var rtable = new xq.RichTable(this.rdom, table); + var blockToMove = rtable.deleteRow(tr); + + this.rdom.placeCaretAtStartOf(blockToMove); + return true; + }, + + handleDeleteColumn: function() { + var cur = this.rdom.getCurrentBlockElement(); + var td = this.rdom.getParentElementOf(cur, ["TD"], true); + if(!td) return true; + + var table = this.rdom.getParentElementOf(td, ["TABLE"]); + var rtable = new xq.RichTable(this.rdom, table); + rtable.deleteCell(td); + + return true; + }, + + /** + * Performs block indentation + */ + handleIndent: function() { + if(this.rdom.hasSelection()) { + var blocks = this.rdom.getBlockElementsAtSelectionEdge(true, true); + if(blocks.first() != blocks.last()) { + var affected = this.rdom.indentElements(blocks.first(), blocks.last()); + this.rdom.selectBlocksBetween(affected.first(), affected.last()); + + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + + return true; + } + } + + var block = this.rdom.getCurrentBlockElement(); + var affected = this.rdom.indentElement(block); + + if(affected) { + this.rdom.placeCaretAtStartOf(affected); + + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + } + + return true; + }, + + /** + * Performs block outdentation + */ + handleOutdent: function() { + if(this.rdom.hasSelection()) { + var blocks = this.rdom.getBlockElementsAtSelectionEdge(true, true); + if(blocks.first() != blocks.last()) { + var affected = this.rdom.outdentElements(blocks.first(), blocks.last()); + this.rdom.selectBlocksBetween(affected.first(), affected.last()); + + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + + return true; + } + } + + var block = this.rdom.getCurrentBlockElement(); + var affected = this.rdom.outdentElement(block); + + if(affected) { + this.rdom.placeCaretAtStartOf(affected); + + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + } + + return true; + }, + + /** + * Applies list. + * + * @param {String} type "UL" or "OL" or "CODE". CODE generates OL.code + */ + handleList: function(type) { + if(this.rdom.hasSelection()) { + var blocks = this.rdom.getBlockElementsAtSelectionEdge(true, true); + if(blocks.first() != blocks.last()) { + blocks = this.rdom.applyLists(blocks.first(), blocks.last(), type); + } else { + blocks[0] = blocks[1] = this.rdom.applyList(blocks.first(), type); + } + this.rdom.selectBlocksBetween(blocks.first(), blocks.last()); + } else { + var block = this.rdom.applyList(this.rdom.getCurrentBlockElement(), type); + this.rdom.placeCaretAtStartOf(block); + } + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + + return true; + }, + + /** + * Applies justification + * + * @param {String} dir "left", "center", "right" or "both" + */ + handleJustify: function(dir) { + var block = this.rdom.getCurrentBlockElement(); + var dir = (dir == "left" || dir == "both") && (block.style.textAlign == "left" || block.style.textAlign == "") ? "both" : dir; + + if(this.rdom.hasSelection()) { + var blocks = this.rdom.getSelectedBlockElements(); + this.rdom.justifyBlocks(blocks, dir); + this.rdom.selectBlocksBetween(blocks.first(), blocks.last()); + } else { + this.rdom.justifyBlock(block, dir); + } + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + + return true; + }, + + /** + * Removes current block element + */ + handleRemoveBlock: function() { + var block = this.rdom.getCurrentBlockElement(); + var blockToMove = this.rdom.removeBlock(block); + this.rdom.placeCaretAtStartOf(blockToMove); + blockToMove.scrollIntoView(false); + }, + + /** + * Applies background color + * + * @param {String} color CSS color string + */ + handleBackgroundColor: function(color) { + if(color) { + this.rdom.applyBackgroundColor(color); + + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + } else { + var dialog = new xq.controls.FormDialog( + this, + xq.ui_templates.basicColorPickerDialog, + function(dialog) {}, + function(data) { + this.focus(); + + if(xq.Browser.isTrident) { + var rng = this.rdom.rng(); + rng.moveToBookmark(bm); + rng.select(); + } + + if(!data) return; + + this.handleBackgroundColor(data.color); + }.bind(this) + ); + + if(xq.Browser.isTrident) var bm = this.rdom.rng().getBookmark(); + + dialog.show({position: 'centerOfEditor'}); + } + return true; + }, + + /** + * Applies foreground color + * + * @param {String} color CSS color string + */ + handleForegroundColor: function(color) { + if(color) { + this.rdom.applyForegroundColor(color); + + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + } else { + var dialog = new xq.controls.FormDialog( + this, + xq.ui_templates.basicColorPickerDialog, + function(dialog) {}, + function(data) { + this.focus(); + + if(xq.Browser.isTrident) { + var rng = this.rdom.rng(); + rng.moveToBookmark(bm); + rng.select(); + } + + if(!data) return; + + this.handleForegroundColor(data.color); + }.bind(this) + ); + + if(xq.Browser.isTrident) var bm = this.rdom.rng().getBookmark(); + + dialog.show({position: 'centerOfEditor'}); + } + return true; + }, + + /** + * Applies superscription + */ + handleSuperscription: function() { + this.rdom.applySuperscription(); + + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + + return true; + }, + + /** + * Applies subscription + */ + handleSubscription: function() { + this.rdom.applySubscription(); + + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + + return true; + }, + + /** + * Change of wrap current block's tag + */ + handleApplyBlock: function(tagName) { + if(this.rdom.hasSelection()) { + var blocks = this.rdom.getBlockElementsAtSelectionEdge(true, true); + if(blocks.first() != blocks.last()) { + var applied = this.rdom.applyTagIntoElements(tagName, blocks.first(), blocks.last()); + this.rdom.selectBlocksBetween(applied.first(), applied.last()); + + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + + return true; + } + } + + var block = this.rdom.getCurrentBlockElement(); + this.rdom.pushMarker(); + var applied = + this.rdom.applyTagIntoElement(tagName, block) || + block; + this.rdom.popMarker(true); + + if(this.rdom.isEmptyBlock(applied)) { + this.rdom.correctEmptyElement(applied); + this.rdom.placeCaretAtStartOf(applied); + } + + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + + return true; + }, + + /** + * Inserts seperator (HR) + */ + handleSeparator: function() { + this.rdom.collapseSelection(); + + var curBlock = this.rdom.getCurrentBlockElement(); + var atStart = this.rdom.isCaretAtBlockStart(); + if(this.rdom.tree.isBlockContainer(curBlock)) curBlock = this.rdom.wrapAllInlineOrTextNodesAs("P", curBlock, true)[0]; + + this.rdom.insertNodeAt(this.rdom.createElement("HR"), curBlock, atStart ? "before" : "after"); + this.rdom.placeCaretAtStartOf(curBlock); + + // add undo history + var historyAdded = this.editHistory.onCommand(); + this._fireOnCurrentContentChanged(this); + + return true; + }, + + /** + * Performs UNDO + */ + handleUndo: function() { + var performed = this.editHistory.undo(); + this._fireOnCurrentContentChanged(this); + + var curBlock = this.rdom.getCurrentBlockElement(); + if(!xq.Browser.isTrident && curBlock) { + curBlock.scrollIntoView(false); + } + return true; + }, + + /** + * Performs REDO + */ + handleRedo: function() { + var performed = this.editHistory.redo(); + this._fireOnCurrentContentChanged(this); + + var curBlock = this.rdom.getCurrentBlockElement(); + if(!xq.Browser.isTrident && curBlock) { + curBlock.scrollIntoView(false); + } + return true; + }, + + + + _handleContextMenu: function(e) { + if (xq.Browser.isWebkit) { + if (e.metaKey || Event.isLeftClick(e)) return false; + } else if (e.shiftKey || e.ctrlKey || e.altKey) { + return false; + } + + var x=Event.pointerX(e); + var y=Event.pointerY(e); + var pos=Position.cumulativeOffset(this.getFrame()); + x+=pos[0]; + y+=pos[1]; + this._contextMenuTargetElement = e.target || e.srcElement; + + //TODO: Safari on Windows doesn't work with context key(app key) + if (!x || !y || xq.Browser.isTrident) { + var pos = Position.cumulativeOffset(this._contextMenuTargetElement); + var posFrame = Position.cumulativeOffset(this.getFrame()); + x = pos[0] + posFrame[0] - this.getDoc().documentElement.scrollLeft; + y = pos[1] + posFrame[1] - this.getDoc().documentElement.scrollTop; + } + + if (!xq.Browser.isTrident) { + var doc = this.getDoc(); + var body = this.getBody(); + + x -= doc.documentElement.scrollLeft; + y -= doc.documentElement.scrollTop; + + if (doc != body) { + x -= body.scrollLeft; + y -= body.scrollTop; + } + } + + for(var cmh in this.config.contextMenuHandlers) { + var stop = this.config.contextMenuHandlers[cmh].handler(this, this._contextMenuTargetElement, x, y); + if(stop) { + Event.stop(e); + return true; + } + } + + return false; + }, + + showContextMenu: function(menuItems, x, y) { + if (!menuItems || menuItems.length <= 0) return; + + if (!this._contextMenuContainer) { + this._contextMenuContainer = this.doc.createElement('UL'); + this._contextMenuContainer.className = 'xqContextMenu'; + this._contextMenuContainer.style.display='none'; + + Event.observe(this.doc, 'click', this._contextMenuClicked.bindAsEventListener(this)); + Event.observe(this.rdom.getDoc(), 'click', this.hideContextMenu.bindAsEventListener(this)); + + this.body.appendChild(this._contextMenuContainer); + } else { + while (this._contextMenuContainer.childNodes.length > 0) + this._contextMenuContainer.removeChild(this._contextMenuContainer.childNodes[0]); + } + + for (var i=0; i < menuItems.length; i++) { + menuItems[i]._node = this._addContextMenuItem(menuItems[i]); + } + + this._contextMenuContainer.style.display='block'; + this._contextMenuContainer.style.left=Math.min(Math.max(this.doc.body.scrollWidth, this.doc.documentElement.clientWidth)-this._contextMenuContainer.offsetWidth, x)+'px'; + this._contextMenuContainer.style.top=Math.min(Math.max(this.doc.body.scrollHeight, this.doc.documentElement.clientHeight)-this._contextMenuContainer.offsetHeight, y)+'px'; + + this._contextMenuItems = menuItems; + }, + + hideContextMenu: function() { + if (this._contextMenuContainer) + this._contextMenuContainer.style.display='none'; + }, + + _addContextMenuItem: function(item) { + if (!this._contextMenuContainer) throw "No conext menu container exists"; + + var node = this.doc.createElement('LI'); + if (item.disabled) node.className += ' disabled'; + + if (item.title == '----') { + node.innerHTML = ' '; + node.className = 'separator'; + } else { + if(item.handler) { + node.innerHTML = ''+(item.title.toString().escapeHTML())+''; + } else { + node.innerHTML = (item.title.toString().escapeHTML()); + } + } + + if(item.className) node.className = item.className; + + this._contextMenuContainer.appendChild(node); + + return node; + }, + + _contextMenuClicked: function(e) { + this.hideContextMenu(); + + if (!this._contextMenuContainer) return; + + var node = Event.findElement(e, 'LI'); + if (!node || !this.rdom.tree.isDescendantOf(this._contextMenuContainer, node)) return; + + for (var i=0; i < this._contextMenuItems.length; i++) { + if (this._contextMenuItems[i]._node == node) { + var handler = this._contextMenuItems[i].handler; + if (!this._contextMenuItems[i].disabled && handler) { + var xed = this; + var element = this._contextMenuTargetElement; + if(typeof handler == "function") { + handler(xed, element); + } else { + eval(handler); + } + } + break; + } + } + }, + + /** + * Inserts HTML template + * + * @param {String} html Template string. It should have single root element + * @returns {Element} inserted element + */ + insertTemplate: function(html) { + return this.rdom.insertHtml(this._processTemplate(html)); + }, + + /** + * Places given HTML template nearby target. + * + * @param {String} html Template string. It should have single root element + * @param {Node} target Target node. + * @param {String} where Possible values: "before", "start", "end", "after" + * + * @returns {Element} Inserted element. + */ + insertTemplateAt: function(html, target, where) { + return this.rdom.insertHtmlAt(this._processTemplate(html), target, where); + }, + + _processTemplate: function(html) { + // apply template processors + var tps = $H(this.getTemplateProcessors()).values(); + for(var i = 0; i < tps.length; i++) { + html = tps[i].handler(html); + } + + // remove all whitespace characters between block tags + return html = this.removeUnnecessarySpaces(html); + }, + + + + /** @private */ + _handleEnterAtEmptyBlock: function() { + var block = this.rdom.getCurrentBlockElement(); + if(this.rdom.tree.isTableCell(block) && this.rdom.isFirstBlockOfBody(block)) { + block = this.rdom.insertNodeAt(this.rdom.makeEmptyParagraph(), this.rdom.getRoot(), "start"); + } else { + block = + this.rdom.outdentElement(block) || + this.rdom.extractOutElementFromParent(block) || + this.rdom.replaceTag("P", block) || + this.rdom.insertNewBlockAround(block); + } + + this.rdom.placeCaretAtStartOf(block); + if(!xq.Browser.isTrident) block.scrollIntoView(false); + }, + + /** @private */ + _handleEnterAtEdge: function(atStart, forceInsertParagraph) { + var block = this.rdom.getCurrentBlockElement(); + var blockToPlaceCaret; + + if(atStart && this.rdom.isFirstBlockOfBody(block)) { + blockToPlaceCaret = this.rdom.insertNodeAt(this.rdom.makeEmptyParagraph(), this.rdom.getRoot(), "start"); + } else { + if(this.rdom.tree.isTableCell(block)) forceInsertParagraph = true; + var newBlock = this.rdom.insertNewBlockAround(block, atStart, forceInsertParagraph ? "P" : null); + blockToPlaceCaret = !atStart ? newBlock : newBlock.nextSibling; + } + + this.rdom.placeCaretAtStartOf(blockToPlaceCaret); + if(!xq.Browser.isTrident) blockToPlaceCaret.scrollIntoView(false); + } +}); +xq.Browser = { + // By Layout Engines + isTrident: navigator.appName == "Microsoft Internet Explorer", + isWebkit: navigator.userAgent.indexOf('AppleWebKit/') > -1, + isGecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1, + isKHTML: navigator.userAgent.indexOf('KHTML') != -1, + isPresto: navigator.appName == "Opera", + + // By Platforms + isMac: navigator.userAgent.indexOf("Macintosh") != -1, + isUbuntu: navigator.userAgent.indexOf('Ubuntu') != -1, + + // By Browsers + isIE: navigator.appName == "Microsoft Internet Explorer", + isIE6: navigator.userAgent.indexOf('MSIE 6') != -1, + isIE7: navigator.userAgent.indexOf('MSIE 7') != -1 +}; +xq.Shortcut = Class.create({ + initialize: function(keymapOrExpression) { + this.keymap = (typeof keymapOrExpression == "string") ? + xq.Shortcut.interprete(keymapOrExpression).keymap : + keymapOrExpression; + }, + matches: function(e) { + var which = xq.Browser.isGecko && xq.Browser.isMac ? (e.keyCode + "_" + e.charCode) : e.keyCode; + + var keyMatches = + (this.keymap.which == which) || + (this.keymap.which == 32 && which == 25); // 25 is SPACE in Type-3 keyboard. + + if(typeof e.metaKey == "undefined") e.metaKey = false; + + var modifierMatches = + (typeof this.keymap.shiftKey == "undefined" || this.keymap.shiftKey == e.shiftKey) && + (typeof this.keymap.altKey == "undefined" || this.keymap.altKey == e.altKey) && + (typeof this.keymap.ctrlKey == "undefined" || this.keymap.ctrlKey == e.ctrlKey) && + (typeof this.keymap.metaKey == "undefined" || this.keymap.metaKey == e.metaKey) + + return modifierMatches && keyMatches; + } +}); + +xq.Shortcut.interprete = function(expression) { + expression = expression.toUpperCase(); + + var which = xq.Shortcut._interpreteWhich(expression.split("+").pop()); + var ctrlKey = xq.Shortcut._interpreteModifier(expression, "CTRL"); + var altKey = xq.Shortcut._interpreteModifier(expression, "ALT"); + var shiftKey = xq.Shortcut._interpreteModifier(expression, "SHIFT"); + var metaKey = xq.Shortcut._interpreteModifier(expression, "META"); + + var keymap = {}; + + keymap.which = which; + if(typeof ctrlKey != "undefined") keymap.ctrlKey = ctrlKey; + if(typeof altKey != "undefined") keymap.altKey = altKey; + if(typeof shiftKey != "undefined") keymap.shiftKey = shiftKey; + if(typeof metaKey != "undefined") keymap.metaKey = metaKey; + + return new xq.Shortcut(keymap); +} + +xq.Shortcut._interpreteModifier = function(expression, modifierName) { + return expression.match("\\(" + modifierName + "\\)") ? + undefined : + expression.match(modifierName) ? + true : false; +} +xq.Shortcut._interpreteWhich = function(keyName) { + var which = keyName.length == 1 ? + ((xq.Browser.isMac && xq.Browser.isGecko) ? "0_" + keyName.toLowerCase().charCodeAt(0) : keyName.charCodeAt(0)) : + xq.Shortcut._keyNames[keyName]; + + if(typeof which == "undefined") throw "Unknown special key name: [" + keyName + "]" + + return which; +} +xq.Shortcut._keyNames = + xq.Browser.isMac && xq.Browser.isGecko ? + { + BACKSPACE: "8_0", + TAB: "9_0", + RETURN: "13_0", + ENTER: "13_0", + ESC: "27_0", + SPACE: "0_32", + LEFT: "37_0", + UP: "38_0", + RIGHT: "39_0", + DOWN: "40_0", + DELETE: "46_0", + HOME: "36_0", + END: "35_0", + PAGEUP: "33_0", + PAGEDOWN: "34_0", + COMMA: "0_44", + HYPHEN: "0_45", + EQUAL: "0_61", + PERIOD: "0_46", + SLASH: "0_47", + F1: "112_0", + F2: "113_0", + F3: "114_0", + F4: "115_0", + F5: "116_0", + F6: "117_0", + F7: "118_0", + F8: "119_0" + } + : + { + BACKSPACE: 8, + TAB: 9, + RETURN: 13, + ENTER: 13, + ESC: 27, + SPACE: 32, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, + DELETE: 46, + HOME: 36, + END: 35, + PAGEUP: 33, + PAGEDOWN: 34, + COMMA: 188, + HYPHEN: xq.Browser.isTrident ? 189 : 109, + EQUAL: xq.Browser.isTrident ? 187 : 61, + PERIOD: 190, + SLASH: 191, + F1:112, + F2:113, + F3:114, + F4:115, + F5:116, + F6:117, + F7:118, + F8:119, + F9:120, + F10:121, + F11:122, + F12:123 + } +/** + * Provide various tree operations. + * + * TODO: Add specs + */ +xq.DomTree = Class.create({ + initialize: function() { + this._blockTags = ["DIV", "DD", "LI", "ADDRESS", "CAPTION", "DT", "H1", "H2", "H3", "H4", "H5", "H6", "HR", "P", "BODY", "BLOCKQUOTE", "PRE", "PARAM", "DL", "OL", "UL", "TABLE", "THEAD", "TBODY", "TR", "TH", "TD"]; + this._blockContainerTags = ["DIV", "DD", "LI", "BODY", "BLOCKQUOTE", "UL", "OL", "DL", "TABLE", "THEAD", "TBODY", "TR", "TH", "TD"]; + this._listContainerTags = ["OL", "UL", "DL"]; + this._tableCellTags = ["TH", "TD"]; + this._blockOnlyContainerTags = ["BODY", "BLOCKQUOTE", "UL", "OL", "DL", "TABLE", "THEAD", "TBODY", "TR"]; + this._atomicTags = ["IMG", "OBJECT", "BR", "HR"]; + }, + + getBlockTags: function() { + return this._blockTags; + }, + + /** + * Find common ancestor(parent) and his immediate children(left and right). + * + * A --- B -+- C -+- D -+- E + * | + * +- F -+- G + * + * For example: + * > findCommonAncestorAndImmediateChildrenOf("E", "G") + * + * will return + * + * > {parent:"B", left:"C", right:"F"} + */ + findCommonAncestorAndImmediateChildrenOf: function(left, right) { + if(left.parentNode == right.parentNode) { + return { + left:left, + right:right, + parent:left.parentNode + }; + } else { + var parentsOfLeft = this.collectParentsOf(left, true); + var parentsOfRight = this.collectParentsOf(right, true); + var ca = this.getCommonAncestor(parentsOfLeft, parentsOfRight); + + var leftAncestor = parentsOfLeft.find(function(node) {return node.parentNode == ca}); + var rightAncestor = parentsOfRight.find(function(node) {return node.parentNode == ca}); + + return { + left:leftAncestor, + right:rightAncestor, + parent:ca + }; + } + }, + + /** + * Find leaves at edge. + * + * A --- B -+- C -+- D -+- E + * | + * +- F -+- G + * + * For example: + * > getLeavesAtEdge("A") + * + * will return + * + * > ["E", "G"] + */ + getLeavesAtEdge: function(element) { + if(!element.hasChildNodes()) return [null, null]; + + var findLeft = function(el) { + for (var i = 0; i < el.childNodes.length; i++) { + if (el.childNodes[i].nodeType == 1 && this.isBlock(el.childNodes[i])) return findLeft(el.childNodes[i]); + } + return el; + }.bind(this); + + var findRight=function(el) { + for (var i = el.childNodes.length; i--;) { + if (el.childNodes[i].nodeType == 1 && this.isBlock(el.childNodes[i])) return findRight(el.childNodes[i]); + } + return el; + }.bind(this); + + var left = findLeft(element); + var right = findRight(element); + return [left == element ? null : left, right == element ? null : right]; + }, + + getCommonAncestor: function(parents1, parents2) { + for(var i = 0; i < parents1.length; i++) { + for(var j = 0; j < parents2.length; j++) { + if(parents1[i] == parents2[j]) return parents1[i]; + } + } + }, + + collectParentsOf: function(node, includeSelf, exitCondition) { + var parents = []; + if(includeSelf) parents.push(node); + + while((node = node.parentNode) && (node.nodeName != "HTML") && !(typeof exitCondition == "function" && exitCondition(node))) parents.push(node); + return parents; + }, + + isDescendantOf: function(parent, child) { + if(parent.length > 0) { + for(var i = 0; i < parent.length; i++) { + if(this.isDescendantOf(parent[i], child)) return true; + } + return false; + } + + if(parent == child) return false; + + while (child = child.parentNode) + if (child == parent) return true; + return false; + }, + + /** + * Perform tree walking (foreward) + */ + walkForward: function(node) { + if(node.hasChildNodes()) return node.firstChild; + if(node.nextSibling) return node.nextSibling; + + while(node = node.parentNode) { + if(node.nextSibling) return node.nextSibling; + } + + return null; + }, + + /** + * Perform tree walking (backward) + */ + walkBackward: function(node) { + if(node.previousSibling) { + node = node.previousSibling; + while(node.hasChildNodes()) {node = node.lastChild;} + return node; + } + + return node.parentNode; + }, + + /** + * Perform tree walking (to next siblings) + */ + walkNext: function(node) {return node.nextSibling}, + + /** + * Perform tree walking (to next siblings) + */ + walkPrev: function(node) {return node.previousSibling}, + + /** + * Returns true if target is followed by start + */ + checkTargetForward: function(start, target) { + return this._check(start, this.walkForward, target); + }, + + /** + * Returns true if start is followed by target + */ + checkTargetBackward: function(start, target) { + return this._check(start, this.walkBackward, target); + }, + + findForward: function(start, condition, exitCondition) { + return this._find(start, this.walkForward, condition, exitCondition); + }, + + findBackward: function(start, condition, exitCondition) { + return this._find(start, this.walkBackward, condition, exitCondition); + }, + + /** @private */ + _check: function(start, direction, target) { + if(start == target) return false; + + while(start = direction(start)) { + if(start == target) return true; + } + return false; + }, + + /** @private */ + _find: function(start, direction, condition, exitCondition) { + while(start = direction(start)) { + if(exitCondition && exitCondition(start)) return null; + if(condition(start)) return start; + } + return null; + }, + + /** + * Walks Forward through DOM tree from start to end, and collects all nodes that matches with a filter. + * If no filter provided, it just collects all nodes. + * + * @param function filter a filter function + */ + collectNodesBetween: function(start, end, filter) { + if(start == end) return [start, end].findAll(filter || function() {return true}); + + var nodes = this.collectForward(start, function(node) {return node == end}, filter); + if( + start != end && + typeof filter == "function" && + filter(end) + ) nodes.push(end); + + return nodes; + }, + + collectForward: function(start, exitCondition, filter) { + return this.collect(start, this.walkForward, exitCondition, filter); + }, + + collectBackward: function(start, exitCondition, filter) { + return this.collect(start, this.walkBackward, exitCondition, filter); + }, + + collectNext: function(start, exitCondition, filter) { + return this.collect(start, this.walkNext, exitCondition, filter); + }, + + collectPrev: function(start, exitCondition, filter) { + return this.collect(start, this.walkPrev, exitCondition, filter); + }, + + collect: function(start, next, exitCondition, filter) { + var nodes = [start]; + + while(true) { + start = next(start); + if( + (start == null) || + (typeof exitCondition == "function" && exitCondition(start)) + ) break; + + nodes.push(start); + } + + return (typeof filter == "function") ? nodes.findAll(filter) : nodes; + }, + + + hasBlocks: function(element) { + var nodes = element.childNodes; + for(var i = 0; i < nodes.length; i++) { + if(this.isBlock(nodes[i])) return true; + } + return false; + }, + + hasMixedContents: function(element) { + if(!this.isBlock(element)) return false; + if(!this.isBlockContainer(element)) return false; + + var hasTextOrInline = false; + var hasBlock = false; + for(var i = 0; i < element.childNodes.length; i++) { + var node = element.childNodes[i]; + if(!hasTextOrInline && this.isTextOrInlineNode(node)) hasTextOrInline = true; + if(!hasBlock && this.isBlock(node)) hasBlock = true; + + if(hasTextOrInline && hasBlock) break; + } + if(!hasTextOrInline || !hasBlock) return false; + + return true; + }, + + isBlockOnlyContainer: function(element) { + if(!element) return false; + return this._blockOnlyContainerTags.include(typeof element == 'string' ? element : element.nodeName); + }, + + isTableCell: function(element) { + if(!element) return false; + return this._tableCellTags.include(typeof element == 'string' ? element : element.nodeName); + }, + + isBlockContainer: function(element) { + if(!element) return false; + return this._blockContainerTags.include(typeof element == 'string' ? element : element.nodeName); + }, + + isHeading: function(element) { + if(!element) return false; + return (typeof element == 'string' ? element : element.nodeName).match(/H\d/); + }, + + isBlock: function(element) { + if(!element) return false; + return this._blockTags.include(typeof element == 'string' ? element : element.nodeName); + }, + + isAtomic: function(element) { + if(!element) return false; + return this._atomicTags.include(typeof element == 'string' ? element : element.nodeName); + }, + + isListContainer: function(element) { + if(!element) return false; + return this._listContainerTags.include(typeof element == 'string' ? element : element.nodeName); + }, + + isTextOrInlineNode: function(node) { + return node && (node.nodeType == 3 || !this.isBlock(node)); + } +}); +/** + * Encapsulates browser incompatibility problem and provides rich set of DOM manipulation API. + * + * RichDom provides basic CRUD + Advanced DOM manipulation API, various query methods and caret/selection management API + */ +xq.RichDom = Class.create({ + /** + * Initialize RichDom. Target window and root element should be set after initialization. See setWin and setRoot. + * + * @constructor + */ + initialize: function() { + /** + * {xq.DomTree} instance of DomTree + */ + this.tree = new xq.DomTree(); + + this._lastMarkerId = 0; + }, + + + + /** + * @param {Window} win Browser's window object + */ + setWin: function(win) { + if(!win) throw "[win] is null"; + this.win = win; + }, + + /** + * @param {Element} root Root element + */ + setRoot: function(root) { + if(!root) throw "[root] is null"; + if(this.win && (root.ownerDocument != this.win.document)) throw "root.ownerDocument != this.win.document"; + this.root = root; + this.doc = this.root.ownerDocument; + }, + + /** + * @returns Browser's window object. + */ + getWin: function() {return this.win}, + + /** + * @returns Document object of root element. + */ + getDoc: function() {return this.doc}, + + /** + * @returns Root element. + */ + getRoot: function() {return this.root}, + + + + ///////////////////////////////////////////// + // CRUDs + + clearRoot: function() { + this.root.innerHTML = ""; + this.root.appendChild(this.makeEmptyParagraph()); + }, + + /** + * Removes place holders and empty text nodes of given element. + * + * @param {Element} element target element + */ + removePlaceHoldersAndEmptyNodes: function(element) { + var children = element.childNodes; + if(!children) return; + var stopAt = this.getBottommostLastChild(element); + if(!stopAt) return; + stopAt = this.tree.walkForward(stopAt); + + while(true) { + if(!element || element == stopAt) break; + + if( + this.isPlaceHolder(element) || + (element.nodeType == 3 && element.nodeValue == "") || + (!this.getNextSibling(element) && element.nodeType == 3 && element.nodeValue.strip() == "") + ) { + var deleteTarget = element; + element = this.tree.walkForward(element); + + this.deleteNode(deleteTarget); + } else { + element = this.tree.walkForward(element); + } + } + }, + + /** + * Sets multiple attributes into element at once + * + * @param {Element} element target element + * @param {Object} map key-value pairs + */ + setAttributes: function(element, map) { + for(key in map) element.setAttribute(key, map[key]); + }, + + /** + * Creates textnode by given node value. + * + * @param {String} value value of textnode + * @returns {Node} Created text node + */ + createTextNode: function(value) {return this.doc.createTextNode(value);}, + + /** + * Creates empty element by given tag name. + * + * @param {String} tagName name of tag + * @returns {Element} Created element + */ + createElement: function(tagName) {return this.doc.createElement(tagName);}, + + /** + * Creates element from HTML string + * + * @param {String} html HTML string + * @returns {Element} Created element + */ + createElementFromHtml: function(html) { + var node = this.createElement("div"); + node.innerHTML = html; + if(node.childNodes.length != 1) { + throw "Illegal HTML fragment"; + } + return this.getFirstChild(node); + }, + + /** + * Deletes node from DOM tree. + * + * @param {Node} node Target node which should be deleted + * @param {boolean} deleteEmptyParentsRecursively Recursively delete empty parent elements + * @param {boolean} correctEmptyParent Call #correctEmptyElement on empty parent element after deletion + */ + deleteNode: function(node, deleteEmptyParentsRecursively, correctEmptyParent) { + if(!node || !node.parentNode) return; + + var parent = node.parentNode; + parent.removeChild(node); + + if(deleteEmptyParentsRecursively) { + while(!parent.hasChildNodes()) { + node = parent; + parent = node.parentNode; + if(!parent || this.getRoot() == node) break; + parent.removeChild(node); + } + } + + if(correctEmptyParent && this.isEmptyBlock(parent)) { + parent.innerHTML = ""; + this.correctEmptyElement(parent); + } + }, + + /** + * Inserts given node into current caret position + * + * @param {Node} node Target node + * @returns {Node} Inserted node. It could be different with given node. + */ + insertNode: function(node) {throw "Not implemented"}, + + /** + * Inserts given html into current caret position + * + * @param {String} html HTML string + * @returns {Node} Inserted node. It could be different with given node. + */ + insertHtml: function(html) { + return this.insertNode(this.createElementFromHtml(html)); + }, + + /** + * Creates textnode from given text and inserts it into current caret position + * + * @param {String} text Value of textnode + * @returns {Node} Inserted node + */ + insertText: function(text) { + this.insertNode(this.createTextNode(text)); + }, + + /** + * Places given node nearby target. + * + * @param {Node} node Node to be inserted. + * @param {Node} target Target node. + * @param {String} where Possible values: "before", "start", "end", "after" + * @param {boolean} performValidation Validate node if needed. For example when P placed into UL, its tag name automatically replaced with LI + * + * @returns {Node} Inserted node. It could be different with given node. + */ + insertNodeAt: function(node, target, where, performValidation) { + if( + ["HTML", "HEAD"].include(target.nodeName) || + ["BODY"].include(target.nodeName) && ["before", "after"].include(where) + ) throw "Illegal argument. Cannot move node[" + node.nodeName + "] to '" + where + "' of target[" + target.nodeName + "]" + + var object; + var message; + var secondParam; + + switch(where.toLowerCase()) { + case "before": + object = target.parentNode; + message = 'insertBefore'; + secondParam = target; + break + case "start": + if(target.firstChild) { + object = target; + message = 'insertBefore'; + secondParam = target.firstChild; + } else { + object = target; + message = 'appendChild'; + } + break + case "end": + object = target; + message = 'appendChild'; + break + case "after": + if(target.nextSibling) { + object = target.parentNode; + message = 'insertBefore'; + secondParam = target.nextSibling; + } else { + object = target.parentNode; + message = 'appendChild'; + } + break + } + + if(performValidation && this.tree.isListContainer(object) && node.nodeName != "LI") { + var li = this.createElement("LI"); + li.appendChild(node); + node = li; + object[message](node, secondParam); + } else if(performValidation && !this.tree.isListContainer(object) && node.nodeName == "LI") { + this.wrapAllInlineOrTextNodesAs("P", node, true); + var div = this.createElement("DIV"); + this.moveChildNodes(node, div); + this.deleteNode(node); + object[message](div, secondParam); + node = this.unwrapElement(div, true); + } else { + object[message](node, secondParam); + } + + return node; + }, + + /** + * Creates textnode from given text and places given node nearby target. + * + * @param {String} text Text to be inserted. + * @param {Node} target Target node. + * @param {String} where Possible values: "before", "start", "end", "after" + * + * @returns {Node} Inserted node. + */ + insertTextAt: function(text, target, where) { + return this.insertNodeAt(this.createTextNode(text), target, where); + }, + + /** + * Creates element from given HTML string and places given it nearby target. + * + * @param {String} html HTML to be inserted. + * @param {Node} target Target node. + * @param {String} where Possible values: "before", "start", "end", "after" + * + * @returns {Node} Inserted node. + */ + insertHtmlAt: function(html, target, where) { + return this.insertNodeAt(this.createElementFromHtml(html), target, where); + }, + + /** + * Replaces element's tag by removing current element and creating new element by given tag name. + * + * @param {String} tag New tag name + * @param {Element} element Target element + * + * @returns {Element} Replaced element + */ + replaceTag: function(tag, element) { + if(element.nodeName == tag) return null; + if(this.tree.isTableCell(element)) return null; + + var newElement = this.createElement(tag); + this.moveChildNodes(element, newElement); + this.copyAttributes(element, newElement, true); + element.parentNode.replaceChild(newElement, element); + + if(!newElement.hasChildNodes()) this.correctEmptyElement(newElement); + + return newElement; + }, + + /** + * Unwraps unnecessary paragraph. + * + * Unnecessary paragraph is P which is the only child of given container element. + * For example, P which is contained by LI and is the only child is the unnecessary paragraph. + * But if given container element is a block-only-container(BLOCKQUOTE, BODY), this method does nothing. + * + * @param {Element} element Container element + * @returns {boolean} True if unwrap performed. + */ + unwrapUnnecessaryParagraph: function(element) { + if(!element) return false; + + if(!this.tree.isBlockOnlyContainer(element) && element.childNodes.length == 1 && element.firstChild.nodeName == "P" && !this.hasImportantAttributes(element.firstChild)) { + var p = element.firstChild; + this.moveChildNodes(p, element); + this.deleteNode(p); + return true; + } + return false; + }, + + /** + * Unwraps element by extracting all children out and removing the element. + * + * @param {Element} element Target element + * @param {boolean} wrapInlineAndTextNodes Wrap all inline and text nodes with P before unwrap + * @returns {Node} First child of unwrapped element + */ + unwrapElement: function(element, wrapInlineAndTextNodes) { + if(wrapInlineAndTextNodes) this.wrapAllInlineOrTextNodesAs("P", element); + + var nodeToReturn = element.firstChild; + + while(element.firstChild) this.insertNodeAt(element.firstChild, element, "before"); + this.deleteNode(element); + + return nodeToReturn; + }, + + /** + * Wraps element by given tag + * + * @param {String} tag tag name + * @param {Element} element target element to wrap + * @returns {Element} wrapper + */ + wrapElement: function(tag, element) { + var wrapper = this.insertNodeAt(this.createElement(tag), element, "before"); + wrapper.appendChild(element); + return wrapper; + }, + + /** + * Tests #smartWrap with given criteria but doesn't change anything + */ + testSmartWrap: function(endElement, criteria) { + return this.smartWrap(endElement, null, criteria, true); + }, + + /** + * Create inline element with given tag name and wraps nodes nearby endElement by given criteria + * + * @param {Element} endElement Boundary(end point, exclusive) of wrapper. + * @param {String} tag Tag name of wrapper. + * @param {Object} function which returns text index of start boundary. + * @param {boolean} testOnly just test boundary and do not perform actual wrapping. + * + * @returns {Element} wrapper + */ + smartWrap: function(endElement, tag, criteria, testOnly) { + var block = this.getParentBlockElementOf(endElement); + + tag = tag || "SPAN"; + criteria = criteria || function(text) {return -1}; + + // check for empty wrapper + if(!testOnly && (!endElement.previousSibling || this.isEmptyBlock(block))) { + var wrapper = this.insertNodeAt(this.createElement(tag), endElement, "before"); + return wrapper; + } + + // collect all textnodes + var textNodes = this.tree.collectForward(block, function(node) {return node == endElement}, function(node) {return node.nodeType == 3}); + + // find textnode and break-point + var nodeIndex = 0; + var nodeValues = textNodes.pluck("nodeValue"); + var textToWrap = nodeValues.join(""); + var textIndex = criteria(textToWrap) + var breakPoint = textIndex; + + if(breakPoint == -1) { + breakPoint = 0; + } else { + textToWrap = textToWrap.substring(breakPoint); + } + + for(var i = 0; i < textNodes.length; i++) { + if(breakPoint > nodeValues[i].length) { + breakPoint -= nodeValues[i].length; + } else { + nodeIndex = i; + break; + } + } + + if(testOnly) return {text:textToWrap, textIndex:textIndex, nodeIndex:nodeIndex, breakPoint:breakPoint}; + + // break textnode if necessary + if(breakPoint != 0) { + var splitted = textNodes[nodeIndex].splitText(breakPoint); + nodeIndex++; + textNodes.splice(nodeIndex, 0, splitted); + } + var startElement = textNodes[nodeIndex] || block.firstChild; + + // split inline elements up to parent block if necessary + var family = this.tree.findCommonAncestorAndImmediateChildrenOf(startElement, endElement); + var ca = family.parent; + if(ca) { + if(startElement.parentNode != ca) startElement = this.splitElementUpto(startElement, ca, true); + if(endElement.parentNode != ca) endElement = this.splitElementUpto(endElement, ca, true); + + var prevStart = startElement.previousSibling; + var nextEnd = endElement.nextSibling; + + // remove empty inline elements + if(prevStart && prevStart.nodeType == 1 && this.isEmptyBlock(prevStart)) this.deleteNode(prevStart); + if(nextEnd && nextEnd.nodeType == 1 && this.isEmptyBlock(nextEnd)) this.deleteNode(nextEnd); + + // wrap + var wrapper = this.insertNodeAt(this.createElement(tag), startElement, "before"); + while(wrapper.nextSibling != endElement) wrapper.appendChild(wrapper.nextSibling); + return wrapper; + } else { + // wrap + var wrapper = this.insertNodeAt(this.createElement(tag), endElement, "before"); + return wrapper; + } + }, + + /** + * Wraps all adjust inline elements and text nodes into block element. + * + * TODO: empty element should return empty array when it is not forced and (at least) single item array when forced + * + * @param {String} tag Tag name of wrapper + * @param {Element} element Target element + * @param {boolean} force Force wrapping. If it is set to false, this method do not makes unnecessary wrapper. + * + * @returns {Array} Array of wrappers. If nothing performed it returns empty array + */ + wrapAllInlineOrTextNodesAs: function(tag, element, force) { + var wrappers = []; + + if(!force && !this.tree.hasMixedContents(element)) return wrappers; + + var node = element.firstChild; + while(node) { + if(this.tree.isTextOrInlineNode(node)) { + var wrapper = this.wrapInlineOrTextNodesAs(tag, node); + wrappers.push(wrapper); + node = wrapper.nextSibling; + } else { + node = node.nextSibling; + } + } + + return wrappers; + }, + + /** + * Wraps node and its adjust next siblings into an element + */ + wrapInlineOrTextNodesAs: function(tag, node) { + var wrapper = this.createElement(tag); + var from = node; + + from.parentNode.replaceChild(wrapper, from); + wrapper.appendChild(from); + + // move nodes into wrapper + while(wrapper.nextSibling && this.tree.isTextOrInlineNode(wrapper.nextSibling)) wrapper.appendChild(wrapper.nextSibling); + + return wrapper; + }, + + /** + * Turns block element into list item + * + * @param {Element} element Target element + * @param {String} type One of "UL", "OL", "CODE". "CODE" is same with "OL" but it gives "OL" a class name "code" + * + * @return {Element} LI element + */ + turnElementIntoListItem: function(element, type) { + type = type.toUpperCase(); + + var container = this.createElement(type == "UL" ? "UL" : "OL"); + if(type == "CODE") container.className = "code"; + + if(this.tree.isTableCell(element)) { + var p = this.wrapAllInlineOrTextNodesAs("P", element, true)[0]; + container = this.insertNodeAt(container, element, "start"); + var li = this.insertNodeAt(this.createElement("LI"), container, "start"); + li.appendChild(p); + } else { + container = this.insertNodeAt(container, element, "after"); + var li = this.insertNodeAt(this.createElement("LI"), container, "start"); + li.appendChild(element); + } + + this.unwrapUnnecessaryParagraph(li); + this.mergeAdjustLists(container); + + return li; + }, + + /** + * Extracts given element out from its parent element. + * + * @param {Element} element Target element + */ + extractOutElementFromParent: function(element) { + if(element == this.root || this.root == element.parentNode || !element.offsetParent) return null; + + if(element.nodeName == "LI") { + this.wrapAllInlineOrTextNodesAs("P", element, true); + element = element.firstChild; + } + + var container = element.parentNode; + var nodeToReturn = null; + + if(container.nodeName == "LI" && container.parentNode.parentNode.nodeName == "LI") { + // nested list item + if(element.previousSibling) { + this.splitContainerOf(element, true); + this.correctEmptyElement(element); + } + + this.outdentListItem(element); + nodeToReturn = element; + } else if(container.nodeName == "LI") { + // not-nested list item + + if(this.tree.isListContainer(element.nextSibling)) { + // 1. split listContainer + var listContainer = container.parentNode; + this.splitContainerOf(container, true); + this.correctEmptyElement(element); + + // 2. extract out LI's children + nodeToReturn = container.firstChild; + while(container.firstChild) { + this.insertNodeAt(container.firstChild, listContainer, "before"); + } + + // 3. remove listContainer and merge adjust lists + var prevContainer = listContainer.previousSibling; + this.deleteNode(listContainer); + if(prevContainer && this.tree.isListContainer(prevContainer)) this.mergeAdjustLists(prevContainer); + } else { + // 1. split LI + this.splitContainerOf(element, true); + this.correctEmptyElement(element); + + // 2. split list container + var listContainer = this.splitContainerOf(container); + + // 3. extract out + this.insertNodeAt(element, listContainer.parentNode, "before"); + this.deleteNode(listContainer.parentNode); + + nodeToReturn = element; + } + } else if(this.tree.isTableCell(container) || this.tree.isTableCell(element)) { + // do nothing + } else { + // normal block + this.splitContainerOf(element, true); + this.correctEmptyElement(element); + nodeToReturn = this.insertNodeAt(element, container, "before"); + + this.deleteNode(container); + } + + return nodeToReturn; + }, + + /** + * Insert new block above or below given element. + * + * @param {Element} block Target block + * @param {boolean} before Insert new block above(before) target block + * @param {String} forceTag New block's tag name. If omitted, target block's tag name will be used. + * + * @returns {Element} Inserted block + */ + insertNewBlockAround: function(block, before, forceTag) { + var isListItem = block.nodeName == "LI" || block.parentNode.nodeName == "LI"; + + this.removeTrailingWhitespace(block); + if(this.isFirstLiWithNestedList(block) && !forceTag && before) { + var li = this.getParentElementOf(block, ["LI"]); + var newBlock = this._insertNewBlockAround(li, before); + return newBlock; + } else if(isListItem && !forceTag) { + var li = this.getParentElementOf(block, ["LI"]); + var newBlock = this._insertNewBlockAround(block, before); + if(li != block) newBlock = this.splitContainerOf(newBlock, false, "prev"); + return newBlock; + } else if(this.tree.isBlockContainer(block)) { + this.wrapAllInlineOrTextNodesAs("P", block, true); + return this._insertNewBlockAround(block.firstChild, before, forceTag); + } else { + return this._insertNewBlockAround(block, before, this.tree.isHeading(block) ? "P" : forceTag); + } + }, + + /** + * @private + * + * TODO: Rename + */ + _insertNewBlockAround: function(element, before, tagName) { + var newElement = this.createElement(tagName || element.nodeName); + this.copyAttributes(element, newElement, false); + this.correctEmptyElement(newElement); + newElement = this.insertNodeAt(newElement, element, before ? "before" : "after"); + return newElement; + }, + + /** + * Wrap or replace element with given tag name. + * + * @param {String} tag Tag name + * @param {Element} element Target element + * + * @return {Element} wrapper element or replaced element. + */ + applyTagIntoElement: function(tag, element) { + if(this.tree.isBlockOnlyContainer(tag)) { + return this.wrapBlock(tag, element); + } else if(this.tree.isBlockContainer(element)) { + var wrapper = this.createElement(tag); + this.moveChildNodes(element, wrapper); + return this.insertNodeAt(wrapper, element, "start"); + } else { + if(this.tree.isBlockContainer(tag) && this.hasImportantAttributes(element)) { + return this.wrapBlock(tag, element); + } else { + return this.replaceTag(tag, element); + } + } + + throw "IllegalArgumentException - [" + tag + ", " + element + "]"; + }, + + /** + * Wrap or replace elements with given tag name. + * + * @param {String} tag Tag name + * @param {Element} from Start boundary (inclusive) + * @param {Element} to End boundary (inclusive) + * + * @returns {Array} Array of wrappers or replaced elements + */ + applyTagIntoElements: function(tagName, from, to) { + var applied = []; + + if(this.tree.isBlockContainer(tagName)) { + var family = this.tree.findCommonAncestorAndImmediateChildrenOf(from, to); + var node = family.left; + var wrapper = this.insertNodeAt(this.createElement(tagName), node, "before"); + + var coveringWholeList = + family.parent.nodeName == "LI" && + family.parent.parentNode.childNodes.length == 1 && + !family.left.previousSilbing && + !family.right.nextSibling; + + if(coveringWholeList) { + var ul = node.parentNode.parentNode; + this.insertNodeAt(wrapper, ul, "before"); + wrapper.appendChild(ul); + } else { + while(node != family.right) { + next = node.nextSibling; + wrapper.appendChild(node); + node = next; + } + wrapper.appendChild(family.right); + } + applied.push(wrapper); + } else { + // is normal tagName + var elements = this.getBlockElementsBetween(from, to); + for(var i = 0; i < elements.length; i++) { + if(this.tree.isBlockContainer(elements[i])) { + applied.push(this.wrapAllInlineOrTextNodesAs(tagName, elements[i], true)); + } else { + applied.push(this.replaceTag(tagName, elements[i])); + } + } + } + return applied.flatten(); + }, + + /** + * Moves block up or down + * + * @param {Element} block Target block + * @param {boolean} up Move up if true + * + * @returns {Element} Moved block. It could be different with given block. + */ + moveBlock: function(block, up) { + // if block is table cell or contained by table cell, select its row as mover + block = this.getParentElementOf(block, ["TR"]) || block; + + // if block is only child, select its parent as mover + while(block.nodeName != "TR" && block.parentNode != this.getRoot() && !block.previousSibling && !block.nextSibling && !this.tree.isListContainer(block.parentNode)) { + block = block.parentNode; + } + + // find target and where + var target, where; + if (up) { + target = block.previousSibling; + + if(target) { + var singleNodeLi = target.nodeName == 'LI' && ((target.childNodes.length == 1 && this.tree.isBlock(target.firstChild)) || !this.tree.hasBlocks(target)); + var table = ['TABLE', 'TR'].include(target.nodeName); + + where = this.tree.isBlockContainer(target) && !singleNodeLi && !table ? "end" : "before"; + } else if(block.parentNode != this.getRoot()) { + target = block.parentNode; + where = "before"; + } + } else { + target = block.nextSibling; + + if(target) { + var singleNodeLi = target.nodeName == 'LI' && ((target.childNodes.length == 1 && this.tree.isBlock(target.firstChild)) || !this.tree.hasBlocks(target)); + var table = ['TABLE', 'TR'].include(target.nodeName); + + where = this.tree.isBlockContainer(target) && !singleNodeLi && !table ? "start" : "after"; + } else if(block.parentNode != this.getRoot()) { + target = block.parentNode; + where = "after"; + } + } + + + // no way to go? + if(!target) return null; + if(["TBODY", "THEAD"].include(target.nodeName)) return null; + + // normalize + this.wrapAllInlineOrTextNodesAs("P", target, true); + + // make placeholder if needed + if(this.isFirstLiWithNestedList(block)) { + this.insertNewBlockAround(block, false, "P"); + } + + // perform move + var parent = block.parentNode; + var moved = this.insertNodeAt(block, target, where, true); + + // cleanup + if(!parent.hasChildNodes()) this.deleteNode(parent, true); + this.unwrapUnnecessaryParagraph(moved); + this.unwrapUnnecessaryParagraph(target); + + // remove placeholder + if(up) { + if(moved.previousSibling && this.isEmptyBlock(moved.previousSibling) && !moved.previousSibling.previousSibling && moved.parentNode.nodeName == "LI" && this.tree.isListContainer(moved.nextSibling)) { + this.deleteNode(moved.previousSibling); + } + } else { + if(moved.nextSibling && this.isEmptyBlock(moved.nextSibling) && !moved.previousSibling && moved.parentNode.nodeName == "LI" && this.tree.isListContainer(moved.nextSibling.nextSibling)) { + this.deleteNode(moved.nextSibling); + } + } + + return moved; + }, + + /** + * Remove given block + * + * @param {Element} block Target block + * @returns {Element} Nearest block of remove element + */ + removeBlock: function(block) { + var blockToMove; + + // if block is only child, select its parent as mover + while(block.parentNode != this.getRoot() && !block.previousSibling && !block.nextSibling && !this.tree.isListContainer(block.parentNode)) { + block = block.parentNode; + } + + var finder = function(node) {return this.tree.isBlock(node) && !this.tree.isAtomic(node) && !this.tree.isDescendantOf(block, node) && !this.tree.hasBlocks(node);}.bind(this); + var exitCondition = function(node) {return this.tree.isBlock(node) && !this.tree.isDescendantOf(this.getRoot(), node)}.bind(this); + + if(this.isFirstLiWithNestedList(block)) { + blockToMove = this.outdentListItem(block.nextSibling.firstChild); + this.deleteNode(blockToMove.previousSibling, true); + } else if(this.tree.isTableCell(block)) { + var rtable = new xq.RichTable(this, this.getParentElementOf(block, ["TABLE"])); + blockToMove = rtable.getBelowCellOf(block); + + // should not delete row when there's thead and the row is the only child of tbody + if( + block.parentNode.parentNode.nodeName == "TBODY" && + rtable.hasHeadingAtTop() && + rtable.getDom().tBodies[0].rows.length == 1) return blockToMove; + + blockToMove = blockToMove || + this.tree.findForward(block, finder, exitCondition) || + this.tree.findBackward(block, finder, exitCondition); + + this.deleteNode(block.parentNode, true); + } else { + blockToMove = blockToMove || + this.tree.findForward(block, finder, exitCondition) || + this.tree.findBackward(block, finder, exitCondition); + + if(!blockToMove) blockToMove = this.insertNodeAt(this.makeEmptyParagraph(), block, "after"); + + this.deleteNode(block, true); + } + if(!this.getRoot().hasChildNodes()) { + blockToMove = this.createElement("P"); + this.getRoot().appendChild(blockToMove); + this.correctEmptyElement(blockToMove); + } + + return blockToMove; + }, + + /** + * Removes trailing whitespaces of given block + * + * @param {Element} block Target block + */ + removeTrailingWhitespace: function(block) {throw "Not implemented"}, + + /** + * Extract given list item out and change its container's tag + * + * @param {Element} element LI or P which is a child of LI + * @param {String} type "OL", "UL", or "CODE" + * + * @returns {Element} changed element + */ + changeListTypeTo: function(element, type) { + type = type.toUpperCase(); + + var li = this.getParentElementOf(element, ["LI"]); + if(!li) throw "IllegalArgumentException"; + + var container = li.parentNode; + + this.splitContainerOf(li); + + var newContainer = this.insertNodeAt(this.createElement(type == "UL" ? "UL" : "OL"), container, "before"); + if(type == "CODE") newContainer.className = "code"; + + this.insertNodeAt(li, newContainer, "start"); + this.deleteNode(container); + + this.mergeAdjustLists(newContainer); + + return element; + }, + + /** + * Split container of element into (maxium) three pieces. + */ + splitContainerOf: function(element, preserveElementItself, dir) { + if([element, element.parentNode].include(this.getRoot())) return element; + + var container = element.parentNode; + if(element.previousSibling && (!dir || dir.toLowerCase() == "prev")) { + var prev = this.createElement(container.nodeName); + this.copyAttributes(container, prev); + while(container.firstChild != element) { + prev.appendChild(container.firstChild); + } + this.insertNodeAt(prev, container, "before"); + this.unwrapUnnecessaryParagraph(prev); + } + + if(element.nextSibling && (!dir || dir.toLowerCase() == "next")) { + var next = this.createElement(container.nodeName); + this.copyAttributes(container, next); + while(container.lastChild != element) { + this.insertNodeAt(container.lastChild, next, "start"); + } + this.insertNodeAt(next, container, "after"); + this.unwrapUnnecessaryParagraph(next); + } + + if(!preserveElementItself) element = this.unwrapUnnecessaryParagraph(container) ? container : element; + return element; + }, + + /** + * TODO: Add specs + */ + splitParentElement: function(seperator) { + var parent = seperator.parentNode; + if(["HTML", "HEAD", "BODY"].include(parent.nodeName)) throw "Illegal argument. Cannot seperate element[" + parent.nodeName + "]"; + + var previousSibling = seperator.previousSibling; + var nextSibling = seperator.nextSibling; + + var newElement = this.insertNodeAt(this.createElement(parent.nodeName), parent, "after"); + + var next; + while(next = seperator.nextSibling) newElement.appendChild(next); + + this.insertNodeAt(seperator, newElement, "start"); + this.copyAttributes(parent, newElement); + + return newElement; + }, + + /** + * TODO: Add specs + */ + splitElementUpto: function(seperator, element, excludeElement) { + while(seperator.previousSibling != element) { + if(excludeElement && seperator.parentNode == element) break; + seperator = this.splitParentElement(seperator); + } + return seperator; + }, + + /** + * Merges two adjust elements + * + * @param {Element} element base element + * @param {boolean} withNext merge base element with next sibling + * @param {boolean} skip skip merge steps + */ + mergeElement: function(element, withNext, skip) { + this.wrapAllInlineOrTextNodesAs("P", element.parentNode, true); + + // find two block + if(withNext) { + var prev = element; + var next = this.tree.findForward( + element, + function(node) {return this.tree.isBlock(node) && !this.tree.isListContainer(node) && node != element.parentNode}.bind(this) + ); + } else { + var next = element; + var prev = this.tree.findBackward( + element, + function(node) {return this.tree.isBlock(node) && !this.tree.isListContainer(node) && node != element.parentNode}.bind(this) + ); + } + + // normalize next block + if(next && this.tree.isDescendantOf(this.getRoot(), next)) { + var nextContainer = next.parentNode; + if(this.tree.isBlockContainer(next)) { + nextContainer = next; + this.wrapAllInlineOrTextNodesAs("P", nextContainer, true); + next = nextContainer.firstChild; + } + } else { + next = null; + } + + // normalize prev block + if(prev && this.tree.isDescendantOf(this.getRoot(), prev)) { + var prevContainer = prev.parentNode; + if(this.tree.isBlockContainer(prev)) { + prevContainer = prev; + this.wrapAllInlineOrTextNodesAs("P", prevContainer, true); + prev = prevContainer.lastChild; + } + } else { + prev = null; + } + + try { + var containersAreTableCell = + prevContainer && (this.tree.isTableCell(prevContainer) || ['TR', 'THEAD', 'TBODY'].include(prevContainer.nodeName)) && + nextContainer && (this.tree.isTableCell(nextContainer) || ['TR', 'THEAD', 'TBODY'].include(nextContainer.nodeName)); + + if(containersAreTableCell && prevContainer != nextContainer) return null; + + // if next has margin, perform outdent + if((!skip || !prev) && next && this.outdentElement(next)) return element; + + // nextContainer is first li and next of it is list container + if(nextContainer && nextContainer.nodeName == 'LI' && this.tree.isListContainer(next.nextSibling)) { + this.extractOutElementFromParent(nextContainer); + return prev; + } + + // merge two list containers + if(nextContainer && nextContainer.nodeName == 'LI' && this.tree.isListContainer(nextContainer.parentNode.previousSibling)) { + this.mergeAdjustLists(nextContainer.parentNode.previousSibling, true, "next"); + return prev; + } + + if(next && !containersAreTableCell && prevContainer && prevContainer.nodeName == 'LI' && nextContainer && nextContainer.nodeName == 'LI' && prevContainer.parentNode.nextSibling == nextContainer.parentNode) { + var nextContainerContainer = nextContainer.parentNode; + this.moveChildNodes(nextContainer.parentNode, prevContainer.parentNode); + this.deleteNode(nextContainerContainer); + return prev; + } + + // merge two containers + if(next && !containersAreTableCell && prevContainer && prevContainer.nextSibling == nextContainer && ((skip && prevContainer.nodeName != "LI") || (!skip && prevContainer.nodeName == "LI"))) { + this.moveChildNodes(nextContainer, prevContainer); + return prev; + } + + // unwrap container + if(nextContainer && nextContainer.nodeName != "LI" && !this.getParentElementOf(nextContainer, ["TABLE"]) && !this.tree.isListContainer(nextContainer) && nextContainer != this.getRoot() && !next.previousSibling) { + return this.unwrapElement(nextContainer, true); + } + + // delete table + if(withNext && nextContainer && nextContainer.nodeName == "TABLE") { + this.deleteNode(nextContainer, true); + return prev; + } else if(!withNext && prevContainer && this.tree.isTableCell(prevContainer) && !this.tree.isTableCell(nextContainer)) { + this.deleteNode(this.getParentElementOf(prevContainer, ["TABLE"]), true); + return next; + } + + // if prev is same with next, do nothing + if(prev == next) return null; + + // if there is a null block, do nothing + if(!prev || !next || !prevContainer || !nextContainer) return null; + + // if two blocks are not in the same table cell, do nothing + if(this.getParentElementOf(prev, ["TD", "TH"]) != this.getParentElementOf(next, ["TD", "TH"])) return null; + + var prevIsEmpty = false; + + // cleanup empty block before merge + + // 1. cleanup prev node which ends with marker +   + if( + xq.Browser.isTrident && + prev.childNodes.length >= 2 && + this.isMarker(prev.lastChild.previousSibling) && + prev.lastChild.nodeType == 3 && + prev.lastChild.nodeValue.length == 1 && + prev.lastChild.nodeValue.charCodeAt(0) == 160 + ) { + this.deleteNode(prev.lastChild); + } + + // 2. cleanup prev node (if prev is empty, then replace prev's tag with next's) + this.removePlaceHoldersAndEmptyNodes(prev); + if(this.isEmptyBlock(prev)) { + // replace atomic block with normal block so that following code don't need to care about atomic block + if(this.tree.isAtomic(prev)) prev = this.replaceTag("P", prev); + + prev = this.replaceTag(next.nodeName, prev) || prev; + prev.innerHTML = ""; + } else if(prev.firstChild == prev.lastChild && this.isMarker(prev.firstChild)) { + prev = this.replaceTag(next.nodeName, prev) || prev; + } + + // 3. cleanup next node + if(this.isEmptyBlock(next)) { + // replace atomic block with normal block so that following code don't need to care about atomic block + if(this.tree.isAtomic(next)) next = this.replaceTag("P", next); + + next.innerHTML = ""; + } + + // perform merge + this.moveChildNodes(next, prev); + this.deleteNode(next); + return prev; + } finally { + // cleanup + if(prevContainer && this.isEmptyBlock(prevContainer)) this.deleteNode(prevContainer, true); + if(nextContainer && this.isEmptyBlock(nextContainer)) this.deleteNode(nextContainer, true); + + if(prevContainer) this.unwrapUnnecessaryParagraph(prevContainer); + if(nextContainer) this.unwrapUnnecessaryParagraph(nextContainer); + } + }, + + /** + * Merges adjust list containers which has same tag name + * + * @param {Element} container target list container + * @param {boolean} force force adjust list container even if they have different list type + * @param {String} dir Specify merge direction: PREV or NEXT. If not supplied it will be merged with both direction. + */ + mergeAdjustLists: function(container, force, dir) { + var prev = container.previousSibling; + var isPrevSame = prev && (prev.nodeName == container.nodeName && prev.className == container.className); + if((!dir || dir.toLowerCase() == 'prev') && (isPrevSame || (force && this.tree.isListContainer(prev)))) { + while(prev.lastChild) { + this.insertNodeAt(prev.lastChild, container, "start"); + } + this.deleteNode(prev); + } + + var next = container.nextSibling; + var isNextSame = next && (next.nodeName == container.nodeName && next.className == container.className); + if((!dir || dir.toLowerCase() == 'next') && (isNextSame || (force && this.tree.isListContainer(next)))) { + while(next.firstChild) { + this.insertNodeAt(next.firstChild, container, "end"); + } + this.deleteNode(next); + } + }, + + /** + * Moves child nodes from one element into another. + * + * @param {Elemet} from source element + * @param {Elemet} to target element + */ + moveChildNodes: function(from, to) { + if(this.tree.isDescendantOf(from, to) || ["HTML", "HEAD"].include(to.nodeName)) + throw "Illegal argument. Cannot move children of element[" + from.nodeName + "] to element[" + to.nodeName + "]"; + + if(from == to) return; + + while(from.firstChild) to.appendChild(from.firstChild); + }, + + /** + * Copies attributes from one element into another. + * + * @param {Element} from source element + * @param {Element} to target element + * @param {boolean} copyId copy ID attribute of source element + */ + copyAttributes: function(from, to, copyId) { + // IE overrides this + + var attrs = from.attributes; + if(!attrs) return; + + for(var i = 0; i < attrs.length; i++) { + if(attrs[i].nodeName == "class" && attrs[i].nodeValue) { + to.className = attrs[i].nodeValue; + } else if((copyId || !["id"].include(attrs[i].nodeName)) && attrs[i].nodeValue) { + to.setAttribute(attrs[i].nodeName, attrs[i].nodeValue); + } + } + }, + + _indentElements: function(node, blocks, affect) { + for (var i=0; i < affect.length; i++) { + if (affect[i] == node || this.tree.isDescendantOf(affect[i], node)) + return; + } + leaves = this.tree.getLeavesAtEdge(node); + + if (blocks.include(leaves[0])) { + var affected = this.indentElement(node, true); + if (affected) { + affect.push(affected); + return; + } + } + + if (blocks.include(node)) { + var affected = this.indentElement(node, true); + if (affected) { + affect.push(affected); + return; + } + } + + var children=$A(node.childNodes); + for (var i=0; i < children.length; i++) + this._indentElements(children[i], blocks, affect); + return; + }, + + indentElements: function(from, to) { + var blocks = this.getBlockElementsBetween(from, to); + var top = this.tree.findCommonAncestorAndImmediateChildrenOf(from, to); + + var affect = []; + + leaves = this.tree.getLeavesAtEdge(top.parent); + if (blocks.include(leaves[0])) { + var affected = this.indentElement(top.parent); + if (affected) + return [affected]; + } + + var children = $A(top.parent.childNodes); + for (var i=0; i < children.length; i++) { + this._indentElements(children[i], blocks, affect); + } + + affect = affect.flatten() + return affect.length > 0 ? affect : blocks; + }, + + outdentElementsCode: function(node) { + if (node.tagName == 'LI') + node = node.parentNode; + if (node.tagName == 'OL' && node.className == 'code') + return true; + return false; + }, + + _outdentElements: function(node, blocks, affect) { + for (var i=0; i < affect.length; i++) { + if (affect[i] == node || this.tree.isDescendantOf(affect[i], node)) + return; + } + leaves = this.tree.getLeavesAtEdge(node); + + if (blocks.include(leaves[0]) && !this.outdentElementsCode(leaves[0])) { + var affected = this.outdentElement(node, true); + if (affected) { + affect.push(affected); + return; + } + } + + if (blocks.include(node)) { + var children = $A(node.parentNode.childNodes); + var isCode = this.outdentElementsCode(node); + var affected = this.outdentElement(node, true, isCode); + if (affected) { + if (children.include(affected) && this.tree.isListContainer(node.parentNode) && !isCode) { + for (var i=0; i < children.length; i++) { + if (blocks.include(children[i]) && !affect.include(children[i])) + affect.push(children[i]); + } + }else + affect.push(affected); + return; + } + } + + var children=$A(node.childNodes); + for (var i=0; i < children.length; i++) + this._outdentElements(children[i], blocks, affect); + return; + }, + + outdentElements: function(from, to) { + var start, end; + + if (from.parentNode.tagName == 'LI') start=from.parentNode; + if (to.parentNode.tagName == 'LI') end=to.parentNode; + + var blocks = this.getBlockElementsBetween(from, to); + var top = this.tree.findCommonAncestorAndImmediateChildrenOf(from, to); + + var affect = []; + + leaves = this.tree.getLeavesAtEdge(top.parent); + if (blocks.include(leaves[0]) && !this.outdentElementsCode(top.parent)) { + var affected = this.outdentElement(top.parent); + if (affected) + return [affected]; + } + + var children = $A(top.parent.childNodes); + for (var i=0; i < children.length; i++) { + this._outdentElements(children[i], blocks, affect); + } + + if (from.offsetParent && to.offsetParent) { + start = from; + end = to; + }else if (blocks.first().offsetParent && blocks.last().offsetParent) { + start = blocks.first(); + end = blocks.last(); + } + + affect = affect.flatten() + if (!start || !start.offsetParent) + start = affect.first(); + if (!end || !end.offsetParent) + end = affect.last(); + + return this.getBlockElementsBetween(start, end); + }, + + /** + * Performs indent by increasing element's margin-left + */ + indentElement: function(element, noParent, forceMargin) { + if( + !forceMargin && + (element.nodeName == "LI" || (!this.tree.isListContainer(element) && !element.previousSibling && element.parentNode.nodeName == "LI")) + ) return this.indentListItem(element, noParent); + + var root = this.getRoot(); + if(!element || element == root) return null; + + if (element.parentNode != root && !element.previousSibling && !noParent) element=element.parentNode; + + var margin = element.style.marginLeft; + var cssValue = margin ? this._getCssValue(margin, "px") : {value:0, unit:"em"}; + + cssValue.value += 2; + element.style.marginLeft = cssValue.value + cssValue.unit; + + return element; + }, + + /** + * Performs outdent by decreasing element's margin-left + */ + outdentElement: function(element, noParent, forceMargin) { + if(!forceMargin && element.nodeName == "LI") return this.outdentListItem(element, noParent); + + var root = this.getRoot(); + if(!element || element == root) return null; + + var margin = element.style.marginLeft; + + var cssValue = margin ? this._getCssValue(margin, "px") : {value:0, unit:"em"}; + if(cssValue.value == 0) { + return element.previousSibling || forceMargin ? + null : + this.outdentElement(element.parentNode, noParent); + } + + cssValue.value -= 2; + element.style.marginLeft = cssValue.value <= 0 ? "" : cssValue.value + cssValue.unit; + if(element.style.cssText == "") element.removeAttribute("style"); + + return element; + }, + + /** + * Performs indent for list item + */ + indentListItem: function(element, treatListAsNormalBlock) { + var li = this.getParentElementOf(element, ["LI"]); + var container = li.parentNode; + var prev = li.previousSibling; + if(!li.previousSibling) return this.indentElement(container); + + if(li.parentNode.nodeName == "OL" && li.parentNode.className == "code") return this.indentElement(li, treatListAsNormalBlock, true); + + if(!prev.lastChild) prev.appendChild(this.makePlaceHolder()); + + var targetContainer = + this.tree.isListContainer(prev.lastChild) ? + // if there's existing list container, select it as target container + prev.lastChild : + // if there's nothing, create new one + this.insertNodeAt(this.createElement(container.nodeName), prev, "end"); + + this.wrapAllInlineOrTextNodesAs("P", prev, true); + + // perform move + targetContainer.appendChild(li); + + // flatten nested list + if(!treatListAsNormalBlock && li.lastChild && this.tree.isListContainer(li.lastChild)) { + var childrenContainer = li.lastChild; + var child; + while(child = childrenContainer.lastChild) { + this.insertNodeAt(child, li, "after"); + } + this.deleteNode(childrenContainer); + } + + this.unwrapUnnecessaryParagraph(li); + + return li; + }, + + /** + * Performs outdent for list item + * + * @return {Element} outdented list item or null if no outdent performed + */ + outdentListItem: function(element, treatListAsNormalBlock) { + var li = this.getParentElementOf(element, ["LI"]); + var container = li.parentNode; + + if(!li.previousSibling) { + var performed = this.outdentElement(container); + if(performed) return performed; + } + + if(li.parentNode.nodeName == "OL" && li.parentNode.className == "code") return this.outdentElement(li, treatListAsNormalBlock, true); + + var parentLi = container.parentNode; + if(parentLi.nodeName != "LI") return null; + + if(treatListAsNormalBlock) { + while(container.lastChild != li) { + this.insertNodeAt(container.lastChild, parentLi, "after"); + } + } else { + // make next siblings as children + if(li.nextSibling) { + var targetContainer = + li.lastChild && this.tree.isListContainer(li.lastChild) ? + // if there's existing list container, select it as target container + li.lastChild : + // if there's nothing, create new one + this.insertNodeAt(this.createElement(container.nodeName), li, "end"); + + this.copyAttributes(container, targetContainer); + + var sibling; + while(sibling = li.nextSibling) { + targetContainer.appendChild(sibling); + } + } + } + + // move current LI into parent LI's next sibling + li = this.insertNodeAt(li, parentLi, "after"); + + // remove empty container + if(container.childNodes.length == 0) this.deleteNode(container); + + if(li.firstChild && this.tree.isListContainer(li.firstChild)) { + this.insertNodeAt(this.makePlaceHolder(), li, "start"); + } + + this.wrapAllInlineOrTextNodesAs("P", li); + this.unwrapUnnecessaryParagraph(parentLi); + + return li; + }, + + /** + * Performs justification + * + * @param {Element} block target element + * @param {String} dir one of "LEFT", "CENTER", "RIGHT", "BOTH" + */ + justifyBlock: function(block, dir) { + // if block is only child, select its parent as mover + while(block.parentNode != this.getRoot() && !block.previousSibling && !block.nextSibling && !this.tree.isListContainer(block.parentNode)) { + block = block.parentNode; + } + + var styleValue = dir.toLowerCase() == "both" ? "justify" : dir; + if(styleValue == "left") { + block.style.textAlign = ""; + if(block.style.cssText == "") block.removeAttribute("style"); + } else { + block.style.textAlign = styleValue; + } + return block; + }, + + justifyBlocks: function(blocks, dir) { + blocks.each(function(block) { + this.justifyBlock(block, dir); + }.bind(this)); + + return blocks; + }, + + /** + * Turn given element into list. If the element is a list already, it will be reversed into normal element. + * + * @param {Element} element target element + * @param {String} type one of "UL", "OL" + * @returns {Element} affected element + */ + applyList: function(element, type) { + type = type.toUpperCase(); + var containerTag = type == "UL" ? "UL" : "OL"; + + if(element.nodeName == "LI" || (element.parentNode.nodeName == "LI" && !element.previousSibling)) { + var element = this.getParentElementOf(element, ["LI"]); + var container = element.parentNode; + if(container.nodeName == containerTag) { + return this.extractOutElementFromParent(element); + } else { + return this.changeListTypeTo(element, type); + } + } else { + return this.turnElementIntoListItem(element, type); + } + }, + + applyLists: function(from, to, type) { + type = type.toUpperCase(); + var containerTag = type == "UL" ? "UL" : "OL"; + var blocks = this.getBlockElementsBetween(from, to); + + // LIs or Non-containing blocks + var whole = blocks.findAll(function(e) { + return e.nodeName == "LI" || !this.tree.isBlockContainer(e); + }.bind(this)); + + // LIs + var listItems = whole.findAll(function(e) {return e.nodeName == "LI"}.bind(this)); + + // Non-containing blocks which is not a descendant of any LIs selected above(listItems). + var normalBlocks = whole.findAll(function(e) { + return e.nodeName != "LI" && + !(e.parentNode.nodeName == "LI" && !e.previousSibling && !e.nextSibling) && + !this.tree.isDescendantOf(listItems, e) + }.bind(this)); + + var diffListItems = listItems.findAll(function(e) { + return e.parentNode.nodeName != containerTag; + }.bind(this)); + + // Conditions needed to determine mode + var hasNormalBlocks = normalBlocks.length > 0; + var hasDifferentListStyle = diffListItems.length > 0; + + var blockToHandle = null; + + if(hasNormalBlocks) { + blockToHandle = normalBlocks; + } else if(hasDifferentListStyle) { + blockToHandle = diffListItems; + } else { + blockToHandle = listItems; + } + + // perform operation + for(var i = 0; i < blockToHandle.length; i++) { + var block = blockToHandle[i]; + + // preserve original index to restore selection + var originalIndex = blocks.indexOf(block); + blocks[originalIndex] = this.applyList(block, type); + } + + return blocks; + }, + + /** + * Insert place-holder for given empty element. Empty element does not displayed and causes many editing problems. + * + * @param {Element} element empty element + */ + correctEmptyElement: function(element) {throw "Not implemented"}, + + /** + * Corrects current block-only-container to do not take any non-block element or node. + */ + correctParagraph: function() {throw "Not implemented"}, + + /** + * Makes place-holder for empty element. + * + * @returns {Node} Platform specific place holder + */ + makePlaceHolder: function() {throw "Not implemented"}, + + /** + * Makes place-holder string. + * + * @returns {String} Platform specific place holder string + */ + makePlaceHolderString: function() {throw "Not implemented"}, + + /** + * Makes empty paragraph which contains only one place-holder + */ + makeEmptyParagraph: function() {throw "Not implemented"}, + + /** + * Applies background color to selected area + * + * @param {Object} color valid CSS color value + */ + applyBackgroundColor: function(color) {throw "Not implemented";}, + + /** + * Applies foreground color to selected area + * + * @param {Object} color valid CSS color value + */ + applyForegroundColor: function(color) { + this.execCommand("forecolor", color); + }, + + execCommand: function(commandId, param) {throw "Not implemented";}, + + applyRemoveFormat: function() {throw "Not implemented";}, + applyEmphasis: function() {throw "Not implemented";}, + applyStrongEmphasis: function() {throw "Not implemented";}, + applyStrike: function() {throw "Not implemented";}, + applyUnderline: function() {throw "Not implemented";}, + applySuperscription: function() { + this.execCommand("superscript"); + }, + applySubscription: function() { + this.execCommand("subscript"); + }, + indentBlock: function(element, treatListAsNormalBlock) { + return (!element.previousSibling && element.parentNode.nodeName == "LI") ? + this.indentListItem(element, treatListAsNormalBlock) : + this.indentElement(element); + }, + outdentBlock: function(element, treatListAsNormalBlock) { + while(true) { + if(!element.previousSibling && element.parentNode.nodeName == "LI") { + element = this.outdentListItem(element, treatListAsNormalBlock); + return element; + } else { + var performed = this.outdentElement(element); + if(performed) return performed; + + // first-child can outdent container + if(!element.previousSibling) { + element = element.parentNode; + } else { + break; + } + } + } + + return null; + }, + wrapBlock: function(tag, start, end) { + if(!this.tree._blockTags.include(tag)) throw "Unsuppored block container: [" + tag + "]"; + if(!start) start = this.getCurrentBlockElement(); + if(!end) end = start; + + // Check if the selection captures valid fragement + var validFragment = false; + + if(start == end) { + // are they same block? + validFragment = true; + } else if(start.parentNode == end.parentNode && !start.previousSibling && !end.nextSibling) { + // are they covering whole parent? + validFragment = true; + start = end = start.parentNode; + } else { + // are they siblings of non-LI blocks? + validFragment = + (start.parentNode == end.parentNode) && + (start.nodeName != "LI"); + } + + if(!validFragment) return null; + + var wrapper = this.createElement(tag); + + if(start == end) { + // They are same. + if(this.tree.isBlockContainer(start) && !this.tree.isListContainer(start)) { + // It's a block container. Wrap its contents. + if(this.tree.isBlockOnlyContainer(wrapper)) { + this.correctEmptyElement(start); + this.wrapAllInlineOrTextNodesAs("P", start, true); + } + this.moveChildNodes(start, wrapper); + start.appendChild(wrapper); + } else { + // It's not a block container. Wrap itself. + wrapper = this.insertNodeAt(wrapper, start, "after"); + wrapper.appendChild(start); + } + + this.correctEmptyElement(wrapper); + } else { + // They are siblings. Wrap'em all. + wrapper = this.insertNodeAt(wrapper, start, "before"); + var node = start; + + while(node != end) { + next = node.nextSibling; + wrapper.appendChild(node); + node = next; + } + wrapper.appendChild(node); + } + + return wrapper; + }, + + + + ///////////////////////////////////////////// + // Focus/Caret/Selection + + /** + * Gives focus to root element's window + */ + focus: function() {throw "Not implemented";}, + + /** + * Returns selection object + */ + sel: function() {throw "Not implemented";}, + + /** + * Returns range object + */ + rng: function() {throw "Not implemented";}, + + /** + * Returns true if DOM has selection + */ + hasSelection: function() {throw "Not implemented";}, + + /** + * Returns true if root element's window has selection + */ + hasFocus: function() { + var cur = this.getCurrentElement(); + return (cur && cur.ownerDocument == this.getDoc()); + }, + + /** + * Adjust scrollbar to make the element visible in current viewport. + * + * @param {Element} element Target element + * @param {boolean} toTop Align element to top of the viewport + * @param {boolean} moveCaret Move caret to the element + */ + scrollIntoView: function(element, toTop, moveCaret) { + element.scrollIntoView(toTop); + if(moveCaret) this.placeCaretAtStartOf(element); + }, + + /** + * Select all document + */ + selectAll: function() { + return this.execCommand('selectall'); + }, + + /** + * Select specified element. + * + * @param {Element} element element to select + * @param {boolean} entireElement true to select entire element, false to select inner content of element + */ + selectElement: function(node, entireElement) {throw "Not implemented"}, + + /** + * Select all elements between two blocks(inclusive). + * + * @param {Element} start start of selection + * @param {Element} end end of selection + */ + selectBlocksBetween: function(start, end) {throw "Not implemented"}, + + /** + * Delete selected area + */ + deleteSelection: function() {throw "Not implemented"}, + + /** + * Collapses current selection. + * + * @param {boolean} toStart true to move caret to start of selected area. + */ + collapseSelection: function(toStart) {throw "Not implemented"}, + + /** + * Returns selected area as HTML string + */ + getSelectionAsHtml: function() {throw "Not implemented"}, + + /** + * Returns selected area as text string + */ + getSelectionAsText: function() {throw "Not implemented"}, + + /** + * Places caret at start of the element + * + * @param {Element} element Target element + */ + placeCaretAtStartOf: function(element) {throw "Not implemented"}, + + /** + * Checks if the node is empty-text-node or not + */ + isEmptyTextNode: function(node) { + return node.nodeType == 3 && node.nodeValue.length == 0; + }, + + /** + * Checks if the caret is place in empty block element + */ + isCaretAtEmptyBlock: function() { + return this.isEmptyBlock(this.getCurrentBlockElement()); + }, + + /** + * Checks if the caret is place at start of the block + */ + isCaretAtBlockStart: function() {throw "Not implemented"}, + + /** + * Checks if the caret is place at end of the block + */ + isCaretAtBlockEnd: function() {throw "Not implemented"}, + + /** + * Saves current selection info + * + * @returns {Object} Bookmark for selection + */ + saveSelection: function() {throw "Not implemented"}, + + /** + * Restores current selection info + * + * @param {Object} bookmark Bookmark + */ + restoreSelection: function(bookmark) {throw "Not implemented"}, + + /** + * Create marker + */ + createMarker: function() { + var marker = this.createElement("SPAN"); + marker.id = "xquared_marker_" + (this._lastMarkerId++); + marker.className = "xquared_marker"; + return marker; + }, + + /** + * Create and insert marker into current caret position. + * Marker is an inline element which has no child nodes. It can be used with many purposes. + * For example, You can push marker to mark current caret position. + * + * @returns {Element} marker + */ + pushMarker: function() { + var marker = this.createMarker(); + return this.insertNode(marker); + }, + + /** + * Removes last marker + * + * @params {boolean} moveCaret move caret into marker before delete. + */ + popMarker: function(moveCaret) { + var id = "xquared_marker_" + (--this._lastMarkerId); + var marker = this.$(id); + if(!marker) return; + + if(moveCaret) { + this.selectElement(marker, true); + this.collapseSelection(false); + } + + this.deleteNode(marker); + }, + + + + ///////////////////////////////////////////// + // Query methods + + isMarker: function(node) { + return (node.nodeType == 1 && node.nodeName == "SPAN" && node.className == "xquared_marker"); + }, + + isFirstBlockOfBody: function(block) { + var root = this.getRoot(); + var found = this.tree.findBackward( + block, + function(node) {return (node == root) || node.previousSibling;}.bind(this) + ); + + return found == root; + }, + + /** + * Returns outer HTML of given element + */ + getOuterHTML: function(element) {throw "Not implemented"}, + + /** + * Returns inner text of given element + * + * @param {Element} element Target element + * @returns {String} Text string + */ + getInnerText: function(element) { + return element.innerHTML.stripTags(); + }, + + /** + * Checks if given node is place holder or not. + * + * @param {Node} node DOM node + */ + isPlaceHolder: function(node) {throw "Not implemented"}, + + /** + * Checks if given block is the first LI whose next sibling is a nested list. + * + * @param {Element} block Target block + */ + isFirstLiWithNestedList: function(block) { + return !block.previousSibling && + block.parentNode.nodeName == "LI" && + this.tree.isListContainer(block.nextSibling); + }, + + /** + * Search all links within given element + * + * @param {Element} [element] Container element. If not given, the root element will be used. + * @param {Array} [found] if passed, links will be appended into this array. + * @returns {Array} Array of anchors. It returns empty array if there's no links. + */ + searchAnchors: function(element, found) { + if(!element) element = this.getRoot(); + if(!found) found = []; + + var anchors = element.getElementsByTagName("A"); + for(var i = 0; i < anchors.length; i++) { + found.push(anchors[i]); + } + + return found; + }, + + /** + * Search all headings within given element + * + * @param {Element} [element] Container element. If not given, the root element will be used. + * @param {Array} [found] if passed, headings will be appended into this array. + * @returns {Array} Array of headings. It returns empty array if there's no headings. + */ + searchHeadings: function(element, found) { + if(!element) element = this.getRoot(); + if(!found) found = []; + + var regexp = /^h[1-6]/ig; + + if (!element.childNodes) return []; + $A(element.childNodes).each(function(child) { + var isContainer = child && this.tree._blockContainerTags.include(child.nodeName); + var isHeading = child && child.nodeName.match(regexp); + + if (isContainer) { + this.searchHeadings(child, found); + } else if (isHeading) { + found.push(child); + } + }.bind(this)); + + return found; + }, + + /** + * Collect structure and style informations of given element. + * + * @param {Element} element target element + * @returns {Object} object that contains information: {em: true, strong: false, block: "p", list: "ol", ...} + */ + collectStructureAndStyle: function(element) { + if(!element || element.nodeName == "#document") return {}; + + var block = this.getParentBlockElementOf(element); + var parents = this.tree.collectParentsOf(element, true, function(node) {return block.parentNode == node}); + var blockName = block.nodeName; + + var info = {}; + + var doc = this.getDoc(); + var em = doc.queryCommandState("Italic"); + var strong = doc.queryCommandState("Bold"); + var strike = doc.queryCommandState("Strikethrough"); + var underline = doc.queryCommandState("Underline") && !this.getParentElementOf(element, ["A"]); + var superscription = doc.queryCommandState("superscript"); + var subscription = doc.queryCommandState("subscript"); + + // if block is only child, select its parent + while(block.parentNode && block.parentNode != this.getRoot() && !block.previousSibling && !block.nextSibling && !this.tree.isListContainer(block.parentNode)) { + block = block.parentNode; + } + + var list = false; + if(block.nodeName == "LI") { + var parent = block.parentNode; + var isCode = parent.nodeName == "OL" && parent.className == "code"; + list = isCode ? "CODE" : parent.nodeName; + } + + var justification = block.style.textAlign || "left"; + + return { + block:blockName, + em: em, + strong: strong, + strike: strike, + underline: underline, + superscription: superscription, + subscription: subscription, + list: list, + justification: justification + }; + }, + + /** + * Find elements by CSS selector. + * + * WARNING: Use this method carefully since prototype.js doesn't work well with designMode DOM. + */ + findBySelector: function(selector) { + return Element.getElementsBySelector(this.root, selector); + }, + + /** + * Find elements by attribute. + * + * This method will be deprecated when findBySelector get stabilized. + */ + findByAttribute: function(name, value) { + var nodes = []; + this._findByAttribute(nodes, this.root, name, value); + return nodes; + }, + + /** @private */ + _findByAttribute: function(nodes, element, name, value) { + if(element.getAttribute(name) == value) nodes.push(element); + if(!element.hasChildNodes()) return; + + var children = element.childNodes; + for(var i = 0; i < children.length; i++) { + if(children[i].nodeType == 1) this._findByAttribute(nodes, children[i], name, value); + } + }, + + /** + * Checks if the element has one or more important attributes: id, class, style + * + * @param {Element} element Target element + */ + hasImportantAttributes: function(element) {throw "Not implemented"}, + + /** + * Checks if the element is empty or not. Place-holder is not counted as a child. + * + * @param {Element} element Target element + */ + isEmptyBlock: function(element) {throw "Not implemented"}, + + /** + * Returns element that contains caret. + */ + getCurrentElement: function() {throw "Not implemented"}, + + /** + * Returns block element that contains caret. + */ + getCurrentBlockElement: function() { + var cur = this.getCurrentElement(); + if(!cur) return null; + + var block = this.getParentBlockElementOf(cur); + if(!block) return null; + + return (block.nodeName == "BODY") ? null : block; + }, + + /** + * Returns parent block element of parameter. + * If the parameter itself is a block, it will be returned. + * + * @param {Element} element Target element + * + * @returns {Element} Element or null + */ + getParentBlockElementOf: function(element) { + while(element) { + if(this.tree._blockTags.include(element.nodeName)) return element; + element = element.parentNode; + } + return null; + }, + + /** + * Returns parent element of parameter which has one of given tag name. + * If the parameter itself has the same tag name, it will be returned. + * + * @param {Element} element Target element + * @param {Array} tagNames Array of string which contains tag names + * + * @returns {Element} Element or null + */ + getParentElementOf: function(element, tagNames) { + while(element) { + if(tagNames.include(element.nodeName)) return element; + element = element.parentNode; + } + return null; + }, + + /** + * Collects all block elements between two elements + * + * @param {Element} from Start element(inclusive) + * @param {Element} to End element(inclusive) + */ + getBlockElementsBetween: function(from, to) { + return this.tree.collectNodesBetween(from, to, function(node) { + return node.nodeType == 1 && this.tree.isBlock(node); + }.bind(this)); + }, + + /** + * Returns block element that contains selection start. + * + * This method will return exactly same result with getCurrentBlockElement method + * when there's no selection. + */ + getBlockElementAtSelectionStart: function() {throw "Not implemented"}, + + /** + * Returns block element that contains selection end. + * + * This method will return exactly same result with getCurrentBlockElement method + * when there's no selection. + */ + getBlockElementAtSelectionEnd: function() {throw "Not implemented"}, + + /** + * Returns blocks at each edge of selection(start and end). + * + * TODO: implement ignoreEmptyEdges for FF + * + * @param {boolean} naturalOrder Mak the start element always comes before the end element + * @param {boolean} ignoreEmptyEdges Prevent some browser(Gecko) from selecting one more block than expected + */ + getBlockElementsAtSelectionEdge: function(naturalOrder, ignoreEmptyEdges) {throw "Not implemented"}, + + /** + * Returns array of selected block elements + */ + getSelectedBlockElements: function() { + var selectionEdges = this.getBlockElementsAtSelectionEdge(true, true); + var start = selectionEdges[0]; + var end = selectionEdges[1]; + + return this.tree.collectNodesBetween(start, end, function(node) { + return node.nodeType == 1 && this.tree.isBlock(node); + }.bind(this)); + }, + + /** + * Get element by ID + * + * @param {String} id Element's ID + * @returns {Element} element or null + */ + getElementById: function(id) {return this.doc.getElementById(id)}, + + /** + * Shortcut for #getElementById + */ + $: function(id) {return this.getElementById(id)}, + + /** + * Returns first "valid" child of given element. It ignores empty textnodes. + * + * @param {Element} element Target element + * @returns {Node} first child node or null + */ + getFirstChild: function(element) { + if(!element) return null; + + var nodes = $A(element.childNodes); + for(var i = 0; i < nodes.length; i++) { + if(!this.isEmptyTextNode(nodes[i])) return nodes[i]; + } + return null; + }, + + /** + * Returns last "valid" child of given element. It ignores empty textnodes and place-holders. + * + * @param {Element} element Target element + * @returns {Node} last child node or null + */ + getLastChild: function(element) {throw "Not implemented"}, + + getNextSibling: function(node) { + while(node = node.nextSibling) { + if(node.nodeType != 3 || node.nodeValue.strip() != "") break; + } + return node; + }, + + getBottommostFirstChild: function(node) { + while(node.firstChild && node.nodeType == 1) node = node.firstChild; + return node; + }, + + getBottommostLastChild: function(node) { + while(node.lastChild && node.nodeType == 1) node = node.lastChild; + return node; + }, + + /** @private */ + _getCssValue: function(str, defaultUnit) { + if(!str || str.length == 0) return {value:0, unit:defaultUnit}; + + var tokens = str.match(/(\d+)(.*)/); + return { + value:parseInt(tokens[1]), + unit:tokens[2] || defaultUnit + }; + } +}); + +/** + * Creates and returns instance of browser specific implementation. + */ +xq.RichDom.createInstance = function() { + if(xq.Browser.isTrident) { + return new xq.RichDomTrident(); + } else if(xq.Browser.isWebkit) { + return new xq.RichDomWebkit(); + } else { + return new xq.RichDomGecko(); + } +} +/** + * RichDom for W3C Standard Engine + */ +xq.RichDomW3 = Class.create(xq.RichDom, { + insertNode: function(node) { + var rng = this.rng(); + rng.insertNode(node); + rng.selectNode(node); + rng.collapse(false); + return node; + }, + + removeTrailingWhitespace: function(block) { + // TODO: do nothing + }, + + getOuterHTML: function(element) { + var div = element.ownerDocument.createElement("div"); + div.appendChild(element.cloneNode(true)); + return div.innerHTML; + }, + + correctEmptyElement: function(element) { + if(!element || element.nodeType != 1 || this.tree.isAtomic(element)) return; + + if(element.firstChild) + this.correctEmptyElement(element.firstChild); + else + element.appendChild(this.makePlaceHolder()); + }, + + correctParagraph: function() { + if(this.hasSelection()) return false; + + var block = this.getCurrentElement(); + var modified = false; + + if(this.tree.isBlockOnlyContainer(block)) { + this.execCommand("InsertParagraph"); + + // check for atomic block element such as HR + var newBlock = this.getCurrentElement(); + if(this.tree.isAtomic(newBlock.previousSibling)) { + var nextBlock = this.tree.findForward( + newBlock, + function(node) {return this.tree.isBlock(node) && !this.tree.isBlockOnlyContainer(node)}.bind(this) + ); + if(nextBlock) { + this.deleteNode(newBlock); + this.placeCaretAtStartOf(nextBlock); + } + } + modified = true; + } else if(this.tree.hasMixedContents(block)) { + this.wrapAllInlineOrTextNodesAs("P", block, true); + modified = true; + } + + block = this.getCurrentElement(); + if(this.tree.isBlock(block) && !this._hasPlaceHolderAtEnd(block)) { + block.appendChild(this.makePlaceHolder()); + modified = true; + } + + if(this.tree.isBlock(block)) { + var parentsLastChild = block.parentNode.lastChild; + if(this.isPlaceHolder(parentsLastChild)) { + this.deleteNode(parentsLastChild); + modified = true; + } + } + + return modified; + }, + + _hasPlaceHolderAtEnd: function(block) { + if(!block.hasChildNodes()) return false; + return this.isPlaceHolder(block.lastChild) || this._hasPlaceHolderAtEnd(block.lastChild); + }, + + applyBackgroundColor: function(color) { + this.execCommand("styleWithCSS", "true"); + this.execCommand("hilitecolor", color); + this.execCommand("styleWithCSS", "false"); + + // 0. Save current selection + var bookmark = this.saveSelection(); + + // 1. Get selected blocks + var blocks = this.getSelectedBlockElements(); + if(blocks.length == 0) return; + + // 2. Apply background-color to all adjust inline elements + // 3. Remove background-color from blocks + for(var i = 0; i < blocks.length; i++) { + if((i == 0 || i == blocks.length-1) && !blocks[i].style.backgroundColor) continue; + + var spans = this.wrapAllInlineOrTextNodesAs("SPAN", blocks[i], true); + for(var j = 0; j < spans.length; j++) { + spans[j].style.backgroundColor = color; + } + blocks[i].style.backgroundColor = ""; + } + + // 4. Restore selection + this.restoreSelection(bookmark); + }, + + + + + ////// + // Commands + execCommand: function(commandId, param) { + return this.doc.execCommand(commandId, false, param || null); + }, + + saveSelection: function() { + var rng = this.rng(); + return [rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset]; + }, + + restoreSelection: function(bookmark) { + var rng = this.rng(); + rng.setStart(bookmark[0], bookmark[1]); + rng.setEnd(bookmark[2], bookmark[3]); + }, + + applyRemoveFormat: function() { + this.execCommand("RemoveFormat"); + this.execCommand("Unlink"); + }, + applyEmphasis: function() { + // Generate tag. It will be replaced with tag during cleanup phase. + this.execCommand("styleWithCSS", "false"); + this.execCommand("italic"); + }, + applyStrongEmphasis: function() { + // Generate tag. It will be replaced with tag during cleanup phase. + this.execCommand("styleWithCSS", "false"); + this.execCommand("bold"); + }, + applyStrike: function() { + // Generate tag. It will be replaced with - {Context::getHtmlHeader()} From e3ac291b3abee4dc5776381389db842eef0238be Mon Sep 17 00:00:00 2001 From: zero Date: Fri, 30 Nov 2007 04:17:55 +0000 Subject: [PATCH 093/265] =?UTF-8?q?=EC=8A=A4=ED=94=84=EB=A7=81=EB=85=B8?= =?UTF-8?q?=ED=8A=B8=20=EB=AA=A8=EB=93=88=EC=97=90=EC=84=9C=20=EB=82=B4?= =?UTF-8?q?=EC=9A=A9=EC=9D=98=20ul,=20ol=20=EC=97=90=20=EB=8C=80=ED=95=B4?= =?UTF-8?q?=20=EA=B8=B0=EB=B3=B8=20margin-left=EB=A5=BC=20=EB=91=90?= =?UTF-8?q?=EC=96=B4=EC=84=9C=20depth=20=ED=91=9C=EC=8B=9C=20=EA=B0=80?= =?UTF-8?q?=EB=8A=A5=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3117 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/springnote/skins/xe_official/css/common.css | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/springnote/skins/xe_official/css/common.css b/modules/springnote/skins/xe_official/css/common.css index da2b01469..d1bfe469f 100644 --- a/modules/springnote/skins/xe_official/css/common.css +++ b/modules/springnote/skins/xe_official/css/common.css @@ -37,3 +37,4 @@ .pageInfo td a:hover { text-decoration:underline; } { border:1px solid #CCCCCC; margin-bottom:10px; } .pageView { border:1px solid #E3E3E2; padding:20px; margin-bottom:10px; } +.pageView .xhtmlEditorBody ol, .pageView .xhtmlEditorBody ul { margin-left:20px; } From a22814fae7a0d9fcc6a2e2bc55a321c092dd670a Mon Sep 17 00:00:00 2001 From: k10206 Date: Fri, 30 Nov 2007 05:44:42 +0000 Subject: [PATCH 094/265] =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=EB=A5=BC=20=EA=B0=80=EC=A0=B8=EC=98=A4=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=86=8C=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3118 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/message/message.admin.view.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/message/message.admin.view.php b/modules/message/message.admin.view.php index e4727908d..d7fc78b4f 100644 --- a/modules/message/message.admin.view.php +++ b/modules/message/message.admin.view.php @@ -22,6 +22,10 @@ $skin_list = $oModuleModel->getskins($this->module_path); Context::set('skin_list', $skin_list); + // 설정 정보를 받아옴 (module model 객체를 이용) + $config = $oModuleModel->getModuleConfig('message'); + Context::set('config',$config); + // 템플릿 파일 지정 $this->setTemplatePath($this->module_path.'tpl'); $this->setTemplateFile('config'); From 75a8cf6665326f0ac05f24474d2e405a9e09fe91 Mon Sep 17 00:00:00 2001 From: k10206 Date: Fri, 30 Nov 2007 06:01:44 +0000 Subject: [PATCH 095/265] =?UTF-8?q?=EB=AA=A8=EB=93=88=20=EC=84=A4=EC=A0=95?= =?UTF-8?q?=20=EA=B0=92=EC=9D=84=20=EC=9E=98=EB=AA=BB=20=EA=B0=80=EC=A0=B8?= =?UTF-8?q?=EC=98=A4=EB=8A=94=20=EC=98=A4=EB=A5=98=20=EC=A0=95=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3119 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/message/message.view.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/message/message.view.php b/modules/message/message.view.php index 1d7adf2ff..1919a0e7a 100644 --- a/modules/message/message.view.php +++ b/modules/message/message.view.php @@ -19,7 +19,7 @@ function dispMessage() { // 설정 정보를 받아옴 (module model 객체를 이용) $oModuleModel = &getModel('module'); - $config = $oModuleModel->getModuleConfig('rss'); + $config = $oModuleModel->getModuleConfig('message'); if(!$config->skin) $config->skin = 'default'; // 템플릿 경로를 지정 From 4d9aa7fd5fbea597cc944cb2978cff4bc53971a6 Mon Sep 17 00:00:00 2001 From: zero Date: Fri, 30 Nov 2007 07:34:31 +0000 Subject: [PATCH 096/265] =?UTF-8?q?=C3=AA=C2=B2=C2=8C=C3=AC=C2=8B=C2=9C?= =?UTF-8?q?=C3=AD=C2=8C=C2=90=20cozy=5Fboard=C3=AC=C2=8A=C2=A4=C3=AD=C2=82?= =?UTF-8?q?=C2=A8=C3=AC=C2=9D=C2=98=20listStyle=C3=AC=C2=98=C2=A4=C3=AB?= =?UTF-8?q?=C2=A5=C2=98=20=C3=AC=C2=88=C2=98=C3=AC=C2=A0=C2=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3120 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/board/skins/cozy_board/header.html | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/board/skins/cozy_board/header.html b/modules/board/skins/cozy_board/header.html index 03fe9da82..06a1e2f63 100644 --- a/modules/board/skins/cozy_board/header.html +++ b/modules/board/skins/cozy_board/header.html @@ -35,15 +35,18 @@ + + {@ $module_info->default_style = 'list'} + + {@ $module_info->default_style = 'gallery'} {@ $module_info->default_style = 'webzine'} - + {@ $module_info->default_style = 'list'} - {$module_info->header_text} From e511b851e8b9004f9a7596f86404ded616472ec7 Mon Sep 17 00:00:00 2001 From: haneul Date: Fri, 30 Nov 2007 09:09:05 +0000 Subject: [PATCH 097/265] =?UTF-8?q?albatross=EC=97=90=EC=84=9C=20=EA=B8=80?= =?UTF-8?q?=20=EB=93=B1=EB=A1=9D=20=EC=95=88=EB=90=98=EB=8A=94=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=ED=95=B4=EA=B2=B0=20prototype=EC=97=90=EC=84=9C=20?= =?UTF-8?q?element=EC=9D=98=20insert=EB=A5=BC=20=EC=A0=95=EC=9D=98?= =?UTF-8?q?=ED=95=98=EA=B3=A0=20=EC=9E=88=EA=B8=B0=20=EB=95=8C=EB=AC=B8?= =?UTF-8?q?=EC=97=90=20insert=EB=8C=80=EC=8B=A0=EC=97=90=20window.insert?= =?UTF-8?q?=EB=A5=BC=20=EB=B6=88=EB=9F=AC=EC=A4=98=EC=95=BC=20=ED=95=A9?= =?UTF-8?q?=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3121 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/board/skins/cozy_board/write_form.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/board/skins/cozy_board/write_form.html b/modules/board/skins/cozy_board/write_form.html index 64c151219..8689e278d 100644 --- a/modules/board/skins/cozy_board/write_form.html +++ b/modules/board/skins/cozy_board/write_form.html @@ -2,7 +2,7 @@
    -
    fileupload)-->enctype="multipart/form-data" class="boardEditor" id="fo_write"> + fileupload)-->enctype="multipart/form-data" class="boardEditor" id="fo_write">
    From d99d82a6d2060e700515cdf5de949b27066cec30 Mon Sep 17 00:00:00 2001 From: k10206 Date: Fri, 30 Nov 2007 10:29:51 +0000 Subject: [PATCH 098/265] =?UTF-8?q?INPUT=EC=97=90=20=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?=EC=8A=A4=ED=83=80=EC=9D=BC=EC=9D=B4=20=EC=A0=81=EC=9A=A9=20?= =?UTF-8?q?=EB=90=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=AC=B8=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3122 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- common/css/button.css | 1 + 1 file changed, 1 insertion(+) diff --git a/common/css/button.css b/common/css/button.css index fb4ae9dbb..8d7b74802 100644 --- a/common/css/button.css +++ b/common/css/button.css @@ -136,6 +136,7 @@ span.button-behavior-hover{ a.button:hover span, span.button:hover button, +span.button:hover input, a.button:focus span, span.button-behavior-hover button, From d65a314a2db7fa6593211e7aba19c84f2e5dfe90 Mon Sep 17 00:00:00 2001 From: k10206 Date: Fri, 30 Nov 2007 15:48:26 +0000 Subject: [PATCH 099/265] =?UTF-8?q?=EC=97=90=EB=94=94=ED=84=B0=20=EC=8A=A4?= =?UTF-8?q?=ED=82=A8=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3123 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- .../editor/skins/msword2007/css/editor.css | 4 ++-- .../msword2007/images/bgBoardEditorOption.gif | Bin 3540 -> 0 bytes .../msword2007/images/bgBoardEditorOption.png | Bin 3433 -> 3333 bytes .../skins/msword2007/images/editor_btn_ac.gif | Bin 1428 -> 1008 bytes .../skins/msword2007/images/editor_btn_aj.gif | Bin 1440 -> 1507 bytes .../skins/msword2007/images/editor_btn_ar.gif | Bin 1424 -> 1004 bytes .../skins/msword2007/images/editor_btn_bg.gif | Bin 1681 -> 1701 bytes .../skins/msword2007/images/editor_btn_c.gif | Bin 1608 -> 1623 bytes .../msword2007/images/editor_btn_copy.gif | Bin 2004 -> 0 bytes .../msword2007/images/editor_btn_cut.gif | Bin 2060 -> 0 bytes .../skins/msword2007/images/editor_btn_i.gif | Bin 1601 -> 1590 bytes .../skins/msword2007/images/editor_btn_id.gif | Bin 1618 -> 1615 bytes .../skins/msword2007/images/editor_btn_lh.gif | Bin 1690 -> 0 bytes .../skins/msword2007/images/editor_btn_od.gif | Bin 1614 -> 1614 bytes .../skins/msword2007/images/editor_btn_ol.gif | Bin 1574 -> 1658 bytes .../msword2007/images/editor_btn_paste.gif | Bin 2020 -> 0 bytes .../msword2007/images/editor_btn_print.gif | Bin 1963 -> 0 bytes .../msword2007/images/editor_btn_redo.gif | Bin 2031 -> 0 bytes .../skins/msword2007/images/editor_btn_s.gif | Bin 1656 -> 1654 bytes .../msword2007/images/editor_btn_saveas.gif | Bin 1989 -> 0 bytes .../msword2007/images/editor_btn_tag.gif | Bin 1600 -> 0 bytes .../skins/msword2007/images/editor_btn_u.gif | Bin 1598 -> 1629 bytes .../skins/msword2007/images/editor_btn_ul.gif | Bin 1635 -> 1626 bytes .../msword2007/images/editor_btn_undo.gif | Bin 1905 -> 0 bytes 24 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 modules/editor/skins/msword2007/images/bgBoardEditorOption.gif delete mode 100644 modules/editor/skins/msword2007/images/editor_btn_copy.gif delete mode 100644 modules/editor/skins/msword2007/images/editor_btn_cut.gif delete mode 100644 modules/editor/skins/msword2007/images/editor_btn_lh.gif delete mode 100644 modules/editor/skins/msword2007/images/editor_btn_paste.gif delete mode 100644 modules/editor/skins/msword2007/images/editor_btn_print.gif delete mode 100644 modules/editor/skins/msword2007/images/editor_btn_redo.gif delete mode 100644 modules/editor/skins/msword2007/images/editor_btn_saveas.gif delete mode 100644 modules/editor/skins/msword2007/images/editor_btn_tag.gif delete mode 100644 modules/editor/skins/msword2007/images/editor_btn_undo.gif diff --git a/modules/editor/skins/msword2007/css/editor.css b/modules/editor/skins/msword2007/css/editor.css index f86cc6946..c34e0a9a9 100644 --- a/modules/editor/skins/msword2007/css/editor.css +++ b/modules/editor/skins/msword2007/css/editor.css @@ -3,7 +3,7 @@ .xeEditor { } .xeEditor .optionABC, .xeEditor .option2, -.xeEditor .optionDE { clear:both; width:100%; border-bottom:1px solid #c2c2c2; overflow:hidden; background:#ffffff url(../images/bgBoardEditorOption.gif) no-repeat -3px bottom;} +.xeEditor .optionDE { clear:both; width:100%; border-bottom:1px solid #c2c2c2; overflow:hidden; background:#ffffff url(../images/bgBoardEditorOption.png) no-repeat -3px bottom;} .xeEditor .optionABC .selectGroup { white-space:nowrap; display:block; height:22px; margin:0 .5em 0 0; padding-left:1em; float:left;} .xeEditor .optionABC .buttonGroup, .xeEditor .option2 .buttonGroup { white-space:nowrap; position:relative; display:block; margin:0 .5em 0 0; float:left; height:22px; overflow:hidden; padding-left:2px;} @@ -13,7 +13,7 @@ .xeEditor .optionB, .xeEditor .optionC, .xeEditor .optionE, -.xeEditor .optionF { float:left; background:#ffffff url(../images/bgBoardEditorOption.gif) no-repeat left bottom; padding:.5em 0 .5em .7em; overflow:hidden;} +.xeEditor .optionF { float:left; background:#ffffff url(../images/bgBoardEditorOption.png) no-repeat left bottom; padding:.5em 0 .5em .7em; overflow:hidden;} .xeEditor .optionA *, .xeEditor .optionB *, .xeEditor .optionC *, diff --git a/modules/editor/skins/msword2007/images/bgBoardEditorOption.gif b/modules/editor/skins/msword2007/images/bgBoardEditorOption.gif deleted file mode 100644 index ec7bb62a80d9d60cf4ea760e6626a50d289b072d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3540 zcmXw)Sy0mng2vHt!L<=7$Atin!`hb6NYkuiL4aP1aV-cC0^8FC0UgJ6EI~x292Wvw zRye~El5pkZ2!{~va7Ydi5D`L71cW49;Y_%4ll*g#Y|q1fPv6_`<*VNp85IEz`5)$Y zz7CTP4jl0jPpX`kX%;uN)8ZqJV<8sSaIy||MCB4`6tWaU+mu3FprKJtALSrB9+CC%+1R$C@ex1mz0*F%Q0A7MP*fW4W2+Gktwxx^$pa< zrskISt!=dSj?S*`o?d!i|G?mfAqJDh_-^Fm=-BwDiO-W?rlvVFTpnK_6wQ8}n_u|0 zxFnWHmseKT)@2);TiZLka>d^M!QqiorPgS5`eTC;FqtjZ6Pw-Pcjqoc=+r;wUAX9X zpF?l_jB@=xx)##c^rZ~+r?eGLU-LB9`@c#rNAZo_;+q?)Ih6% z0{+MT%FIBUs3AQ6+#jL`XbE)^?=h8pK z40TBcQs+DV${XrlW@Kz}>tYx^tHTK0{wj~ryFP~e-FH`@O!~&>;@{tRz-RVtP2;|g zsfV)qcX-4b6OEqa zoKkP`8sf%APb`4$U|lpeX16;y`pS@J+)`z^XRp&__B`hxg)HAS!gr(KQbOuRA?OKh zqv&#`Vguz}-KcJ0&=~5yAm3-w_Oz<@xxB_uL)0gYT!@WckuT!_jU*mi+Dp z_I4>5Q$NUSUoSqD*CBS><@Ik3d-4XPqo0CW;FhLnEWAinG@*m`70tK^zrB{~gtWc) z#3vnlt+ko^du`MrzkON@K5f69*4nY((KWQc-$|eHJLno*Ogrdi?sgpXj2QM0ddD4a z9MUJi0)o`F1b8zxkkDqZ*SARO|)1{tp4!#`V;2P<#nY@&k zuK5B=>C#MH&N|dgd!zidoNI)1?Tl|*mzL|#IMnh2r~P&OTTAIW0a)Ip6aH*G)QQ5K ze$>z2b$_n^3i0XI&q0Ha^z-qNKOQgqn)v+q8$6}^c=3ML(ectl)Q<-7W5RQTB(<&E zAWdf+8J07qe>ASVUV3g^Maa92Yrl7w8P}0c0f4N){ROa5?9&5mqJx#d7A`Wtv|XL} z!n8w7=`rorW+_c_Dk{KiSF{jbnD=OHJ?8x`hSGdMpAN7b4lcd095LlR7UhUhX;F?(}{i|@#V>}IHmW*u#%-ZG0IRs*??`rOPfj2)@w5# zGE_E;dip23RloGoegepQ?KZ1X_1grUsSZw%@zb7a)}T|N&7Mn~sUWtdJOkZ)Sq_;Fm1-~ue)AP0XZp5TgGD;GcsoUL?s#f(#n6_k z?lYW-P;CVc-Ez$*Y9=~aTS?@%To0a^f#qncsLtXSfM$Z4Dj$ z-ajRZmn_xdnf&(wSu?x`W-Vddxit_K#ed|fBXXdvHwiQRC!sphEV}hpTa+LzSw|N0 zTZ0%gf)_bDip;qUJRK!`Mb_0SplzW`Gr~-^u1<}Xhk1mHa-_O?fZul8I3s#z)-^bs zr-eI3&*pjRsb^zpcig$NMWOme*K*ojpXjfp$@(UcfEE$V{ff!4>zlpLw?iVM=PJqi z7T?(R=tS-uo~?f$Sl$jziJm7*^{rq*J1mPkUvJj8g`e+;M@26*c^=asu^qnyVFx*mZeg|5L3|oB8#`YW;QU!&-Y}Y zVpcXijZ98#&np6NWfxy_dbYghbz98pezK8m7Ylka8N5|xj&WFaz85hav!*2*M-;KW zIZM1X1KapfUEcdv9;ez@#s%uQZXr={5{}3B>fFQ=nU(%fJ*^ z*oVpDZ(Xqf)8Q`tI23gIs+Wlaf%R7s_}kaROf&JA{^~a9j^8~K7cT6_Gx$3JZ%n+0 zE(64A==sjWbFPg6!QWN_MszDu%9q& z{zk`q=t_w_NM1HCGKC*{vIGYYEas(gmmxYT_VAIHMa+Q>^%De#Pr@vcSV2(S%)OlW3+1WVegu75(6lUFU#WE*-V4Bi<)=iLzITb9_VBT1_yf3ggf9}bx zq*%9o<5=88p%y=E-3i39_$e?QdD*%P7O{j`LS4PZDi6QFo<+g*O~x;SoR(_I8ih1oPX?8vrHoQZqSrX`9-c7sJG z;TxNddf}rYGR{0lvFT}XANLbQ=EY&#F&+EyFeT0+UA7sRqL0cfk!8(dGmc*vRiomp zn_hN+6E~_Qh^)I|cGE0&RNoeNvVYHR7K=s=4AF^lY4x=1!Wb|eXVX&bRz=*Hc}Zk5 z4BJoC*fFa-&Td||+W^s+%_y?lEWb$@gggyK+Rwm|jtJygBJvy)=`2RN07zF*?nQ9! zC3vnIA{Ru=^EfanKv4z=^$Lu74M$}nPzWL_hlzSCM!f@2 zNKkPexVQjbT!bhtCKi`6i_zj@3{Z>%l~jUDs^KMgLMFLZCTB zG?$6yi_t;=Jqs$I1D7wr%NG&lVq&?JS-v7JUjxczAj~Ehvkk}WA}|UfW}k^U6l0VC zMh(Jh!B{;UYd~NDBG$~rTE$o!fOYV|oesgBNy0hqmHZnHcaDW~mf&1WI9HE~iy;-4 zk}BM?D?p?QPgcccNyQaYg||oL)sV_-NtM^LD}70oeymD=No9bkGSH*yW=Peoq^h9o zDln-klvVY!r0TY*D%_*`PDu6Lr0R(5Y6z)1npF*zRKrZw@g6n5gw*^u=~O~?jU7&^ zNoLjDm()Bk)jagTKMKJ=PQpLQ#;20-X)JuY1pmT>&+s6;3L(5sB4lP05F|nli||%L zcxNIYJ&1WB#DXMZQ8uxdL@Z?y(GnuYM8tWJDnm%sNhEwWiAW-mS)^JCsoq4Q?vXAB zl3S9+g{InBkGi>#x`m{=#q2sUsZPqOTanbQnd)R7^_wB}+e!7i+4Txi{XVPy zP*Q*3aZ2scpbcrzCp8$d8vs&+nblyGG}ufH4xZGc)1lNe$yCQ2>RB@N9GmJarMj4@ zuAYq-LmMw8H@f9Cg2;`Y?8eK|#w+GVZ_lQyp-tD4o37_H`I4Lb*iHV@rT}wOpl9>V X(B@mo%|SWMU~+S4Y4g83IE4KlRq;qI diff --git a/modules/editor/skins/msword2007/images/bgBoardEditorOption.png b/modules/editor/skins/msword2007/images/bgBoardEditorOption.png index 5e1041c40d958a7cca57ba331bdb28018c2ccd12..c17e3a74cf94a6429d0bd73d60f5196fb7a4ad8a 100644 GIT binary patch delta 607 zcmaDU)habXoJ*O5je&uIWwSf;M#cGD^#-0Ujv*Dd-rU*9>1-(C9B9Azuei^ARwnr% zmUN!g7U?Wk#m~O}Ysn4N0|R=eCvInkaTpi^6n>Q*&4xP5M_CX#0xnQh@x5H6RN#G|E)n%eW3I<3lbO2V#f!3V99zg z>A>2EVy%%GlFkJU?Bz&YEe>P{uTVhoY|{Z*gwh7C$Yf+EyzAbFEXxLRAH;r;9yA9k zCL@It16PXMBZz~+#viD~=QqXd9)u$p4%Et_I9PxkIZQoGP6VL@YQk(Jy$x(kC|>^q djH>_tnHlP$q#4Zf?RIEGZ*dUI!^FN>py%fXooYd`r52sa8? zsqBb7^dmQ<^+MU}x7)uTKh6Zy1_cd?KmS$ko5cv@GcYt{?tFin3&CgTIsNnjAA;}D z7&BcE!DW~+y;^ezGXq0COw7Rlpe&3HG>+?Mbrnb+1`PD=_w&7j@qqLhYc(X^g2rZR zB(CVDTqK?YBWpPlS1ZL6VKUJE0EK^Vk)%y5Pz-iFcddXOA)PR<3DqK&J4m6RG2tz$ zr<0KajX}!g0J0a^xPbnF`=24?L|Gw{MGG9R-3mk4%aAaq4%OoAC=U7j=pJ%tH?K)% zLDKx}=zbKN5grEFA9CUzYSaZI`*?xVG!&ayAKgc>3Dt`!`kcsN{VetOcBEJgPR*NqV~axvX z*X8)q;Pcw&_~Y&SoVnbeyWWv%HU`Vy^vmA!v9cEdlMMq3e+U170D^;rg@%GAD~gMZ zjgBiSD3X(um6j+aBbu9>ot`5pC!(XIrKTq&BB~;Et*)=Ht0EpDwYImoxgi`Cy}q!p zzP=d|#m2|T$q^V3%@DxQbj}bL57yV%+1d{S1>WD$t>51p66WXV>FN>+1nvaku)(H0j{pAv1}LC^a};Rc zfe0p8U>poK=-`78G6=_n6jo^Ag%iG^p@yo_vEdtTgec;OB$gOr8z`pOMm#E_$i|B> z#wg>AFQQ?ijUC>IMjAZ!=;Mz-@~Fm;M5+-_U6Dhsq2yJPOg8DHl4e91WrtFlamJNc zW~t?tSC--Bmu18Qrk7%rY37+|rdcK!Y_{p+5o?Zkh V=%9oa8YmfvCaUP7j3OEc06UIqUQPf2 delta 905 zcmeysK83s9-P6s&GEtntiQzi~!|d%37VLR)<>8l$_daep^?du;SG&%?*?#8bzRMr> zUV3-<`p3i9-XFaD=IHegr|x{c@bLS^2Vbr~{c-8R=UdNzJbwFo&dxjYci-E4<-_ia zZ+D)5z2n@g{Z~I6xcXuL)%W`@zu9x)<$)`2Pu~4@=<3@Ow?7}d`SJ94 zx9`f^y_a5{zW3$yz0b#PyxmwP&N#V&k(b7pXL2tiS3Spn21X7Uj|~eP8?EXzVoq#W z=qznl;W5W!PHbH4&Tm`RA>+AeiKnDR)`~TaE0&&~t{;A^z;W@iv$HLV z%MtcQ2Xu91f`aXi#;Z5?QLLc2^MfztW*{C;7I%Gh|O7dy%HFj*C#C9#`62? z0WQIe%d28fhc&m%lSqz@^GyPULAK<%Bl7GhUC-p{#rG>y}hIO^)}xn z+uz?m(EMFaXvvO`k55eI7Ytgm^Yilyi@7b6mhAfa`o?DY$VE$bPuf|pzgPdi<7Af3 zpPye`UhLoWjAy3dhll5T?c2^s8YdojasT{&`~L=MDHmCUS(=^;HTtG3Y!&u3dGVlG z!0tthShT~(Bdy}+S|17r0KS)=%LN=TTes&v7Thi=j_WiOvj zkJ}~aE*Uo^^V!UdWsz(GIon=7n_aLe^WdD4YnjjI7T;U=d|u7Bm&@n1v1q+m&>|-F zLa{?_)r&L{kPjJ(Exujnx>E+THX{%N)Z7#W$+1*iL)uFItTGp$TD<(;uSha?& z-Y9(aYNkr1*K4+1%UZpr=E*GW6}vuNJih(_oA#Rx`+p_A*;sd`bqRFP5!-x9iO!@8i2a9MgWk=l!+B_j`Xl pTfKg7@t4={_cO5HSuevPp7Y@#hj7pFLplIyrOlA8)|9f@w94nV&FZ?(?6=J6zSHo%((c38@x#{d!PD%;*YL{R_0Zw>(ctvg z<@nOz^VZ|_*W~ru=lI*^_2cdPl9%uG5*f-JQGPmb2HJ zx7we(-o4cDyV32r&+E9(>c7?Sz}4`-)$hL3?7YzFz|`%&(&~|p9+9sVB--ft-0At- z==kLB`s(uhw94bZ)$YF3?Y+|K%ii?M-t)%T?UB|ek^wOw&q@E#N&nDF|ItqW&`j zh%)Aj#fum-Vg!SN#+51{Ly8i{NXc<4d9w(Z-tft;A21cUG2z=H$-p&~;Q5Xh4& zU#|Sd3Kr0#OP@}i#gc>A4<<~*y}S4C-z7%>L1U)8`Sa+1&7(on@r;`H@Z-ymf952c zHTd)E->;udOgL`@nAuGM!qHPCZnTkL8w@t+po4Biaug(uFw)3?HdzQsRF5c9CQrg79n@kVMmK~+(F1)h3J7t z9(XkAQP8whV-!qA1&_Dharj~@`oQ^`XT0+WRm#@B9vhg2q1y9$R;M8Ei#ED zbJj_xopsi^$Z45WLW!S%{uwBsfMyb#CYM;E=%S1^s^}$}?B>WJlvZl#rIkA3NO5I! z>glJTg6dp#q*ixbD5$2Y>Z+?EM1?J|#>gt`th7#lbjz){=Bn$i9o6FNufPT?>`Al~ zYwWSeCL7Z%v&b?_i_Xr{Q!Lb0Ywfkz9tF#`u(Zf+RIj|^O1R{fYp%HAZiULasI~%7j3lBql%*R(o8qqv~>Xi06RPkR+#_* delta 955 zcmV;s14R7e3!n>sM@dFFIbjz7LIC#w0GqeqpuFVOA=+Oz0v8( z-S)!O?a15n#@X@9-uBJk_RZYy*5&xsEt|E)6ro*nqiOG{FQ>Ki09)iXA%^i3S1=(mK$3G_3&*IatV@OSf*_BN~4uG}zmKZOy#}HVk+`xUk{Fhbtt& z;i9n%zcd?D=&+-O<;$2eXTGsO0))??LyHzI0Eh(`s8g$6y?O?S9uZ>8o=uy!j1fOD z=-$n{cW)IWN(diLytwfaPy#4l&b+yE+ejGpAhE9L7F^C<0^kLXxh$gD&qKqP{ z$)k`)D(R$;Zer=Bm}aV}rI~c<>8GHE+9@WamTKy$sFHfgs;g$m>Lr%Mg(~Z;wAOzb zYbChinqjV$P~z*azy>R8q-$t2ijtL?VjV(ZAa z-)0D|Baf78?z!luTW%xlvYTPMjVL1Ty!6&TtTyX z*X8)q;Pcw&_~Y&SoVnbeyWWv%HU`Vy^vmA!v9cEdlMMq3e+U170D^;rg@%GAD~gMZ zjgBiSD3X(um6j+aBbu9>ot`5pC!(XIrKTq&BB~;Et*)=Ht0EpDwYImoxgi`Cy}rG$ zu)i4*#m2|T$q^V3%@D!Rbj}bL57yV%+1d{S1>WD@(XHSc66WXV>FN>+1nvaluVV|Jp*CBBcqFyLj{J&D%su zksLSzcXbswM-d}BawuNRxG`fLMvm~)(H0j{pAv1}LC^a};Rc zfe0p8U>poK=-`78G6=_n6jo^Ag%iG^p@yo_vEdtTgec;OB$gOr8z`ojVmvCc;o^%h z#weqUXw+C^hc=>-#*RGp=;Mz&sv+c%L&ihoSsF+tspL_TOd@H8l$_daep^?du;SG&%?*?#8bzRMr> zUV3-<`p3i9-XFaD=IHegr|x{c@bLS^2Vbr~{c-8R=UdNzJbwFo&dxjYci-E4<-_ia zZ+D)5z2n@g{Z~I6xcXuL)%W`@zu9x)<$)`2Pu~4@=<3@Ow?7}d`SJ94 zx9`f^y_a5{zW3$yz0b#PyxmwP&N#V&k(b7pXL2tiS3Spn21X7Uj|~eP8?EXzVoq#W z=qznl;W5W!PHbH4&Tm`RA>+AeiKnDR)`~TaE0&&~t{;A^z;W@iv$HLV z%MttuZ}w_<d)MaWYHi z&(AL|FZOSG#xv9K!{h#$-1E;!8YdojasT{&`~L=MDHmCUS(=^;HTtG3Y!&u3dGVlG z!0tthShT~(Bdrp4hSysIat^kN1h!~A>QL#^U=@!IFg)7Dwrz`&XlzZQtEkDfjK{rZ zQ6G;=N5njQ+#i1Csj^sp$3i!$dJnagPbPV-Qe>0KS)=%LN=TTes&v7Thi=j_WiOvj zkJ}~aE*Uo^^V!UdWsz(GIon=7n_aLe^WdD4YnjjI7T;U=d|u7Bm&@n1v1q+m&>|-F zLa{?_)r&L{kPjJ(Exujnx>E+THX{%N)Z7#W$+1*iL)uFItTGp$TD<(;uShZ$T ztyTEyh9jj~uh(q3CZ#RE;}KWZx|%N!U#~yFroCo;ok;eYjm5IRk8e6-_WI4{)2|fQ zZdu^B`ncSUwAF97-AS5#eEWkY>+l_AQ?lRfe6cKAPxj5W*Y9?J*c5$y&zEc2@ArN_ jxA6VGKi^)j-&e$<^WgxCxQu}uhx(cihj^4_1Q@IVhKJEK diff --git a/modules/editor/skins/msword2007/images/editor_btn_bg.gif b/modules/editor/skins/msword2007/images/editor_btn_bg.gif index e56b89ee9a0cd9692fd8e96a2d132f82f047b40b..5ef293348022e3f879b28baaae101ec52d0cb685 100644 GIT binary patch delta 1564 zcmV+%2IKjW4W$i#M@dFFIbjz7LIC#w0RR60>GEx$yyTy|-pA7FilEDkp2Lit!F!Id zdyTJrj<0foo1U-F#LU|0?e<-AmT!l!c#pPkgQJFlIyrOlA8)|9f@r@Yv-%ICMu>Y%gCy3g!?x6J9j)9|Od)4kH}!`Jb{ z*6+d7?8Vpc%G~wP;rG$t^w;J1)Z+Eg-}2Vu_1ozA+vfG-?fZF|!h4&dD>q z!qx4_+w;bM+40NX_RZh+&D`(Rhk=w%HzJ&?Y+|K zyU*s!-t^1f^Tyci%G~hR<@MI&^WW?E;Oh0r+wRxq_1Wk3)#LHX)!ymk$sL;OmCs?TFdqkJ{vu9RVUFtFch(@^tF)bL#JD>hEgo z@qOy-YwGN5Lqs9$?|S6tgz4;vlWYMw1L)XkldAzSII>pHv|#(}yZh|C{O`m4_1gc? zN&nDF|ItqW(^mi0VE@-@|Jrx|;*bC0kpJV8|Kyne<)8oOq?0cKAb*Vi;g$dBtN-h` z|Lwm2vm5`!P>g%$ErfAcPpB<^z%| zVZw~8_V<^BLwQ&TwH4qo?jSVAaELq~RFCaT>1<4^mn8e~GHgbrV zqD09^KX>wAdIN_IVIiG6ufbtr1`8Gt6DNq{(7)ZR{odw5;Do%n6S4N7Is!R7s z2p3)kM-dn+qJK-*7S3EbawMc{zmTJZj27U-i~k=l{=x<#GN3>Kz`niv_W+>K*pb4@ zlPB==w|_##!-*I!xS*eYE?B_B5m-ne#en%qK}8QL)bPTD6jo?qg)smD!xlGm=;4PT ze#k@+1C(gui72KxKn(}Acu+#G#3{F2N+zNQcbA3QiCVG7Bv}?V^h=R1p=xA&XpD!BQ0HvI|tu0U)wS zBv@(1RW8tg^$au2ly#OPk3hnfTX4z3%rkX4lT0#t@#R;bfenU1EQ>mW*f6~C(pUhA z?7>N3lYbFbOQyUGqZu*1XeyE-lV~zpX`*KT+Dk9QuvUyOzN|XQCbZe600y<-Dr_;n z8S~4r$P#B9a<(9gtTE0V1I)D4QfD1Gw@|C?G2I~(%(vi%D{i>RoL7x7!Y~M*FxAkv zj5N`x`<^t*_-D;D)5z=IG}at=4K>v0+a5L7K!4cGF$gED@WKf<(~O3uL@e>d6jMB+ ziWsZN;x`<3?D5ARBP51CB$sUR$tX|6&&n*f?DESUE%_`xebCfa7BvK>z z?1N=LI{ReL(QpR9$R|QCfacLq)gv{WjCfK?of>c@HCXd>?Pmc0P|`^$gT93UJzduY z&wtvD_O-_-r$kD?0T{@$Hav)_qxYtgfQpg|sB>fRj^27}#tu8{j3h}YsJzMs-R~SO zIcx1yE|Mgopwg=wzs6Jf=k56B&gi7OqwI0_#8W!y&Yk1>>*rW|T{^JC-W@u)=dSzi zyq_n|?*g;;JAK}GGfwaT6z|_Q%p=eIfhFB^!wvG$LzvC=*k`Z(_8Ma2{rBL9AO6MQ OlyCm|=%c@4Kma>a25HX# delta 1504 zcmV<61t0pQ4Ur8}M@dFFIbjz7LIC#w0RR60|HM%Lvm5`iX#b@s|DGNHnxSQx za{(+Z>GEx>u~6#rbn5YQLPR3!?`i7qYV7fS>g;Rk>}*3sAnfmYxc}|G+svil)3esOba~2W~S4^Vg?VMGG@4N>_P+xe+Um9RE!it zQwT>qB{zP-;_^d=2q9_)85-nf&Ye*}_|ss5LkXfjqWaiK2IoIDSfn)Zw*f+h5-p_a z7^}k!87ODWRLSZ@OjikD$?C{KH%G~|V5m%KBIXGMxHsz3#X%ScM=w{h>{-I(2wWS5 z3%{8BVxt!;TKMD%gM>l}e-@NO?-)&b^sPgO9O>D&qI78&uw%on=FMC=aw}x(hQYhH z@87_A_ZZ#-fbrwVlLH{mqd5=d(2qNhK|MzF=+%E{|8X7qb{XKqi~k=_9{h~+=+moT zf1ZZ>_weJ(r;%cW{rmXy>$g9tzyJRL1~`c|k~~u2BM2s_;DQE9f5HqU5K_|7gl0q- zVI+}AbIFF6lyp)`9HDUuBrkO^1}2y+^T~>z7=@D=XtY5h2|tApN+`&9(us~Pnvq5u zb10?32~PFW3o^MRnG01`!4ZcXTXpr7CA{zwjV-lcX%<>)J=xYNE5eJs{koTK3R$}7~EQi`D)v0;ZFnuVdn1tn-w z%A}^i0t+;#oRaA&oSt%8YO8J1siv{S0*xxEpqk36snBK{Ih?Tnx~eL&$np#;tKhoI zuDtf@D=W0n;!G>Vw$hz)#~jnlFTOB)Y;w5ZB1|yAQ2Q)$f5{{>OflRRbM0};C_{`c zvyeN>x#*^=Zn?S`qsY7P#w+iAYf2q z%k$Kub3Hw}e-Q{GLZaZ5&g{fvbUaL&@y{KABoZYA7L*{5(drmrwE zCBSp_ItrAnfSPp-(#V@%m(Y&c3ZRp~+zD`02O*63c?8()&~`m{ItT=gz(#cx!bqb@ zK}mu~v$s1p#*H>`j2t#Pb_ zqs{Evybi$Z++3skHMZ-%4K~1IV>|HK1YrE}$S1FS0MiKI{PWO9FTL{)RB!$D*k@mT GKma=-qcPY3 diff --git a/modules/editor/skins/msword2007/images/editor_btn_c.gif b/modules/editor/skins/msword2007/images/editor_btn_c.gif index cbca4ef09a5e9da1252bfef8ba27661f104cc979..4d69b17c899af9118fdbf0237216209ba7625fe6 100644 GIT binary patch delta 1404 zcmV-?1%vv?4A%@UM@dFFIbjz7LIC#w0GqeqpuFUOjGffs^wHk&rnk+**6*me&X}jW zTV!y=*YJ@p7zWqn_|o9>kxwT!#@h3Bfso1F_QKWe!PM+BH$BMP^T*oq#@X?nt-#CP z_P5C0&ENLT-0#re^4I40)Z_Kh;PR23GZon8_Sfa~;Og}yDlfau;I_!x%H8pi-yawE z)&BY7{`%$r`{+J9E=fi@{`Ju5-L#Vr0VE0g?7aEx!2IvSlRNazOivi9V!!?lZ4e@;C5=(GRt#6UbT6A};n@5=n~(Ean(|J;H9+=Bn#i~rw@|KXJX z;g$dBtN-h`|Lwm2vm5`!Q2)C{|G-TDv^{%fMW>Et|E)6rvprBS2603Q|DGNHq$vNT zD9UdG)^-H{jRpOT1^9{u;e7?naRmR32LFx*j!y(gC;~GblZ65uM3xl)mlQrF1-5Jt z{Fx&8mm>d~BmbKtky#XTM-cm`ME|Nr$AvfMnLk!J80el$|E^Q^r%*pD6+tZ*{H|Q= zqgMa0UX$zsA%Fh>000000000000000000000000000000000000000i000007XU&4 z00{p80SFvOu%JPKN2DlR$grV9DN&wCoJg^v#V1CFXxzxLqsJjomWW)UWQx6$RERKH z(qyE|B}IbBoH;Xz6CpwD(WGg^htHosft>i^!yZteG=EqqUAlBdj}$EIwP3n528pX! zuZl>(Ljj4C_Of1u;i0VAvK)4NC~FVFS+g%P$epX90Fn+H=gZ*t2Wj&fUU=@8H9W z{~!N7fcf+2)2lb1rM>(2@Z-0~Vx_+Q`}p%?xx%Ht|Nj66c!d~X6bQx_TYxo67+!$U zhJg@@;RYKNR#;&dqO8G&Jr-8zhAC>CA>xQ4rhlOY8fVx;qKImkQVJ-X#3*Boo_x{? zC-#^zBPXDgLW(Ar1S#Ytn2=FMCYOLUq$Z?5QU@GRMhV9pdAtFoJ#~b4^5I7yg8b13oO{@VC!T;vGRYx?5Hg4%V^i!VIHh&N=GX!*Dtak7M!07>iR5Ipf%aF~;76Eb_?Tgwu^T_JA|8$lA2* zvdh%r83I;|tF_8)Nj*#so7=GRFvGv^_`{b96IQQ*o^f zGtfNa%raHmQ}x%)P$M=q(d1H%F4jmhHZ}IFJazOivi1n%ufw&AR8BmT@BtQo-;3J4c;3Q%;>Usi z;gsgfhX3fR|LeHe$DIG|zT3>D;M23#xpmXEbkMVM&araMuyW0{g3h;v(!Gw=!j<07 ztpBqc|HM$#q)5=YiQ?A1|GP#1z)a4aMgO!t$Cg9DkV1QAMW>EtlYLtMtunfcLbQfM zu7pLZf=5s=2603y3ICoQ|D`Cah*+tISF(;=u8Uf?l3>bj1J-r~|BVIxj0O0L1>t=K z%y9&hUjisfmlQrF1-5Jt{Fx&8mm>e0BavAYb4L*Sr$qm%M#qIWy_ICbnP}#jKUO&y z=$=deu2c4>P(LdbK`j@-nQXX|X`+H%{H|Q=qgIp40wI4a000007XU&400{p81qd8S zu%JPKLYOFA$grV9CQFh?oJg^v#Uw#~XxzxLqsJdgI2LIVprjKZMt&Um_(MjImoQ-x zLE@uFfS565=-A1VCyx_5bOh+x6UK_8NRg_@pYqxxijYgo;go|K)ST))2Ja#NRa}7>({Vj17OWM1_~6ibHBcQ z`$dEZx^@5lZJ|Yr;JJ+(pCO^S^XJf`OQ3O~y7hnS*t1{2z`eWo@8G!){}@lcy!rFv zrKn%ezP)=Xu%JYlPrttX`=Ovz+0Vbf|NpCKfyIDWTtP)wkz`>77G)6VASh;xA>o7* zk^zYrV+26qgq~3H#fKn*7{(M}d=Ws1AgVISA}qGpVk3?)vPb}4xX5BEk{qJrjyfX3 zMHhdG9MTn!hrAL98b~IIgXt( z00IbdvPlYvD2h~438k@VTFE7ySYipMu!(#VfaYU?IX zL<;OqM1?fc~H_jj1WeV@sMq|KDG z*^#i-n6}%Tx!kzT=(EV-ywK^u)a}XL_QKWet-jO9+w;cR@w&|7%ii|Q-}ct!_|4qz z*5vl(?)mBQ`^(<+%iiGk65_b^CcfUw|TfS{15z>uJ@ps>Km z+wQQy(7@2((BSaY;L=T|NQ0u{O14t?*IPx>EECK`PKjW-v9Hu|MkKD`Pu*a;{W~g|L&>(@UQ>yvfIv? z|MbQG^~(SD&Hwh&wz8oA*hK%@O#j?i|K4Q(-)#TlbN}IV|KfQ6;(hpNx7hOzNL7!o^-aNeYU2FtfG&$opZFEcJ`PJ z`kor`hzpBvP40RI@s~aFn?>@TO!KQ`{g*ubnLYiTM*g8r^rTw;vTgLPZ2q=%@vw6A zvv~5ccif|IvV~l)gIx7`7x;o4_=P3-j5PL(HT;x0`jI&MmqYxVO8cv2`>kyIuyXOP zcFLG;@OdHij6C^~KKGJC_oQU@s&VkEcGsJ0>8N$vpKsf%hU#k->~S3LeJ}EaHS?KS z^P+0>rf}t84CZ1H(Vl(ZR}JD^59)zJ=6piw zg-XJPX7KRvEC2ui02cs4000R80H4G#L9n2~g9inoFvGB+!-o!s0O^q>jKzx>Gh!s; zgNKSLAVZ2ADe}sX9a=zApddz!fe9o?inJ2LMHDJjC;-?A08AGoID-n!(xZixDO1Go z1mNY21SCkKM#aLzC=(_I0E{R>=8Fgd1U5v7aN_FKC_Gq5F=7PFP5}ebh*+wjLkPA; za_nHCqezhg0ARe}vSP#11|k@Q@M~pn79vEv08sNU4Ve%C6evLOfdK;!kj?CkLW9N^ zHH24yaKKYdnhFy*l+LnO#gQXl29QBB<^Ti$8ZvzF;9aIWl zjD_V;YS-A#eLDsK!-;$UC}3fG_7*CXs9&%Cf|?2N!4&Y4Kz)j;Sd!@9um6H)4jfou zK>`ox2SpDqU}3|83^wRsgDLc|0~SqGXyJtzUI;}DJm7G{haiS1Vu()s(1Q>;q^RPG zEUrid5M{&=#Edl7Xrql~EHTKAJof10k4sE~2OC5dY2=Yc;xP#+Y`{@R9C64YrIdEq zF{K<()=>u=q>OTh9&`8s2OV^1`J|a-!r{jpbKEhCDR<C@_95pXg8pGjDu3`nh*CT?C4n1t6JiT1gsl9?&OG5;Z0s?=j0PoxG7pA9HAF#~*C8!NwnUXgPiwsKy;P~T^M=p8ex-`Sg<(Ox#IWx^Pql@F) zj8o3&%am^V>C22h&N$mRP7XQZXrqlXv?pVGGPKjKjX1B9<2W+ygd_a$#1|hCJDsf)gI&=tCd7a9j`H(XZzKOkmb|$2*c3fL!R~9Pc=XGq(7Qh>2%B7Jvsla^bjK zzylrUK!-D)!N!oqXFdstM?AYuuyo=SANl2e93s1*^rf>Fi?A42cEU?^x-d|HbfDyJkilw;x|_G)u*K!p zcq<@4d|_v!KbPH2Q=a)EGvkIL8O z+2-}vGe=xaM9uM)Z_Bi;NjuB zzrK@|i1+yI!^F3HdvX8&`~Uy`|N77W`_upYK)^1J`^#Q*lr|M%1H>Cx%r&i~j$ z|Jh0Z+D`x5RR7#t|K4N&;B5clb^qjk|Lmgw?4Vs-lbW)|BViv#+O<{jCGUuYdop z1O2K7&9{uHhe^Jrc(tK>wx)@-tC{(q3%8wg;>4Buo*ML!4X2um?tKUGmp$^EMf0m< z;oaH%jw$_=GyRx6`<+Sro=g3pP5q%y^qfxfqEz*yT;7;h{m`l40&rCs`|W%{gb{IYZKt#!MH zUFfNH@^cXMdm8e7B=meLC@uMD&$Q^_*AvreyY_WY(E#+n;aiY7p#k8tio@ z?|m=sh(hj-O!J~@^{8;>W)|sfAM1@&@03~bn`5(gQKN8Aw0~aTR}JG{59)zJ=6piw zg-X7NYLIt#EC2ui02cs4000R80Ef(2L9n2~g9in&$ilFp!-o!8_}Eb;iN%W;Gh)2L zLxvJ5AVIqL0TfZ@di zAR#b-1|6mIY7#71U(ks{{RLk zV1PmRfW-_yB>m3^IrX5PU=^;e-@c2w^B@WT@eW9Bvp2AD@_^#v5>~Vd9B##BrjD zaJ=z`8J~P2hZ}C-F`|nk!l5IMYT!Ym9G{>f#~efw>Bbgc)VK*4NfOxxk#eAdN*;ey zS>+spTo6bbV=O?%9905RWge)Mk_R1rr0GYM5QG5;QKI~jrX6YKQA#Os^r5GokwoH@ zAW?~8hn|n<8AmCqaN@`wjPCKsBVk;yRRNGZ(kP>xsG`aydUV=pCYgwGmK9|@l1ZnI zbh?Quui(K*Bd|9A;)o-e)OANDj=+iuBaGnj$}5@-LddX$ATr4Z8PG661rU@nY$1aT zqRFqC5K_psg-o)61`Tvz!ewG$JM6TtL{f+$=o&)9Xc#y#K_zuyknXjS{2GZNhva(* z36)fWK`0Zz0ty5AqFZmdhajRbA{kWD$_bLFV4ML9=Xi6k|5Vu>e2Thd9*k}Se99jmay z#v(pbV#(B(U}E(pMjxH@B5bh2iYREL(S{o?#*v2^XPA*k94@-iMjB~|!b%OGfHKP6 zt>k^j-h1c&-OAl}gHi(!0u*le;fN`hAQ;k!wL^X{2 z)d)k5`oa_*%slIpLk%^pxWFu&K!E>|v)va$u;2%L8B0ul71!nX(%|#j=lJ98`<%JlpS#{ADK3$wMHMwWLUw|X zO;ujY-t?5BvU!D)%ii;|3;_WGlkfr^lkfr^lM4eEe?*ojT*$DY!zD_NNSsKqqQxUa zf@s{xv7^TzNsNdbNwTC#BSL_vT*pHDwyZgw?B885FVFpa9mZFh+b(*SU`4!0ts;A!hKKz zt^p=;f929Z!M87p3nlvU;NjPA2M34|TM&>Tu>&L(96L^cp)!UD5G+@w5J0o%87e}H z9<74K4$`A-q*%?mwd>a@IB1wnySDAy8a%w%&AYen-!E`%7*4#n@#7nEd|1xBx%1~A zKuDiXy}EVj1hQ-2&b@o~DB#13{~u2tJQOGBf77d9&mPK?De&XVpHKfu6)O1i>)+46 zN*68w1}NZw1a{Gg7FQ&gU=|EAh(&^1WTD^{S~S8)B8X(Dp@y4mlHn&-Y?ufmix^VK zi728d1tBM9lVTx;EYgP=WYlP5jbS)aqZeh|NQN1G_;H3AL>5UT7-A6Vh$CN&QREqZ zfBdnA8dO%P1{#l0nMNp9Qn|(-fWYy_m}Iiy2AOTNK_;1S01}8DbHq7^9FWu@=Nxg+ zac7)%1Tu&oc?22>9)T8mhbM(5s>dLj@Uh3EkVY!WB#}bOhbD(qLdm9_cIs)Tl^nv! zC6<(G>Zz!ndI=|;WP-`7u*Ux?Ypj`cf1-#WxaO+suDmMJ#IL{xE9|hphG6Wm$R?|- zv8FWZ?6c5D+w3*eR%`9G*iwtlw%m5>?YG-nBks85mTRuK)ugNLy6m=_E;aDREAPDY z!aL2q_)a6uzWYXVFErBRdoMBs7i=&x$s|LtGtV51%rOv0Eb%eT7z1%O6GM#4f5sel ze2X$0GgC{)9P?uG$tdrVi^<9;V~Z{*^8(DwG}HV`FEjhHOwBb5o%Sej y$1V5Vbi+-`-FWA%_uhAl8{+rh8h{5bxZj`@ZusGdCtmm|j5qH1qqOy5~lFQ!n#@Ow#&;bII4FeT_SiUG+$grV9DqglooJg^v#U@v( zXxzxLqemHCw1^x@vZTo+R;H+2$+D$OB}bshoav)x%_uUZ_?RgZMv)#sg9<%x04RbT zLVLIna-*r!rvWrHZTGaPiXb+!YSlU+OI8X6wq|7jWQN(ZXJgPX3jhF<2xu25$UwI) zT?;jT=o$cHx2^*sI06gC;h~1$Cr<_oZc(CwW5*o?fOuSi3kS-NStR(t`2&UvojGp^ z5IS^&Av#j4Uaf~cySMM(z#o|SLA7^fhjM8NvwS3v-ACpi*$RKRC35XzV1`+>gXb}I4Y?lm$(ASBba8YsVS#unkgi%Y?2Bp zq?T&xsivl~2`sCq;_9og#{UZIDzL&?6AZZ>q!{MCadhS z%p#k@v(QE>?X=J8V(qoqW~;5W>vZewx8R1`Ej#3vYwo$|lB>?T?6&LfyX&SS@4WQZ zYp=ZMtFswb#8E^R?H<@G|zM*KN1lx8$w&-hB5aoi{EefCn!4;DiHi%i)M8uK41I)8hE!kVh`Ll9%uG5*f-JQGPmb2HJx7we(-o4cDyV32r&+E9(>c7?Sz}4`-)$hL3?7YzF zlSlzP58Ubb+vxb@?)vKT{ItsBlaK-WO2171z)b(NJ$q(Fr;cX-tup_!J^!8^|D-7Y zr6~W61^B$od8X!r$P}wR0fddLCs8G#GrAG%9U8G2vFaZI94F}YJ%AKor$Bz_RqUbdd;6Q^C zQK;(GYsUu*3^5WL;BX>w462S}Xz;-#OqI)+Gi%OV$H$TzFhaxNIeP3j7#V)7xFDmo z>({Vf=kTBe%$3_$c;^0wyZ03wL0pWnLcF-~7^y2+%?K2mRRCQUlAx`2~}lUa>*!$k&+1}m=qvLBXnXyRi2rULRl%BXd>vK zgcd63CZ%|0N++B&$`dC7}2bLK`ljfFdeSpx`9xsiKC0OK_{q zBFn3Pu*Ux?>#MV@vRp2;(4yml zzuTas&A=)?4#b43S%_cFZxxjBWPWXrE2nFl@8U(=a%-EjQc20Rs#%cIT}- z_uhIhG}p`DfCv6f;Dq;L-7mlRqWI#BH?BD1;PE2){Ck|n zd6~j{o5Xya#e$;Bf}+Wbs?da)n=zt!--)$qU7@3zb2zSHcy(CNF+=#v8hJPg#~@!aY8%{PCV)LBDy zjRXV^DAZWvl;)ZxAn2qSJ7EF>0vryEUCVZCk`Hmtf5<&EBfxD$x17^IFW-cuejn$0ho*;rz=j~`HC)1fU!#~ummdTpo9h* z%PvlQ!OJYNG#x4L11zx1JTt`@&@{u$vdlK??6S>3Lj@1S^kVI` z*k*ezF~nFggeKsIEAF`Cs-XoJ=%%agy6kenhYZ%lEAPDY(kq`K>*TBNzWnyfA3FdC zEbzbtAE?g32q)}L!VIe;VLA{;Eb+t?e{*Qg#TVaXj*l0gSkA{Fhb;2QGm2xfI14a< z&dENSEaW#Ze{&92?Tqt{k1#{I&CXS#b->O*2Mx5B+!W1CICcp@4mVC2U9_9sMBNPl z1Ars7Q&LCWr#D=8?e*7SCz{RJW8ajGk7HA+&Dw0Y?e^QCVk5WQH(@i=+<43FK58|5 z_c!hL-+=2n&ESL=?oQ!|Pjf6aj5qH1+t_BqL>>o@KU`C(W9fvFyp*?3u@TGR@OrrKZ+4rB>!sKGo8kqr4z0 zf~n+|w@pe+oT((-}r}HARl5|t}muc*8b5EmO#p`oIz&E!jh>88GWcs%GHbpWEL+pj*$MFKD%xKfh5nmv@gqa9WsXL3Rz*5vLfF4;a zL+0{OcrLnrib5A7kh!-@>F9a^rfCNAVwyIpuW28n4ykD)nl?Z#P+CMPvwX?2WY|O` zlqcp;lX9qukJ{rNG<}EZx{^Dgj4Pi_$^%~LA#tlB!e zV3sX!D0Q1EttIYZd+aZ*@ekYM&~2CVJ5fd5DTQ6>L`G)yU`EwIE}5U#IG)?Udr0D- z>)9o3Vj_jr%T?2P8bD-VOzK7?YfOP|c-AyHZQ#tUaiwd*`E`NH!WFNmRyL#>^TNtH z3SGmTTH(yS=ggU=R3_=NRid$|R;&uGWl_JeWZYy+48yZ4e7Rv#X`Eg(3zP=b&t+G$ zaAM7SBANPxL>b~wN@PMhy+$J8aoNqFb##8_ncX6=TNU<=d2mxL9Qk#ORrR);s9)?i zs9AP1PdN4pROQ$-bv7g0ZjsIc4{WNZA^@|g?c3DSw^jiT&}=i$fV?P>7Y*{ygA?(f zAQ_xW17|WpMH#3l2bE7iRTVg24=$3Y0Q|;01zhUbPsj$skoS()~Yk{|^=LVdKLWAW#ru_TF=r zO6t!)Qmzhh04jhYxKDV&T~&H|R@xEPiL6JK%oqO1RL7M#5eet}$9 zP2t1;j&;x!IQBF0zWx&9Du_A@E&nE$n4f@JdZAQO@){5E7qnSlq>RZ&?KNl z@VY6|)9c>&i__1#TQ7%PX3At9P3aPsOl8ckNx?hZ5a>DRzL;J_N@OzqeFd}km2&8@ zHS43GtB-%=_ymqkAIW&^jW~5ZV$bO$C(Q(R{!RM|km_d|8)nw!K~J8PxE2 zbtl{#J}j>df=J^BA$ua4tR6dE_J!U&|0dfM8a51j&ip+Z=e6%O9^AhlL#Y18gK=q| zk%Zf@=uK6L4UHwX&2^J9?` zp?@A`EK^y=CA=Fd6vOHG%qbG$%kk>b2BEg#u;W9YI=bF>rxJBNvg>pjO{*ow-=(1;8da45!_<5d8o}{(~PZSgQxz_7-D3 zc3rw<82F_AnbRlP1f^lfyC}dIK3{puIC8k@O2w&w9<7ms$Wd`egX$ggLQX8cqy-1u zRno?s!^-=|B6f4R|C;vwoqH0Q*6@A;xfjcw6v6Zd|8}t~#2hEPzte4-JT%PB@%yK@ zyA!44*0t?vJ-W=9dl^0!vHPf`^zKjKkK8%5B}ZqG;=c1)mlf)x6Tu3e%yueSVSq5>&vjJ$*bL?8qOV=)~9K2(d&CHthcUy;ztKIb-gzp zuvhxdT>xC@F2}Y$UvN&Q8)`z6M+~FE`x)qWk;fk9R92yEX3>qZH+j&L>eCqa;~sFx GSAPME<*iQu diff --git a/modules/editor/skins/msword2007/images/editor_btn_od.gif b/modules/editor/skins/msword2007/images/editor_btn_od.gif index db39d5b028f2e7747935a6e6b1d742fd0b0d84b4..544757c9a0dc556efd1dac6628ce0acf55e95527 100644 GIT binary patch delta 1134 zcmV-!1d;pB49*OYPeq%z;Gn$Zq`KR#!{g!V_v-QccbCC?n#6pY!+)N~f1bvIp~;4& z&4r`Ni>lIyrOlA8)|9f@k*(5@tkI9F(3Y~-ow(eQsV#re;Pl|@`rqpLi6O5 z_T=pMb(X(*nZkIO!F!v;exApIqRM}t#)6{BhNjMsuGNdG&yB3njH%9)v)PcY(~hgq zn77@Nu+@{X)se2!kF3y{x80Sp*OIT(ox9A=+OzS8Qw(do(E_QKWe$lLSA+40NX z_RZh+&D`$V==s~|_}}XI;p_L{>h|XD_=u>@pS|FkvCFi|g9RAoLY>Rk#gITa0^^`jfI?uX zf&<4G62y+<$B-jOUQ^`HjmtN3X7(EIvKkK>a)=&Hx^!t6Nr2#4jVEX8c&uZuPBX&K zo!hu`>()I(kPjWeg9nc%ytob-P8#W1&b+yE=WeR>*g?Iz_3PJde4+EByZ7(l!SjFr zs1&BW`Sa-0hv9Rfz5Dm@<6qcP$dmp1`19vCgQZiaO#lWc;D7;kGR6sQ{PKTGkH8p1g%P-aMYiz=zW zlF41Oq>>6$W~QP_E>94l3oEO{`HD1`#0gcLtFWSr3PkMUN-KZ{D(Ikqy0Xg^M(`p_ zER5z9OOLYfk^%_6)I!Upm}aW!rM38if)dZ%V#}yG*;3P}sE&HeGgg!kj52@8#Q!Sm zthC0eOfXtB0Sz2&Pz#~_D1<2WRfj1B+-klZ85L5kz@ zIRR*8j>|o|{A4#cQ<>HRIQQ&x&s};WG&%3wRgTb539WRS-!$EHIPfUYG*nJE%_lfm zXRY*wdpK9Z_+c{}d)7x~r-Rd=X=dC*T-hAgXTFu{p z2Odx0gjZv%HHas!_~ML9OU>huM=tr~-Oe%1<(Ox#x#s4Qki6gH{Nd{Msm_k8(37y$k*?B@tk9ac-j=i2m9p28uhW^f+nBZ4oVneiz~r5}-kZ1Ep}yju zyWge4=A^&jt;p%K%ICe*@Vn9NxzFpk&g!#A$l|}%@W9pZzt!)y%jCY(?7YzFyU*yr z)a|~~>dD>q!qx4_+w;cR@yp)!&ENLg==s#)@!#tB;p_L{>h|XD_@BMtnz751p8+ki z&jCIGlkfrtlMMq6fBjq-NU)&6gBP;2p~SGE!-o$Qv9L6$qQ#3CF&)22)S1}NZw0d7)8 z44QPJ;DQUj!{CFOfT6-Co>XYzg&1D=$si|`Ldu7vS=}6HGB%gg}fhy$th!R-*LMe@li30?R9m=JZOBu;}8#2)xW9%cYoRs_CV(@X|sQ&D286s5#M6)2OJ9T1zum zr0@$ef5*iCD(kGY#)`}@Tu9-JGRgGnYp?J8`l~X|z%a!#%q*kqvdlKCEHlr@poK8P z>|*V;*k*gJFlLBh2PWW#EAF`CqR|H#=%%agy6lp{o;C2sEAPDX&bQ9J_~xtczWlM{ z@4o;CEbxKq6m0Op?;NbKIufSi@WT*CEHQ`Ze^gv?PU!Sl@rmbj?D5AShdg6AB$I3o z00NNQBgsL6<8nCxXhn|8J-YnlHaJt6)&e;9>~qguawD`j?c6nv&`=4jber8Y-Sju^ zD9|)iPB+b`H&|z__10V?n$6c==afy4Ur(yd*=VP&_S&Cf%I&ku?bYM=)Zz5e-tpMv_220Af1byGp2miy z&5Nqih^5VtuGW;Y*|f^%x6SIh&+NC%>AutOz0&T(*YU&F@4?gT#nl9%uG5*f-JQGPmb2HJx7we(-o4cDyV32r&+E9(>c7?S zz}4`-)$hL3?7YzFz|`%&(&~}cGbGyR`P}LG+vxb@?)vKT{ItsBzt!%()a|{}>dW5r z%iiazOivij(=|L?^7@5=n~(Ean(|J;H9 z+=Bn#i~rw@|KXJX;g$dBtN-h`|LwlRw2}X_8~?;m|GP#1zfAwYO#ie!duBzaj%NR@ zGXJwZ!<%9Mo*nx07N2jRpUW2LFx*|B?*If;#`M zQ~$7DlZ*m>lMMq6e=7(aNU)&63SidI*~74*!-o#b070Y2j>U@@Gh)2+V~HC!AVZ2A zDe}#TGkEH#yih=;%a<_oh%nPejZFmuY^n*zvu976azH5glBTEy0S}5QUAlD62P9pl zNF`t(fz+#5v5wh6B+HYpV8e)tv7)o*&!9hV&|xA&i_--PG&s$= zb!!?PifoZWTS@^6wE6m^J%dLIFHwR=IgmiO@#9gngg_C)g>%UaoJ*fR9Yc>KHK=Ic z&b>SLD?U_&fB$(wzP$PK=B)&QLFR`0_weJxcOqnn{rmXy>mMTKp#Osj5hCD#1QuAJ zL}&~W$bt+u=pciG4APMxhg4|cg&1Ba$VrMM;$a^JcqrnCBq}n~BaWnqQ;Lr0)>Dd) z2n90Ddr{7P5dOlDNoIB$J2&*eI4zQVAjrEJDejfCl=f zC8IP(N+y?JBAEo2H0tQ1jb=iMW~FeV$tId)s_CYja#9Lur+CtdC#f~i$*HKOda5U< z#C8iPf1kkrT7V&+d?IH!vEJgFDze1VD*_3`BJ8ll3M-2$%i%)HEVM|b%Pi1FD=oCN z;Bs9qw$!5Sw%m5Btu48P*NQ3RmTT_0<+jqwdVjR*?z`~9OW%I;LXY~$E@;G($p-Ckv8Y7bIn{u6Ad)b_$>6$LS;{1>%v#_m?ex=0 z&&3Qg%PhkTHVaIBtJTZ^*38$1ni*sF-FWA% zW;bcbAYXILF{Sn`_~3mX(|2scB%XKy$s~TO;=Ta`3^Bw213&_jXRf*Al>@U}FQE4# zSuvrPZaV1K{ql=1thes^>#VCD9xt@lZu{-HueZzYy!YH{P4sVUp#*S0RTHd CJ=|{q delta 1188 zcmV;V1Y7(145kc_Mht?V$&<0)ldjmEx#5vd6*h8{zI2tqc$mX@n8JUb$%LfNg`~`h zsM3n4(2%aymb2QVzvaW$@4?gT#nazOivj6YI{O`*A@zDMA)&Jaq|KE$+ zy?EZjeB#G}|KXJ8%ZC5xtN-h`*vFjz?Y`U0rQp-E*12`lwRF(4a?Y`G&9HLKwSvyK zh0?u_)xwp-w2|J=tpBqc|HM$#q)5=YiQ?A1|GP#1z)a4aMgO!t$Cg9DkV1QAMWAVGFHVP=fUF&GM*T*=bpnG##F$jqW( zz)WyBbLNx@X2cXMK(Sm9@F1wsqgcX-h;pRq5dsDhIGsxMh!q@7hG^Z&wQJWKAeaal zD?~wo2xQZ$6;k6v5+HEle^OWgSEpULUp#DB!FPp&1`zrR9=xK12Pi}m6B!Udg5t-J ziFol4Lxttbm@{YQ@IeEM&nyZQXaKsjX%;g=JTbzWb%6@3?doJLBZrhCxN#pykh{0< zB2Fg2XhFOMV+O^OD{qm31Pvt6qf4JYeTj)GF0yOi&Yimw9an6KfBzp(zI^#0JbI{K z&%V9;9xqbJpHIKOefe_o>)+46znoWbydmI#1QuxECveoE;DQV`=%6Zi+#%r|YZNfy zg&0ogNgsQ3xJOMM%9fLdoJgX_iF&vp02?T_=;Dc}MB>PdjzEf8>%(8fl6le?%GO91BD#B2H44atI(?0%Au4d2}h}m|T*ANFZni z!k7eUw&^CCqa-58oOIS{=bfS~GRU5Th}Hm~fCjo}D4GyrsG$YWVd$0M912P!lSCRR z0trZJ>7|iYvI!-eQo>j&orWqZr#x8DE3B`!6l?6U$R=wGF55Kg?6c5DyA3tmRBP?E*k;SkG}(0P?YH2Dn~gNs zlv}Ph1(>Vuy5>Gp&Aac`1TUlTIup&k_i7_RH~9AJ@4dz}Be1|W4s7tj0u#f`!VEX; z@Wad$gUrMef1C9U#TaKiu`tPW?C~`Vbj+y7!zg32$<{Og&B-jcZ1OM5#2oXQGS_T# z%)J1k^Ugf?>@zUD1S7Q2ehzK)(L(Q%%hF62aLm$-GOf!jR96i^0##?NHPyAi;FVWtg_xoVnb*(CNU`?aAHt!qx4$ z%i_q}^Tyfn%ii|Q-}ct!_|4qz*5vl(?)mBQ`^(<+%iiGk65 z_fTknV0e(Au)xUM?y$hnz|i2(;PBMr^3~(*U*((8!Sg`qlsX+5i0I|NQ3v{qFz%_we9==-7b& z`rPo?U~p(a@ZgZ3m~j8|y8rdT|MtxP_tO9R-~amJ|NZmf$YcNRq5tlv|M0N?@Uq*^ zng8&#|MbPSvY`LiM*rGU@XS#E+*|+OX#e7P|Kx)I<&6LBt=P(z|MI}x)3SqpY__qU z@W?>$({TUglmF+M|LC6o=%N4WrT^}Fkce=ytC;Yx5YU(q%C?2hyNR%; zknpGg(2xNAtpo7LaR06Y{i+6tXejW&V8N+-vZ8|eq6(>pNxY+WxuA5mo^-XLd!Uto ztfG&Da8S0LbF`gyU{pZ%m<{@#8u5q=?s^9Cmp$^EMf0az^Q&ZVSU^xfFmPZ{fN)?y zI53caaIm0|kcfc$kTCt2JpG_e^PNrfp;Yv)Z1S*m;-zi$vv{(FT(5&%_=+v~j5PL( zHT#k|`8N$^eJ%2YHPm!6^O#rjqH6S~aOP(k>T@OQhDhvN zJ{>F83KhQshB)jhlLP5QrwF2r4Sxb017l9zyQdC z6sS=jxm-iTEiz*8ToP5lpT7bBlKfDhp|^$}mnE>c^@Y$SN|GA*3lhXY5d}(2u$aCh zcm`&Lj-Qf50C$oEL`<0fK!PMg1{xM7NZ0^M6(v!UCNcQO+yH?ZpTz2W@mo5Bpg%f0!Y37+`Uh#(~PEf%`6;)Uvr<`4MF{c%9a>0cYo_OL# z7*ni4#THxW`KFbH!O1IKnBf&zVv%JQTK&)g2q0#d z(ZwsTL;}ZLb={TMUVZTs?HqB$5y>mFK=KA+iZSL`fypcahaYde0m&@1tl`FHoqZPC zXr(RShaZZ#;l>)Y)Y6C@uf;Z7ZMWsN+Z}d9+z2hY988>X$SGIfbJ0O;MxqKi_~VT&ziV6C+wh8%JTBAaZYHrjpgf%O@-z+y($ zT&s;pB8v3?od_at$IXWsu$bbA6q8P&XBTWZ;g1t+bfM=IpJw5RDHz~_%T1wl9?Bqt z)B(EZp`3~f1}y}j`s%E=?t1FETw~4bwAXICHP>8|i|XQt6VC6z2QPd$y^EtdJM65p z&NR$d) z#N2Zau1zhG3$IiiY`x}dtl2hc+m@A z{1Od#z{4KVP#rYtQ4e%2rZJUxOk|*e4tvxC8mbe9KJk$tba%?&Jn#<3R#GfT21p z;sa*zkq>>EQ#1YKgNyjga) z*$!+tvKe0c8jI-Bi$v0+9q!0RHny=1XL!<+oXmzc+|iD9R5Aduz$7`!Q4Vf!qZ_b< zr7KxU4tKaC76Fh2D||r?bG)(}&j_Y4pCL)O| zps=X0z_`HR*x=B}(D3N+|M>r4U~qtdkgu}AP}a@4?gT z#nld;v9w%eS!+`Q1~z|`%y z%i_u1_QKWe$lLSA+40NX_RZh+&D`(N;PTbu_15I|-s<^~m!RJ1_P@x}M?T@TIZ0 zu;B1;h>%cNP>`6Az{tSx`0(K9;DCsK|Nr~{|Nj5}?Z3O3|N77W`_upY-~asM|NZIz z{pVb&|M=Jc`rrTh z;{Wca|L&>(@UQ>yvfIv?|MI&3^1lD`!Tg?K|LC0m>7xJXrRUnP|MJHF^2w2md;j_7|N83E!H(9&lC!Lt%eaWHrjo0p zkNvF!#jt_@t^@t52EnR(`l1S{he^4kdbXyCww`tNm<{@#8l01b@rVoVdIs^AJ@T7H z@}5ldr(E-^WQuN4{hUSqokskgOa7rw{-RLxqEz&*Z1J#i+@x@_g|Z=`%$xQ%M@ekk>f zJo%A6_mV^TreyY_WcaCU`K@vAtaj1-b8ZX)b;C+m$=?UP*bn`4-9SmIj@-&YOeUlQqnL*{%!>4i(chG+2b@X*lEz`($; zu&|(@piodyEC2ui02cs4000R8051p}NU)&63p9o-S;(-VLx(L=06{{rqQ#3BYn-@o zq@%|p7D9^r=n;sCAS63l0KgIefs{vrocuwv=8u&uArP=xQ%8vqK7t0#Aq6J{ol+_Y z4T|HZjHge995AYL00yW}d64+v!o`k${Q`&;o1iR{D`KB?6+r?73l<7k253OHF5N3t zsw8*4^i5oCrOh^#Hz`yRzo&PfsAxVYwHcEWxz`uWo?f@J` zfPekv7s3n(COAV8L=fO00SYE)g9$izVBv)rW|-jzDD)u0haiS1qKGS`pu&kLrl{hI zDkyQsi!jD0~KvdSEE%n=s=bJV@j0r0TEPw<8$YiNu zrr8Lbd6onqfOG;&Ac6#PTC|t3R_$wn1fs1Vg9u`qZtM=gTM~i@!U-&c5Hd({$0fI1 zbI%nJT@r%~GA|*85R%-{Gbg{`Rrj(L)DSnLNwj^-F?e-{slw!9j z8MGk4-hB7}?f2h$?_x|bgcol3;l&tZ%r1K$lg>EfSR=VL#8h7S%;6V%sJNy0tup+N!Ef*$K?S8m=lk9pK$ZzseTa+JdyhW)D^^?0EGXi<-YamPF0 z>DPFW*0By+?2Q)d$cM$=1AzDtKx0Xe2RqndL;=L29qz~mGPZ~^og`z6$jF8}+!2et z#ljurC`U4uu?(C&h>gooMmfkqjxq{>6=~GQHkiSTX7HjHfaFCp__z&il%pK15I`$b xAq#DA!x_(bhA({a3t;@>7ruz3Gq@oOS*W5F88}5MMoG$2nzEFq$Ur~<06T}dJ2U_Q diff --git a/modules/editor/skins/msword2007/images/editor_btn_redo.gif b/modules/editor/skins/msword2007/images/editor_btn_redo.gif deleted file mode 100644 index 84b6644ca228f8901162a5a32e1525b2873c72ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2031 zcmVy3FUs*6q^Z^xo(6S%9^EoWzBs z%#^d-p1Iwcv(?1a?Z?>e$k^`H;`H0+_uJ<6~w%fPP>$Aw= zz0vBz)$F>=;>6bM$Jp)4+V0NY@yy)s*5&xsGtIA`qks|*W~lx z>-f>v-r48%!_LvGv9im{x&QzB|Ns8&>(&4I&;R`6|NZO#```ck<^TNW_43~T{q6t$ z_vzoC|M}JR@YMhM-uLw4|MkKD_RQ(wy8rjm|M}Vf`r`ln^Z)Lt+s>K)@U#E&y8raW z|Jg_X+EM@8TlUpn|J`K&-);Zlb^qdg|Ldgx?yvvxzxnRQ>fyq+v7YhIV*lG~|KWr3 z)_?!vivQz{|L2_A%9Q`^wddNf|MJJJrpNxr3cww`pXqL22N4f>uMxTK2lhzss|2Jx3Y z@|#8Tt7Q9w75s}K{EsU9lQR97JpGT=jPm`GzF}wG0cP8(BFYb*@ z=ZQ-4np*9fV)LSE^{8;>W)|sgAM1lc>y1?IlUd(a4dY%9=6piwg-We@UD2$YqKAE~ zfpm~?Z_&BAEC2ui02cs4000R80Hp{VNU)$mAXj!MT*$DY!zWFYNSsKqqD3t~jA-1* zv7<*YOt^>?sl&w$7A|y*Tsd+KlOiyS(6BKhMG6%hKE&J!vx^TcK(){m@qz@54LP+8 znGh6c7#~)mTCwqf0*@FkLSWdyLI#8@QmuIDai#1P6(T4=x#D941q>!kOfXv(NslUc ztDrrR7YK?D7#={#i}%P9Du}7fxNsmblm>x8KuC=E%aR++bfD!?M57kjr%T5hu$&}l-WlSJ}ySMKtT$V%`PMib;87zn^SH7jk@+deKKv?m7 zd2=DyvtyqjLA!VCSzgco9#1}X`10swXJIm=z5Dm@<6~h$q`v+8`13<)5~RQX{{RLE z#1~QkV&H)YCa9nknapv?p@6r}&Xa9(B+(!wd~@ zAO;^;?zqPuPx^66Dt_QG2oN(^P}EUY?vcg>PY&XyAE~4ghaiFgQ56q7WVIC;K0xq@ zBaYA+M=Gy;(nugSSdf7pj+EgRTyoJF$fTdV@`@*a{E=u4nrI@384ds@m?n)hlBp-J zz|sdJj4+|W0gZJ33JGKnNMMKlE+UDX0D%CRP+~8-pll1S zw}Ti0uOgK&06`>{Tw;kOlvJC@wuTI{>mdIwVs9B`h+?t9_Aat8A`YuENFs_ze90xE zjAHUA79UKB#)%A~iYj=7ObN*)V?xT!n4l~Q!ip$@hbpuPBC;r$6io`QjO2{6C5tQ~ z2raa1q6Uv`kQj#_XP|M0A90Y_Mv`=FLQ4>_#L~&xrlcLo+H0q6%Gqbf5`+{1)NS|O zc;`)b0Lt|L?f2h+|84g<=agf3GKeRxcru0)eoo!yM6S)`lW$}BHk4ByxjA)f0}njd zZ1Yb72<)>BGN`AH&FAoFQ};3NykpJ^9>^er2Py1hj4{~sj!o?E98-5L?vT@h2NjG! zLJ1pmu+KH-OmGc3XhV;JWcfT$oqjB%_ZANe3g-Ee`Ad=TJO)Tl-^ zvOz1!jKhHt#6{h1fsc6zfHT&J1~7^>nh;Dw9P^0bEk;;EcCCqyi%ME@lFa}IBGVy@y2&CP>X4)}M(K-EmU5KN2nRUSp^i=lpcU!} zM>w4EjAuY27{bV9FrZP(RLZgy0dNH?W+9GgL_>qsIG{3-NsVdDViv4$MG#Q2ifUT( Nn%KN1DuNIY06UYMG==~G diff --git a/modules/editor/skins/msword2007/images/editor_btn_s.gif b/modules/editor/skins/msword2007/images/editor_btn_s.gif index 23dad25526d8f2137666ea717a7861b23c622e27..18bc6358d3bfda61298457d1829d9906dd860016 100644 GIT binary patch delta 1006 zcmVhktWQM2X9nFk{M8LWGCS z4+Nr+Ai!gZ%@8~a5a)y>lh>qXD zg9{(7qezb9$dfByo}&ba=g^}|pAO=LkL%d8Yv1nUh=}jt!;AkPF9HdQ^XPxmt6z_T zh5PsL%pm5^iCTxH)1{<7o;-Vd#biu|KIJyYRCzu2o zq!(hCfk`GoBI!kvLVhAiA5ed4#g$iJiA9!KXhA8-Bz{1-h$3aku|*w*{J}>Yi7*n# zAYs7KhaZzr0?3?m?g5A^fQT~Z8F}tWCnc32A}At)5Q4}dh#1<&D2SYaNFjm@T8Sl( zRN9Cml^*g4DTlb>#v^VVa!4taK4Qrwkff^Ws;stp$tsb=|0?UOwAO#RiYBL+qU)}_ z_R8xiny``zD#R9R?6JnC!b&TuH0$iM&_>&eCze!e?X}ou>j@d$cI)l8;Bwo-xa5{= z?z!XAqVBrvw(G9C>%=SXy!6%^FFW|=tM9)2;;YWT00%7a!2hOW@WBWttgyl7H0TZEX{w$(s0v@Ipy>sO*b2RBMmvdSYtBB&$R3^I^#I=3^Xm%j84ri zKjX{JzDU{CS7D7+)>#Pf49wBMFtf}w)o>AwGQs>J&NkW*bIdj1AU(|1T(>g}Hp2+B zbvR*<&Gj(Iq@8v)#UO(XGHp|13^KPMlT0>hBeToiyWm@*%idbf?2?N!x7@PJEzUU8 z4Bxx(;`rl`M=rVJwp4EU<(Ow)`7E4w?)m4Sa~{j+q?c~`>7&b{`s%E=?z-x*#4h{n cwAUW{E4b&b`|iBsUd!*m2QU2azXt>WJEQRZAOHXW delta 1005 zcmVr^sBeW)Z+D#e;6CP(e1g<>%P_SqP5JSw9CKM@1C&6EiyR1 z)9jI>Fd^3D_Sok4-0Au1^8CKk?Y+|KIX_0r-toT;M;lA9$6 zbXh?FiItltkQ5-0BO@t^_THpu)Aykw`Eg*Gi1|~qVLWmLJfEgKE0_X$qKmd#c z5fEgpu*8R39683MD8q#ZhaUrfFc{ddL&5~N6dZ&YJa|h8G9gF|E|7RJ;R`K>NFLIF z#1Jw=ERO&&q`(j&4JKD;;h{8$52eX?2tuYn0S^VpkYP~TgAEoUa_ipBySD`vMuH0; zPP}*xCq6K&|%<#2qvhY9d+#C;DZoGC}ACd{9)mR7-py; zAchp;;fElGD54>)5HiS#D5j`liiEVn3Mw$3f(ILK;DJgiFbaZ78hEUsBaE!9LduXs zs^Nwlq?9tGl4>kTgubb-2c+athCmDYU{1Hm@xa4BXv(QE>?X+o3?n?x!w^R- z@x%|WWAVipXRNV*#ol!64LZrl6HhYUq|>oF-oTTLI4FC(&C4*;^Nu##aPzXw^xO>d zHp=v@43%DiB^Fs`p@o3Y%p}bWHrIR;4jSE9)66pNoMR3&(~QH8($945bw1CK^NcfH zw=;IxUOz+4+H02+4K?IY^ENorP%{iQ)s(|FHOKT_eGD;N#`LYtF~w*z%rM6cqm4G% z_)8@UXD| zu(0sJ!2jUj@Gv-_KuEAqSin$NuwZD=Ff?dzc;H}Yz<`MGaCp!_NRXhY@UXc5Kv2N2 zxbQGQpip4Isi1ZF zuw;q3bePA5r`4LX)xXs6xXk9m*6+d7?8Vpc%G~wP;rG$t^x*6I-|G3}?fc~H_nf)h zxzFpq)9t*_>A=+O$=&wC)$PdJ^Tyfn%ii|Q-}cSi?&a?J>GAu&)$YsQ^vmA!#@Ox3 z-0@TO!K8!|FK^4 zt7QF`JpGwH{hdbsqfP#@YxJ&c@vw6Avv~8ecig0K_>466i#7a|Ir@<}`Nl0)#UcIl{f+n;ahY8C8o9PD)_@qR1rd@u5ZHSUc} z@t9fkpJel*YW1ja=VJ}!VG-qJ80l;t=x!qFf1_X!)6sAxAhw`Jxl`9n-*rxGDhle&gTs&|w;QV>=OsrU0fZ;-pF>J7L z!wvqp;KBz2=%*h^Odx>-3?_&$!Gr{)kOBn*3?Kjr4mvml5KLqt;)o=cSmK9EB%$Jp zEVkHU5kU~q#Edl7Xrqlvq!GjuJof10k3bR;$dE)9Y2=ZCK%xg6Og8D{lT7|09 zA;%qa%t6PNTjGHSmvm&w$C!k)l1CkN_#uZKcHH6S9B$shrW}4mVy7RftofS97|Cbkgb$Rm68>|h^h!l5R za?3SG0V1FTT#CJjBvM^%*lEX|ci<%w%EOn~n}{Omt=Har@y$1YBBFHsh`ov|!k>Qt z3P_-V2riP!%BR@72qUdTIN<~pUYOyAjEti5DYgj02qTS5LJ1|6SW?Q-mQ*syB#kse z%F~+M(g)B&TVnMk%{p>P(v?us$kC-loyi_!*5M`|g}@O99EITFW*vMany3)C;Ihiy zsN^k)B!le#oi{3X2aXF7x)g5s;fN<*crXBTsu@7VXLKns0$3C7ltjJ8JG6UR4F%C!!e$>NTp&3nS zPP3a7)Z>H1=!GsSSdVpC$6dPNjR!&K3tbE&AMnr@29l#3=0LzX@X&`ohS9;mj@4}9c9A9Kh<9>3s)E`A{obBydi0UA(&4kUnc z%wrzE$b~L?L638ELuM4R5Qa2F0(6|?9KBFuFV2Aubx`9P*RX~%l(CFKS_6>PP)9n_ z(Fb*N(&v8cr>eDRHNU?Ur-%tkX-*^E?TBOJc) X#VcST1Xj4>mblENE_KO@fB*nH@NPdr diff --git a/modules/editor/skins/msword2007/images/editor_btn_tag.gif b/modules/editor/skins/msword2007/images/editor_btn_tag.gif deleted file mode 100644 index e29fb2cdb9cdb1cb2ed53628558a26ccf1ab6730..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1600 zcmdth|3A}t0KoCZ$Q4?pFOI9ucec)DI-RR~2o<%5bI})_x;Q5(>h2+R=i6q!e=Wp( z$yB~9-@gu_XlP%owwNy&GyBMF#)j=<$on4s8~6GTo;=sMrnrmMtezl2u*#I~Tct{bVHq1nA5 zS+p<`{a!vJg8c5^Vs`wC(KyP;{k)#!>TzNjH@1`$QP3M%NK1afOQHX*+LyC*!q{~oCiU&_6g`C3DftGpG3V~ETF$W8ztAe=|XhA(a56{ZiBunee2?c$8fh$xDiI&D@l{}GxKeqzZ z1Dh~!Q$4-8HUrkhn@Y~-CFUk9SfB6MSfqVcegqshz;Op$4={KU@UDZAVDK>zw0g}cwaU)pl-B@I9C^(;&d4Nva>P0pcnkZ3D7bpvegI zdV-Eqpc@C8PecTss>lcgHFlu*8&GBi(zQT_HptQic?O`+6jYuDwO*j%8fXmKXb2g| z4V*0x!D6w9|4W!JkS{MFbO3^O8{t%6(nH)z3qVa(Jf$U~4qp7n1j;N<-H#0(XnV`h zvJY`iF?RpE)X2hM9`a!{ma%f9+;9|Hc{#iA*d3#?Rl29@JU%y`_26EL3`!H0{!b@)&; z8WC$Pcpa_&dVkg*3Awbyd=rm>TMfAmE_;iPoNTxAVs+YFvbY;}a*IKUOX`8c1$~JJ z?Aj>T*e{Pt_nbA!8FTKS%EqaEX>x^0{Gy?_lhD)E0WVHAxB}sB=M?p_c(7s?tL=`5rd|$9{?F5kkJr0c<|7TwyqxtJ=N{#UHM(eIVWuGy+zIPHbACCSh1bje z{+YSgmGC+9yel65F8Vq4{(+{rCocjEZk*53)PH=;q@oDNcDJ+*cRc@<{DMS2U&p>LZ77H~ETwLn$7CG0Pk9W|)!F z>@Ye*C>F~WtF=5}_uiML*9c*@dpW{I*!PZthct}qZnihq?O=MC{`R)%l|kGIS=i9| zjz)xLT|kWzjk`Ia9QMI-T+jh|A*!(;7)7wT-6~U!-#s&>X%jXQ0#7_xN4eTW!saqq pfZyuZYaO>QbXAyS#3fj#IV`M-9^UWXiq5$ds-7V&??fSf`VZ9hD`)@! diff --git a/modules/editor/skins/msword2007/images/editor_btn_u.gif b/modules/editor/skins/msword2007/images/editor_btn_u.gif index 9f15891c95d97933b6535eed3ac684125344b158..cd5e11f67b5e908b04a27218cb59705e23df9056 100644 GIT binary patch delta 942 zcmV;f15y0G4BZT{9sz&*?7UM>KK$>){q@?vn>C1TCjZb#zneC!j4@S382`^n|IkVQ z&`Q6YI{(p5RYe;A(N9%I9KW7G|I=1?VkrO9S9fD9zn@3{)nKZQKvhQ||J7mLx?8`Y zPj_T7|JQ2&*K3G$KL6TwRWAX*X#@X_1;1(ptX~9(O9TIn29t~e92b@p z|Cbb1GYh|T8vmLj|C=Mfe>DH9Mw7n+6$UdR5dW}Vli&g^k^>Er0}YY`4Uz*5k^>8~ z4FeDXe|hmzpr~KZzP)=XQK-nDPrttXC|0WI-_O6le=A;eA>e=n7HFUslx%^;f(vTF z#e-L5fdwR7Fu33rluYtSBOG?vp(Bhm0-}eFJTi$SiXfumiYp$H2qG@Bh=?MR0AfZM zIOdq+7i5INqmE&i0Z1Tcm|^6RM~(r88DfY+e})KU7v9Zj@{Bw5Msw1bk<3SC2`a#M;&$2X$K*O?4ie?gXWRP9fazE z$0dpCv42ivCX0Z=$tJ9}>gubma{mHK ze<+@GV(YEA=8CH)p+r*1ufPT??68qMVeGNUCabKm8#L?ev(QG{EGpDiYwfkzQv1!e z+;;2jx7&gv?zrTZYp%H7q^s__?6#Y3H}J+Q@4WQF%gw#qY@_eK{Pw#IzSsmTFgDjz zW3V>XV3SQX0}Cw8!w^R-O*GU@T(QK`e?X%#G|z0ju`|s;1G2`?bgXeND5tD)FTCu+ zvdb&?BFxOf1Vb~;zW^hQFVhSoLNGSZY|PL^7i|nNLl<+5(L*!iG&9RQ?X)t=IE_p) zPA?O+)3kK$b=R}J0*lwO#PYS*x}>d3E@|6h%Pnf_QVT9==fZZ{tmLit-g~b?M4}4c zd7mQqDXyH-%HfD7ez+@z3tr0OkVh{0C1TCjZb#zneC!j4@S382`{oznnV% z(N0xG8dXLdzn(z<(^hw4D0gElzn@3{)nKZQKvhQ|-MU-9p-*>YG5^$up*od4~< z+svil)3Xr`1lGBA)3tQavvSU{a?P-E&9#Egw}sNZj@81I-p{Q6vm5`!P}HPI(7B1? z*1i9`MgPD|&Yea7v^~d`L%@(iduBzaj%Jg6T8La454wv&w1x^pu7pLZ zf=8)`R+Ab6AAhANtB6>shgY(WT&{~+w~}C0F9E-41OJT$ziI@mUj&Ft1OJW&RWAY} z69K<%2>+4{RWJm)0Sh+HiHu2a8)KEau6xRYt3f?YEr5dX1W|FUTOv6HC+C9@3!5CMPrDXgSGSZqhrf`}iermE_ytXlHKtFXrZD(io&Pjs=tt+?i@>#n!X z;_I)#1}p3=wa{bivB)N?EIsek?L6(s+iqgh;vTB0|U%VI0z@Ka5&(6!?42( zHxtdo6jvM#G|zuroUz5qRO9i-AXhUDHPuLCjx{2Hyi7JMx9oB@*RYI@HZN!6i#Isu ztaCTr;JghtI^*06F+>+l^f12wQ?xL_7)>-U$wV!6GR7El%+$poGj-Iv;NtbyV1s>& zEn(xL3oK}-oy*#6x4m}Su*lNN+;rD%_uZ|;;>zB9_ai0k_usC(lFHzO7jF3Bsi=a= X;*2-$_~VPyBKhQ$S8loF0RaFzFEH@M diff --git a/modules/editor/skins/msword2007/images/editor_btn_ul.gif b/modules/editor/skins/msword2007/images/editor_btn_ul.gif index eeb7f2035817d1820c1c812bb5fccc072a2b81f2..5e136ffc479f07f99a82b746a0f1c815c81af323 100644 GIT binary patch delta 1324 zcmV+{1=ITD4B8BkH-DSA;Gn$Zn61p3ug>A>_v-QccbCC?n#6pY!+)N~f1bvIp~;4& z&4r`Ni>lIyrOlA8)|9f@k*(5@tkI9F(3Y~-ow(ez%ICMu>blSDx6J9j)9}60?!(vd z!`AP?)9l69@XFlv(Bb#d;Pl|@`rqpLi6O5_T=pMb$^z>d6~j^n8ACS#D1Q~ zf}+ZQpT>fs$%dxRkFM2=s?UwA(Tu6il(X58uG5aI(3rQ~ld#p3vDJ~T(vPgrnYZ1Q zve%NY)1ABFmb2HGwb`7x-I%r5qQK;wx!jw#+NHwgpS#|qzu~RO>9fk`z0~l#(e1g< z>$uM9zt!-w$XMaP)$qU7@4nOQywK^u)a|~~>b=qF$=&wC)$PdJ^Tyfn%ii|Q-}cSi z?%L@2+vxb;>iFU7_u%UG=I;22sLh|f;Izu)zt!%()a|{}>dW5r%ii0X7N!_1gc?NdM1ClXU@OWB=il|KXLLjbs1ltN-h`|Lwm2vm5`!Q2)C{|G-S0 zka_>KJ$q(Fr;cX-tup_!J-L}^|DGNHq$vNTD7leb|BVIzjRyaY2LF-_|CSX0mlXe+ zBmbKt|Efm+u2Y?QQ~$7Dlb!-ylMMq6f8jV7NU)&6gAS00QN*yJ!-o(56j_9*qQ#3C zG4csg2av~)AVY>M!-3GDlMM(A%C$T!G&cA3?NwE%(?RkA2r&D zW*`87=(svXi}tc%4x85z01S9dyS8l=cV@iU&AYd6-zkO!dPBUp@#DwGD3Jl9x%21H zp|7BlhKBX)*t2Jkk;sbo@8H9WfB&}<=Yje2=+moz040y4_weJ(m%pV+q)3nQ>)+2` ze4I|Ex9DIf5R%DbkYeX z1z_UjlvGan$tp+WzzQgzc;eP4pLocQC!c`A3K2Q9B1$Ns$P$1sY{n^PoT9WMLJqEw zGRmHO_UY%Iq`1Pw4zHL}%AtrRs_3Dnyb=Niv7mCwDU>ik$)uQOiYY3wfbhdGs-%(% zX#j{Srl_h6vqT5A^uh}-f0Y3Lpv#x8D>+3JXj9^4D!2qM| zvdlKCY%s-;5Ctx{z+&yS*k*ezE?QiHh9lsHEAF`Cav?_+=%%agy6k3A9y9R9EAPDX zvS-e{_~xtczV)Hw@4o;CEHHrN6m0Op2q&!II1G=oP66vQEb+t)e_t5R#o@Shv6$ds zJfb%sdy`H8>V$0a$so(v&B`pd?DES#awGH1G}kQiHZv<(&Cb=7Q$RU92QBo@SzcrG zHEtO#rZq>SiOtj4h!em$P*-jB(|2m4_10W>t#vkA4;szbWS4FB*^f@6_B7NmK+W24 zuPx2mo;qWx#_cj5qH11=;%A4C4%tH-Cbk$(_03n61p3ug>A>_v-Qca+AJvmB4tI!+4m&f1k;RsMLR+ z$AqNLf1bvLq|Aw^(uSqYi>lL#sL+U|&5*9wkgnF2v)Y-p+N8hb!`AP?)9l69@XFlv z(Bb#X+V0@%`rqpLi6gH{Nd{MdD>q!qx4_ z+w;cR@yp)!&ENLg==s#)@!#tB;p_L{>h|XD_{-k(%ii;ojR6~zs{u9%>D{&c_1gc? zNR#RTV}IJcc;3Q%;>Usi;gtX3mFCNaosDDv=&S$hxY);>|Lwlp%%$Mdv(~wF)3tQa zvvSU{a?P-E&9#Egw}sNZj@81I-p{Q6vm5`!P}HPI(7B1?*1i9`MgPD|&YeY_ka_>K zJ;#q?FW<{rtW|Mtd|E)5*i$b)9L#~8Hsz-uHsfSj%nP~r>9si{$xshC}h*+tI zSF(;=u8Uf?l3@Rh1^rk03pG2}80$ zfd(W~s$3anLzgTt3oHl#)11wlHeu?-@CA!c1pyBD97?n(mKtE7C|%05sZ$FRm`I&U zwW`$$G?ZvXPym6}uVBL}p}+-+S(yRM;>2mTErly7;(sOxU?8sDyLeMjn9-!K-@kwZ zSEz!bu;Igq6JL;^qA>&p5E@IKOj$*a7*8@Y5C9PY+DV5O zD`Lx@O}lo8Em3mo-p#vr4;L(g3m;CrIFKYTk}F@%ym^Zt(4$MAPCbK+6WFtB-_HF6 zkt1uui+}$gPo6w2A!^j1SvBw9>DXbv8E|uy1HXPCiA8^Jg=bU`>(Z?aF;DE>qmU{ZNFa)wvI8iC2qMU40BCBZAcG77iYX#EVo4>HxB&nzsJ7}V zs(+SP|Kdm{JcNSDCAj9Q>#mnzf=MWv^e{>%oD^&9vB+}LNhhOh@+QGS)*(d^+ZYn`a%Ra^ww+dz4&S)ggE^6>+in+ zXJdjl1Q%@Z!3bkBLN^R|Q%(WpG%WGN41ZSx!ZsLhgBHeCX1onGA6O%@HRA+8&d4aI zEOIkCOyly)Fvl$OG8#x@^UXNttTQt>IODT3-xTo8&qNpPb22tOqx3UqDQ)G_&nRO9 zG*m;wO#tCkt@YMa6JtX(V23UC*klibgE45Qt@he%3&X)Na36yV1IWZ}_uX&@vroe> zeE&$oDc@H1{R=Q64;fyzK_%1xuBKhQ$S8lm3J=mi8=A3u#`7J-hBKqj0 cmu|W&+QOpx>a4f!`nbKsF8l1X*B%f6JELyL+yDRo diff --git a/modules/editor/skins/msword2007/images/editor_btn_undo.gif b/modules/editor/skins/msword2007/images/editor_btn_undo.gif deleted file mode 100644 index a300862d7aa546d6ac0e4dc16009276aa684d947..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1905 zcmV-%2afnhNk%w1VHW^G0QUd@#n$b6W<{uzlx<>rjg`1(bDW;3&yAYIfSTbzV6akm z&|Zk*S$fBCnDB_9*^Hvnt+&oVaL`bM@IYz6Fi?e$k^`H;`H0+_u%XL-|G41?)g-IwT-LMl(X5IxZbnK;lkDIy3FFl*6hdF?aJEj z&ff9N-0#ug^4R6|;p_M0?fB{O`@PZV$=T`DkdhSb54@TO!KE)^Q&b2gcALT8U2SD{fi;|kt+U{Gw6sj{+T`fotv zph^CsPyVD({ijy*qE!8>Uc7)u&Wum~u4d?>Vg9mh^sa3EwRH5fdEBIMvV~msejWIV zE&7#0^pZjQnMVAZNAZ_T@vnBpm22*95At;p^?4TcfF$*UDD;Rl`HngBjY0XPWcjIV z_p5R1sdd_(Zrz}A?sFUNcP8V!w< zd_tyvX`zLEEC2ui02cs4000R80HY*fLa?C0g9wu-!NIVh!-o)&XemOmqQ#3CcTf?+ zv7^V2AdgU)Lb4>u9xGPJ=yAhjNgY*!$ebBO1%eD25TxJ$g{Dj$MWhIQQ9}v}6D%f> zAR!{f1EEl*BV zp6F#!;erbd9`rt$U?GKI!8x=zS*+lLga$2UEOs)X>Ey{dirCm3A;JU@ASi66F`)v7 z&8ThUpaP(^YXD1J^9Zrvwd>VQa_ipRgn@(@ymPN!LcDnK85|@iFm8M}^WrNcMA-41 zxDFydvTN7AB1Mhu;IG^N9#7u&5hCT&zuqzAhx_;NIXyAbeCRj%yi-6(agAhg-At;}Gk;a8-sG*@49CqkohZKHs#)xOcF$RViYN%q0 zX_Vqg8D_-z#*8C!(Lo0@V6jFVJoe~f8F&Pl$B=ofa8ph@u`%P4ub@(f8*be30vdSe zV1fxsG36AILw#T-QBJ2qg=ppQ}l(6bZtb73b$03z0 z0*3?)RATM5m5k!b9nH?_#~*+Mg2*e7i@4Q`?>)xzyS}e$-@vwtVt)Wv=Iov0uPdiB8+tG@yCoT(h4YK zkRjt4CzkOA7-6*BGRt9r@dyv8)EvsqdgKhp&OGE%eYt7cDe4NGGlI(o544 zKsfG19rZO-S8esxwgk}5*6o1fwb#~!E%w-9hZ6ue^su8gJJq!P3IrZNz=<_&*IkX- z)X<~%I()DHV*mmuY=D9T99T2W;fH6<3qFj$kdHb9n7}}mBRFtCG?-(a^)B+*7Cv1BA28@e|~J z{PIrc(hu;HLiSEF)K4%10n}&jG%o!-FDhsh6l2Uhr3qln`R8xn{qyOh!_7Cv#19Q^ z@z-CB)3@lO&p!2tBhEPE=!F0aAOU{}@PNIjMF8^0zy6Jb9OU@LFt9-_Us&)L82p6- zWwDQa*aIFQ%tkhV0S)Oq0~jbwAuyg109n}MgYbw)Im%&W ricyTvSj8z~5sdbMu^Zk{h8&f#ygAAd8axn%DfY<6KKk*G0RaFz4ca3S From 007b55d3681b761122e926f32372fbac3ce04b7d Mon Sep 17 00:00:00 2001 From: k10206 Date: Sat, 1 Dec 2007 00:00:33 +0000 Subject: [PATCH 100/265] =?UTF-8?q?=EB=B0=A9=EB=AA=85=EB=A1=9D.=20(?= =?UTF-8?q?=EA=B8=B0=EB=B3=B8)=20=ED=91=9C=EC=8B=9C=20=EC=A1=B0=EA=B1=B4?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3124 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/guestbook/tpl/header.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/guestbook/tpl/header.html b/modules/guestbook/tpl/header.html index 14ef54ea9..817b3327c 100644 --- a/modules/guestbook/tpl/header.html +++ b/modules/guestbook/tpl/header.html @@ -7,7 +7,7 @@
    -

    {$module_info->mid} ({$lang->is_default}) | View

    +

    {$module_info->mid} ({$lang->is_default}) | View

      From 5ebbd79d364c4fed119c9656dec94d62c946b06f Mon Sep 17 00:00:00 2001 From: k10206 Date: Sat, 1 Dec 2007 00:08:05 +0000 Subject: [PATCH 101/265] =?UTF-8?q?=EB=B0=A9=EB=AA=85=EB=A1=9D=20=EB=8C=93?= =?UTF-8?q?=EA=B8=80=20=EC=82=AD=EC=A0=9C=20=ED=8E=98=EC=9D=B4=EC=A7=80?= =?UTF-8?q?=EC=97=90=20=EB=B3=80=EC=88=98=EA=B0=80=20=EC=9E=98=EB=AA=BB=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=EB=90=98=EC=97=88=EC=9D=8C.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3125 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/guestbook/skins/default/delete_comment_form.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/guestbook/skins/default/delete_comment_form.html b/modules/guestbook/skins/default/delete_comment_form.html index e79019194..a06174f59 100644 --- a/modules/guestbook/skins/default/delete_comment_form.html +++ b/modules/guestbook/skins/default/delete_comment_form.html @@ -10,8 +10,8 @@ - - + +
      From 71554ee2d8730832d5b6ae796564253197627ff2 Mon Sep 17 00:00:00 2001 From: bnu Date: Sat, 1 Dec 2007 12:30:01 +0000 Subject: [PATCH 102/265] =?UTF-8?q?*=5Fdocuments=20=ED=85=8C=EC=9D=B4?= =?UTF-8?q?=EB=B8=94=EC=9D=98=20extra=5Fvars=ED=95=84=EB=93=9C=EB=A5=BC=20?= =?UTF-8?q?=ED=99=9C=EC=9A=A9=ED=95=98=EA=B8=B0=20=EC=9C=84=ED=95=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20-=20extra=5Fvars=ED=95=84=EB=93=9C=20?= =?UTF-8?q?=EA=B0=92=20=EC=84=A4=EC=A0=95=20=EB=B0=98=EC=98=81=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20(=EA=B8=80=20=EC=B6=94=EA=B0=80/=EC=88=98?= =?UTF-8?q?=EC=A0=95=EC=8B=9C)=20-=20queries/insertDocument.xml,=20queries?= =?UTF-8?q?/updateDocument.xml=20=EC=97=90=EC=84=9C=20extra=5Fvars?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80.=20-=20documentItem::ge?= =?UTF-8?q?tExtraVarsValue()=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3126 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/document/document.controller.php | 24 +++++++++++++-------- modules/document/document.item.php | 6 ++++++ modules/document/queries/insertDocument.xml | 1 + modules/document/queries/updateDocument.xml | 1 + 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/modules/document/document.controller.php b/modules/document/document.controller.php index cc945e0fd..9a4c10c85 100644 --- a/modules/document/document.controller.php +++ b/modules/document/document.controller.php @@ -66,7 +66,7 @@ } /** - * @brief 문서의 권한 부여 + * @brief 문서의 권한 부여 * 세션값으로 현 접속상태에서만 사용 가능 **/ function addGrant($document_srl) { @@ -91,7 +91,10 @@ if($obj->lock_comment!='Y') $obj->lock_comment = 'N'; if($obj->allow_trackback!='Y') $obj->allow_trackback = 'N'; if($obj->homepage && !eregi('^http:\/\/',$obj->homepage)) $obj->homepage = 'http://'.$obj->homepage; - if($obj->notify_message != "Y") $obj->notify_message = "N"; + if($obj->notify_message != 'Y') $obj->notify_message = 'N'; + + // $extra_vars를 serialize + $obj->extra_vars = serialize($obj->extra_vars); // 자동저장용 필드 제거 unset($obj->_saved_doc_srl); @@ -180,7 +183,10 @@ if($obj->lock_comment!='Y') $obj->lock_comment = 'N'; if($obj->allow_trackback!='Y') $obj->allow_trackback = 'N'; if($obj->homepage && !eregi('^http:\/\/',$obj->homepage)) $obj->homepage = 'http://'.$obj->homepage; - if($obj->notify_message != "Y") $obj->notify_message = "N"; + if($obj->notify_message != 'Y') $obj->notify_message = 'N'; + + // $extra_vars를 serialize + $obj->extra_vars = serialize($obj->extra_vars); // 자동저장용 필드 제거 unset($obj->_saved_doc_srl); @@ -520,7 +526,7 @@ return $output; } - /** + /** * @brief 카테고리에 문서의 숫자를 변경 **/ function updateCategoryCount($module_srl, $category_srl, $document_count = 0) { @@ -618,7 +624,7 @@ return new Object(); } - /** + /** * @brief 카테고리를 아래로 이동 **/ function moveCategoryDown($category_srl) { @@ -698,7 +704,7 @@ // 캐시 파일의 이름을 지정 $xml_file = sprintf("./files/cache/document_category/%s.xml.php", $module_srl); - // DB에서 module_srl 에 해당하는 카테고리 목록을 listorder순으로 구해옴 + // DB에서 module_srl 에 해당하는 카테고리 목록을 listorder순으로 구해옴 $oDocumentModel = &getModel('document'); $list = $oDocumentModel->getCategoryList($module_srl); @@ -752,12 +758,12 @@ // 자식 노드의 데이터 가져옴 if($category_srl && $tree[$category_srl]) $child_buff = $this->getXmlTree($tree[$category_srl], $tree); - // 변수 정리 + // 변수 정리 $title = str_replace(array('&','"','<','>'),array('&','"','<','>'),$node->title); $expand = $node->expand; $group_srls = $node->group_srls; - // node->group_srls값이 있으면 + // node->group_srls값이 있으면 if($group_srls) $group_check_code = sprintf('($_SESSION["is_admin"]==true||(is_array($_SESSION["group_srls"])&&count(array_intersect($_SESSION["group_srls"], array(%s)))))',$group_srls); else $group_check_code = "true"; @@ -770,7 +776,7 @@ $expand, $node->document_count ); - + if($child_buff) $buff .= sprintf('%s', $attribute, $child_buff); else $buff .= sprintf('', $attribute); } diff --git a/modules/document/document.item.php b/modules/document/document.item.php index e643d6ec8..afc16caed 100644 --- a/modules/document/document.item.php +++ b/modules/document/document.item.php @@ -300,6 +300,12 @@ return $val; } + function getExtraVarsValue($key) { + $extra_vals = unserialize($this->get('extra_vars')); + $val = $extra_vals->$key; + return $val; + } + function getCommentCount() { if(!$this->isGranted() && $this->isSecret()) return 0; return $this->get('comment_count'); diff --git a/modules/document/queries/insertDocument.xml b/modules/document/queries/insertDocument.xml index d1e5d33e3..18ffff75c 100644 --- a/modules/document/queries/insertDocument.xml +++ b/modules/document/queries/insertDocument.xml @@ -25,6 +25,7 @@ + diff --git a/modules/document/queries/updateDocument.xml b/modules/document/queries/updateDocument.xml index f468d43ee..a0a82cc8b 100644 --- a/modules/document/queries/updateDocument.xml +++ b/modules/document/queries/updateDocument.xml @@ -19,6 +19,7 @@ + From f83523db96929e1427bf5ce145280ef6ddfdcf53 Mon Sep 17 00:00:00 2001 From: supershop Date: Sat, 1 Dec 2007 12:37:58 +0000 Subject: [PATCH 103/265] =?UTF-8?q?=EC=98=81=EC=96=B4=20-=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B2=88=EC=97=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3127 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/springnote/conf/info.xml | 5 ++++- modules/springnote/skins/xe_official/skin.xml | 7 +++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/modules/springnote/conf/info.xml b/modules/springnote/conf/info.xml index 14227459e..fb8712857 100644 --- a/modules/springnote/conf/info.xml +++ b/modules/springnote/conf/info.xml @@ -1,8 +1,11 @@ 스프링노트 연동 + Springnote - zero + 제로 + Zero 스프링노트의 페이지를 제로보드XE에서 연동하여 출력하는 기능을 가지고 있는 모듈입니다. + This modules links pages of Springnote with ZeroboardXE, and display them. diff --git a/modules/springnote/skins/xe_official/skin.xml b/modules/springnote/skins/xe_official/skin.xml index fb8fc4694..d3cc5e916 100644 --- a/modules/springnote/skins/xe_official/skin.xml +++ b/modules/springnote/skins/xe_official/skin.xml @@ -1,9 +1,12 @@ 스프링 노트 연동 기본 스킨 + Springnote Module Basic Skin - zero + 제로 + Zero 스프링 노트 연동 모듈의 기본 스킨 + Default Skin of Springnote Module @@ -46,7 +49,7 @@ 게시판의 제목을 적어주세요. 掲示板タイトルを入力してください。 请输入版面标题(留空为不显示)。 - Plase input the title of board. + Please input the title of board. From 8ca3d71d84eb14a9c38cdcd3333b6faa72a09fdb Mon Sep 17 00:00:00 2001 From: supershop Date: Sat, 1 Dec 2007 12:38:27 +0000 Subject: [PATCH 104/265] =?UTF-8?q?=EC=98=81=EC=96=B4=20-=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B2=88=EC=97=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3128 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/springnote/lang/en.lang.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 modules/springnote/lang/en.lang.php diff --git a/modules/springnote/lang/en.lang.php b/modules/springnote/lang/en.lang.php new file mode 100644 index 000000000..e285f9078 --- /dev/null +++ b/modules/springnote/lang/en.lang.php @@ -0,0 +1,24 @@ +springnote = "Springnote"; + $lang->springnote_openid = "OpenID"; + $lang->springnote_userkey = "User Key"; + $lang->springnote_pageid = "Page Number"; + + $lang->page_url = "Original URL"; + $lang->page_modified = "Last Modification"; + $lang->page_modifier = "Last Modifier"; + + $lang->cmd_springnote_list = 'Springnote List'; + $lang->cmd_view_info = 'Springnote Info'; + + $lang->about_springnote = "Springnote is a Wiki Service that Openmaru provides.
      Springnote ZeroboardXE module displays specific springnote pages as internal documents."; + $lang->about_springnote_openid = "Please input your OpenID that created Springnote"; + $lang->about_springnote_userkey = 'User Key is needed to enable Springnote module.
      Please input generated User Key after entering your OpenID at [Get User Key] .'; + $lang->about_springnote_pageid = 'Please input pageid if you want to display specific page first.'; +?> From c24f406efc0ed662d17644ca9adecf4c79297670 Mon Sep 17 00:00:00 2001 From: bnu Date: Sat, 1 Dec 2007 16:25:11 +0000 Subject: [PATCH 105/265] =?UTF-8?q?#286=20RSS=EC=97=90=EC=84=9C=20tag?= =?UTF-8?q?=EB=A5=BC=20=ED=8F=AC=ED=95=A8=ED=95=98=EC=97=AC=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95.=20-?= =?UTF-8?q?=20RSS2.0=20=EC=8A=A4=ED=8C=A9=EC=97=90=20=EB=A7=9E=EC=B6=94?= =?UTF-8?q?=EC=96=B4=20'category'=EB=85=B8=EB=93=9C=EB=A1=9C=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3129 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/rss/tpl/rss20.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/rss/tpl/rss20.html b/modules/rss/tpl/rss20.html index c9a00a067..acd8c3ddc 100644 --- a/modules/rss/tpl/rss20.html +++ b/modules/rss/tpl/rss20.html @@ -19,6 +19,9 @@ getContentText(100)}]]> {$oDocument->getRegdateGM()} + + {$tag} + From cda2775204b071d88779d09ab5ac575a479d9794 Mon Sep 17 00:00:00 2001 From: haneul Date: Sun, 2 Dec 2007 05:06:10 +0000 Subject: [PATCH 106/265] English translation for rss reader widget git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3130 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- widgets/rss_reader/conf/info.xml | 39 +++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/widgets/rss_reader/conf/info.xml b/widgets/rss_reader/conf/info.xml index 1c465aea6..b5a7a0780 100644 --- a/widgets/rss_reader/conf/info.xml +++ b/widgets/rss_reader/conf/info.xml @@ -1,48 +1,61 @@ RSS 리더 - RSS 阅读器 + RSS 阅读器 + RSS Reader Simulz - Simulz + Simulz + Simulz RSS 리더입니다. - RSS 阅读器. + RSS 阅读器. + This widget displays data retrieved from RSS feed. 제목 - 主题 + 主题 + Title text - + + RSS URL - RSS URL + RSS URL + RSS URL text - + + 페이지 수 - 页面数 + 页面数 + number of pages text 기본 값 10 - 默认数 10 + 默认数 10 + default 10 날짜 형식 - 日期形式 + 日期形式 + Date Format text 기본 값 Y-m-d H:i:s - 默认值 Y-m-d H:i:s + 默认值 Y-m-d H:i:s + Default Y-m-d H:i:s 본문 높이 - 文本高度 + 文本高度 + Height text select 스킨에서 본문 높이 (기본값 200px) - 在select皮肤文本高度 (默认值 200px) + 在select皮肤文本高度 (默认值 200px) + From 3fc6eac5787c1c235e8a309ded3463a1a99cb338 Mon Sep 17 00:00:00 2001 From: zero Date: Mon, 3 Dec 2007 00:35:43 +0000 Subject: [PATCH 107/265] =?UTF-8?q?=ED=83=AD=ED=98=95=EC=8B=9D=20=EC=B5=9C?= =?UTF-8?q?=EA=B7=BC=EB=AC=B8=EC=84=9C=20=EC=9C=84=EC=A0=AF=EC=9D=98=20css?= =?UTF-8?q?=EB=AA=85=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3131 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- .../skins/xe_official/css/normal.css | 50 +++++++++---------- .../skins/xe_official/list.html | 2 +- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/widgets/tab_newest_document/skins/xe_official/css/normal.css b/widgets/tab_newest_document/skins/xe_official/css/normal.css index e73dc8495..1a171f21a 100644 --- a/widgets/tab_newest_document/skins/xe_official/css/normal.css +++ b/widgets/tab_newest_document/skins/xe_official/css/normal.css @@ -1,33 +1,33 @@ -.tabWdiget { overflow:hidden; } +.tabWidget { overflow:hidden; } -.tabWdiget .tabBox { border-bottom:1px solid #DEDEDE; height:27px; z-index:1; } -.tabWdiget .tabBox a { text-decoration:none; color:#666666; } -.tabWdiget .tab { position:relative; top:1px; border:1px solid #DEDEDE; margin-right:4px; float:left; cursor:pointer; background-color:#FFFFFF; z-index:2; height:25px; } -.tabWdiget .on { position:relative; top:1px; border:1px solid #DEDEDE; border-bottom:1px solid #FFFFFF; margin-right:4px; float:left; cursor:pointer; background-color:#FFFFFF; z-index:2; height:25px; } +.tabWidget .tabBox { border-bottom:1px solid #DEDEDE; height:27px; z-index:1; } +.tabWidget .tabBox a { text-decoration:none; color:#666666; } +.tabWidget .tab { position:relative; top:1px; border:1px solid #DEDEDE; margin-right:4px; float:left; cursor:pointer; background-color:#FFFFFF; z-index:2; height:25px; } +.tabWidget .on { position:relative; top:1px; border:1px solid #DEDEDE; border-bottom:1px solid #FFFFFF; margin-right:4px; float:left; cursor:pointer; background-color:#FFFFFF; z-index:2; height:25px; } -.tabWdiget .tab div { float:left; height:15px; border-bottom:5px solid #EEEEEE; font-size:9pt; padding:5px 8px 0 8px; color:#666666; } -.tabWdiget .tab div a { color:#666666; } -.tabWdiget .on div { float:left; height:15px; border-bottom:5px solid #FFFFFF; font-size:9pt; padding:5px 8px 0 8px; color:#000000; } -.tabWdiget .on div a { color:#000000; } +.tabWidget .tab div { float:left; height:15px; border-bottom:5px solid #EEEEEE; font-size:9pt; padding:5px 8px 0 8px; color:#666666; } +.tabWidget .tab div a { color:#666666; } +.tabWidget .on div { float:left; height:15px; border-bottom:5px solid #FFFFFF; font-size:9pt; padding:5px 8px 0 8px; color:#000000; } +.tabWidget .on div a { color:#000000; } -.tabWdiget .tabContent { border:1px solid #DEDEDE; padding:10px; border-top:none; background-color:#FFFFFF; z-index:1;} -.tabWdiget .show { display:block; } -.tabWdiget .hide { display:none; } +.tabWidget .tabContent { border:1px solid #DEDEDE; padding:10px; border-top:none; background-color:#FFFFFF; z-index:1;} +.tabWidget .show { display:block; } +.tabWidget .hide { display:none; } -.tabWdiget .tabContent table { border:0; width:100%; table-layout:fixed; } +.tabWidget .tabContent table { border:0; width:100%; table-layout:fixed; } -.tabWdiget .tabContent .thumbnail { text-align:center; } -.tabWdiget .tabContent .thumbnail img { border:1px solid #EEEEEE; padding:5px; float:left; } +.tabWidget .tabContent .thumbnail { text-align:center; } +.tabWidget .tabContent .thumbnail img { border:1px solid #EEEEEE; padding:5px; float:left; } -.tabWdiget .tabContent .titleBox { padding-top:3px; padding-left:10px; color:#888888; vertical-align:top;} -.tabWdiget .tabContent .titleBox .regdate { font-family:tahoma; font-size:.85em; color:#AAAAAA;} -.tabWdiget .tabContent .titleBox .title { background:url(../images/normal/bullet.gif) no-repeat 3px 6px; padding-left:10px; margin-top:3px; height:20px; white-space:nowrap; overflow:hidden; } -.tabWdiget .tabContent .titleBox .title .comment_cnt { font-weight:normal; font-size:0.8em; color:#F48A23; } -.tabWdiget .tabContent .titleBox .title a { color:#666666; text-decoration:none; } -.tabWdiget .tabContent .titleBox .title a:hover { text-decoration:underline; } +.tabWidget .tabContent .titleBox { padding-top:3px; padding-left:10px; color:#888888; vertical-align:top;} +.tabWidget .tabContent .titleBox .regdate { font-family:tahoma; font-size:.85em; color:#AAAAAA;} +.tabWidget .tabContent .titleBox .title { background:url(../images/normal/bullet.gif) no-repeat 3px 6px; padding-left:10px; margin-top:3px; height:20px; white-space:nowrap; overflow:hidden; } +.tabWidget .tabContent .titleBox .title .comment_cnt { font-weight:normal; font-size:0.8em; color:#F48A23; } +.tabWidget .tabContent .titleBox .title a { color:#666666; text-decoration:none; } +.tabWidget .tabContent .titleBox .title a:hover { text-decoration:underline; } -.tabWdiget .tabContent .titleBox .title .author { color:#AAAAAA; } -.tabWdiget .tabContent .titleBox .title .readAndVoted { font-family:tahoma; font-size:.8em; color:#AAAAAA;} -.tabWdiget .tabContent .titleBox .title .readAndVoted .readed { color:#4BC4C8;} -.tabWdiget .tabContent .titleBox .title .readAndVoted .voted { color:#C8A64B;} +.tabWidget .tabContent .titleBox .title .author { color:#AAAAAA; } +.tabWidget .tabContent .titleBox .title .readAndVoted { font-family:tahoma; font-size:.8em; color:#AAAAAA;} +.tabWidget .tabContent .titleBox .title .readAndVoted .readed { color:#4BC4C8;} +.tabWidget .tabContent .titleBox .title .readAndVoted .voted { color:#C8A64B;} diff --git a/widgets/tab_newest_document/skins/xe_official/list.html b/widgets/tab_newest_document/skins/xe_official/list.html index 96e3e45c0..9d90c3d17 100644 --- a/widgets/tab_newest_document/skins/xe_official/list.html +++ b/widgets/tab_newest_document/skins/xe_official/list.html @@ -8,7 +8,7 @@ {@ $_id_prefix = time() } {@ $_checked = false; } -
      +
      From 1feb2d02511103c2c1e2049f9da78aa06b208883 Mon Sep 17 00:00:00 2001 From: zero Date: Mon, 3 Dec 2007 00:42:47 +0000 Subject: [PATCH 108/265] =?UTF-8?q?displyMultimedia=EC=9D=98=20embed?= =?UTF-8?q?=ED=83=9C=EA=B7=B8=EC=97=90=20wmode=3Dtransparent=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3132 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- common/js/common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/js/common.js b/common/js/common.js index 300402e93..ebbde13ce 100644 --- a/common/js/common.js +++ b/common/js/common.js @@ -194,7 +194,7 @@ function displayMultimedia(src, width, height, auto_start) { ""+ ""+ ""+ - ""+ + ""+ "<\/object>"; } else if(/\.flv/i.test(src)) { html = ""; From ef474a41e2b28d92858a21cb4fbaf1f104779b5d Mon Sep 17 00:00:00 2001 From: zero Date: Mon, 3 Dec 2007 01:16:29 +0000 Subject: [PATCH 109/265] =?UTF-8?q?=EB=89=B4=EC=8A=A4=ED=8B=B0=EC=BB=A4=20?= =?UTF-8?q?=EC=B5=9C=EA=B7=BC=EA=B2=8C=EC=8B=9C=EB=AC=BC=EC=9D=98=20?= =?UTF-8?q?=EC=BB=AC=EB=9F=AC=EC=85=8B=EC=97=86=EC=9D=8C=EC=9D=84=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=ED=95=98=EC=98=80=EC=9D=84=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0=20left,right=20=EC=9D=B4=EB=AF=B8=EC=A7=80=EB=A5=BC?= =?UTF-8?q?=20blank=EC=9D=B4=EB=AF=B8=EC=A7=80=EB=A5=BC=20=EC=93=B0?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3133 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- .../skins/news_ticker/images/none/left.gif | Bin 0 -> 43 bytes .../skins/news_ticker/images/none/right.gif | Bin 0 -> 43 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 widgets/newest_document/skins/news_ticker/images/none/left.gif create mode 100644 widgets/newest_document/skins/news_ticker/images/none/right.gif diff --git a/widgets/newest_document/skins/news_ticker/images/none/left.gif b/widgets/newest_document/skins/news_ticker/images/none/left.gif new file mode 100644 index 0000000000000000000000000000000000000000..35d42e808f0a8017b8d52a06be2f8fec0b466a66 GIT binary patch literal 43 scmZ?wbhEHbWMp7uXkcLY|NlP&1B2pE7Dgb&paUX6G7L;iE{qJ;0LZEa`2YX_ literal 0 HcmV?d00001 diff --git a/widgets/newest_document/skins/news_ticker/images/none/right.gif b/widgets/newest_document/skins/news_ticker/images/none/right.gif new file mode 100644 index 0000000000000000000000000000000000000000..35d42e808f0a8017b8d52a06be2f8fec0b466a66 GIT binary patch literal 43 scmZ?wbhEHbWMp7uXkcLY|NlP&1B2pE7Dgb&paUX6G7L;iE{qJ;0LZEa`2YX_ literal 0 HcmV?d00001 From adb7de006561cd4555a5119f2aa423fbc0596219 Mon Sep 17 00:00:00 2001 From: zero Date: Mon, 3 Dec 2007 03:08:10 +0000 Subject: [PATCH 110/265] =?UTF-8?q?xe=5Flayout=EC=9D=98=20=ED=86=B5?= =?UTF-8?q?=ED=95=A9=EA=B2=80=EC=83=89=EB=B6=80=EB=B6=84=20ie7=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=96=B4=EA=B8=8B=EB=82=98=EB=8A=94=20=EA=B2=83?= =?UTF-8?q?=EC=9D=84=20ie7=20hack=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3134 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- layouts/xe_official/css/default.css | 1 + 1 file changed, 1 insertion(+) diff --git a/layouts/xe_official/css/default.css b/layouts/xe_official/css/default.css index d45f2e13c..0a41bde03 100644 --- a/layouts/xe_official/css/default.css +++ b/layouts/xe_official/css/default.css @@ -35,6 +35,7 @@ body { background:#FFFFFF url(../images/default/bgBody.gif) repeat-x left top; } #isSearch { position:absolute; top:48px; right:15px; width:214px; text-align:right;} #isSearch .searchOrder { display:none;} #isSearch .checked { position:absolute; left:0; top:0; text-align:left; display:block; padding:5px 0 0 5px; width:64px; height:14px; background:url(../images/default/bgSearchTerm.gif) no-repeat; font:11px "돋움", Dotum, "굴림", Gulim, AppleGothic, Sans-serif; color:#ffffff; line-height:normal;} +*:first-child+html #isSearch .checked { top:1px; } #isSearch ul { display:none; position:absolute; left:0; top:18px; padding:2px 0 3px 0; text-align:left; border:1px solid #919898; background:#536c6d;} #isSearch ul li { width:67px; height:18px; list-style:none; } #isSearch ul li input { display:none;} From 8da14a6edf9372a895442c95c25b39ee0f907dda Mon Sep 17 00:00:00 2001 From: zero Date: Mon, 3 Dec 2007 03:23:24 +0000 Subject: [PATCH 111/265] =?UTF-8?q?=EB=84=A4=EC=9D=B4=EB=B2=84=20=EC=A7=80?= =?UTF-8?q?=EB=8F=84=20=EC=97=90=EB=94=94=ED=84=B0=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3135 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/editor/components/naver_map/icon.gif | Bin 0 -> 1507 bytes modules/editor/components/naver_map/info.xml | 29 +++ .../components/naver_map/lang/en.lang.php | 22 +++ .../components/naver_map/lang/jp.lang.php | 21 ++ .../components/naver_map/lang/ko.lang.php | 21 ++ .../components/naver_map/lang/zh-CN.lang.php | 21 ++ .../components/naver_map/naver_map.class.php | 183 ++++++++++++++++++ .../components/naver_map/tpl/error.html | 10 + .../naver_map/tpl/navermap_component.gif | Bin 0 -> 528 bytes .../editor/components/naver_map/tpl/popup.css | 11 ++ .../components/naver_map/tpl/popup.html | 57 ++++++ .../editor/components/naver_map/tpl/popup.js | 108 +++++++++++ 12 files changed, 483 insertions(+) create mode 100644 modules/editor/components/naver_map/icon.gif create mode 100644 modules/editor/components/naver_map/info.xml create mode 100644 modules/editor/components/naver_map/lang/en.lang.php create mode 100644 modules/editor/components/naver_map/lang/jp.lang.php create mode 100644 modules/editor/components/naver_map/lang/ko.lang.php create mode 100644 modules/editor/components/naver_map/lang/zh-CN.lang.php create mode 100644 modules/editor/components/naver_map/naver_map.class.php create mode 100644 modules/editor/components/naver_map/tpl/error.html create mode 100644 modules/editor/components/naver_map/tpl/navermap_component.gif create mode 100644 modules/editor/components/naver_map/tpl/popup.css create mode 100644 modules/editor/components/naver_map/tpl/popup.html create mode 100644 modules/editor/components/naver_map/tpl/popup.js diff --git a/modules/editor/components/naver_map/icon.gif b/modules/editor/components/naver_map/icon.gif new file mode 100644 index 0000000000000000000000000000000000000000..26c0eaef44183b8b8f81de9cb6d3e2ac1ca34282 GIT binary patch literal 1507 zcmV<91swWENk%w1VKM+e0Oo%HySuw?*=u;!lQXzH+4lRX?Xz8nsXeVpmfQBq%F6uw z{6xA_mgcKdx@_X&;`a9RPmghe#@x2Hw)^}0#>U1moKWHU{>tzDWQvuD*7t4XV^zgg zTEKiMwJmUsrCQ1GShvR;vlmy#Zu9f;#PR%9tJU7(=5EoX($dm&q`RBF&s=we=I!#d z>H6#I>Nc%EC#EZr#EeyfpZE9n&DP%e`S?v*5x{A$11OtQ8owKiMmXga+!fy?Eh=H#d5_eZM4ACMhSsM24!-G9&TEuJf= z-uy_8yT0lDK+Q!-$yh1)K-v*z=_>iAf??`z2Md)xVu-ldk< z;-25(U5~Qh>F@OS`|j@U{r&yR%geH|vfbU?`uh52W@i8Y|NsC0A^8LW004ggEC2ui z05SkS000O7fPZ^~goTEOh>41Xf-ZiKkdcy;l$Dl#E`yhwoSl!Fo}r?jdzLgiVstwu zqoSaaECy9)Bvxi6G83(xuaGP$8UZH)X%{UYKRvsfy?%BOQ3Y`Y0U{O_Z67j|eSMJK zqs=}}3?dCzI9ViZ7D`DxlHiZ>q0Jaj8v-3C7hzg0Br?1)5YLadgY)EdqX(&(2R0o< zXpl1ofki1xO4ulf&|4&g^Ca2R5n=(gIS9UFV6p+m#*ZNlCIshEW~63xDj>PCAP$T* z89=-UAYes7n;>P@tVv3ehX`0IpzEMxikAZ+8W1`9&8E_>H%moQL4*pI0XVR3QG;dy z5gJ_oV=g?na8k1oDTq`6^WsI5E^goukuhRKE2bjFLPCK80uc@e$h;^6VsIYDhb=X8 z;2=+oCqzOM@t`749?r`uHA~HUkR#TxGYMKmySD8;fBu->&AYen-@t?O*6jc`?9K`N z;91VRx%21Hqf5u*CqeS**t2V|PQj0Y@8G|mO0_Dy`Sa-0fA>S7dyx0=W6i2{OGXX& z`19-EpPzmA2>=3E2Qb1AV+=Ag1gPMG3^u5se|{+VOf=I}b4@n6EZ9we8#>q^dpY<~ z#E3d0idK3OD>J+W*=k1X@s0} z&H1LAM)(0hm^1V_Lry#O^ixnn73F82eITl6qKo>;XrFrW>E}~XO;y!ZS*>vB439SI zDW``<>c<15K0uaPXsN}PTQ>+%>H~ee3M;8|!Mc#FdP?Aj5WEWELSB3I^;cknx!^*t z$R?|7AIkFThXlG7R+wpyK_(exgHd3bwA^;F@vI&w7{?k4diFW1#TYNF zFba2c?D5AShb;2QB;SFs9(O3f$I2|X?DESn#~iZ)e&`{=9Wv*v^Uf`gi}TApjHikT zJQwY<&o9eIi!Hd!V6@Rlw>)4l!xVGO4?;Z6^Roc_yz&UpNJEV^*l6=|H!PzK^`2hy zVWK(csKbssJh-ejA9rufcFQ~J!;e1z31ooXco*Ks$_pW$c+Y#Y9Hm4QS%d&a8WDc@ z<(8+-cn)owS<*=OHsD_8q|T + + 네이버맵 연동 + ネイバーマップ + NAVER 地图 + Naver Map Open Api + + 제로 + Zero + zero + zero + 네이버에서 제공하는 네이버 지도 open api를 이용하여 에디터에 원하는 곳의 지도를 추가하거나 수정할 수 있습니다.\n네이버 지도 open api키를 발급 받아서 등록을 해주셔야 정상적인 사용이 가능합니다. + ネバーから提供されるネイバーマップのOpenAPIを利用してエディターに表示したい地図を追加したり修正したりすることができます。ネイバーマップは、OpenAPIキーを取得してから登録すれば使用することができます。 + naver提供的naver地图,利用open api在编辑器里添加或修改您所需要的地图。\n为了使用naver地图首先要取得open api key,然后登录此key才可正常使用。 + You can add a map to the editor or modify it by using Naver Map open api provided by Naver.\nYou would be able to use it when you register Naver Map api key after you get it from http://www.naver.com. + + + + 네이버지도 api key + APIキー + naver地图 api key + Naver Map api key + http://www.naver.com/ 에서 네이버 지도 API key를 발급 받으신 후 입력해주세요. + http://www.naver.com/ からネイバーマップのAPIキーを取得してから入力してください。 + 在http://www.naver.com/ 取得naver地图 API key后输入。 + Please get Naver Map API key from http://www.naver.com first and then input the key. + + + diff --git a/modules/editor/components/naver_map/lang/en.lang.php b/modules/editor/components/naver_map/lang/en.lang.php new file mode 100644 index 000000000..b8840e7ed --- /dev/null +++ b/modules/editor/components/naver_map/lang/en.lang.php @@ -0,0 +1,22 @@ + + * @brief editor module > language pack of multimedia_link(Naver Map) component + **/ + + $lang->map_width = "Width"; + $lang->map_height = "Height"; + + // Expressions + $lang->about_address = "Ex) Jeongjadong Boondang, Yeoksam"; + $lang->about_address_use = "Please search the address first and then press [Insert] button. Then, the map would be added to the article."; + + // Error Messages + $lang->msg_not_exists_addr = "Address doesn't exists"; + $lang->msg_fail_to_socket_open = "Failed to connect zip code searching server"; + $lang->msg_no_result = "Nothing Found"; + + $lang->msg_no_apikey = "Naver Map api key is necessary to use Naver Map.\nPlease input api key after selecting Module > WISYWIG Editor > Naver Map Open Api"; + +?> diff --git a/modules/editor/components/naver_map/lang/jp.lang.php b/modules/editor/components/naver_map/lang/jp.lang.php new file mode 100644 index 000000000..9346c207b --- /dev/null +++ b/modules/editor/components/naver_map/lang/jp.lang.php @@ -0,0 +1,21 @@ + 翻訳:RisaPapa + * @brief ウィジウィグエディター(editor) > マルチメディアリンク(naver_map)コンポネント言語パッケージ + **/ + + $lang->map_width = "横幅サイズ"; + $lang->map_height = "縦幅サイズ"; + + // 表示メッセージ + $lang->about_address = "例)분당 정자동, 역삼"; + $lang->about_address_use = "検索ウィンドウで住所を検索した後、出力された結果を選択して、「追加」ボタンを押せば、書き込みに地図が追加されます。"; + + // エラーメッセージ + $lang->msg_not_exists_addr = "検索対象がありません。"; + $lang->msg_fail_to_socket_open = "郵便番号を検索するサーバとの接続に失敗しました。"; + $lang->msg_no_result = "検索結果がありません。"; + + $lang->msg_no_apikey = "ネイバーマップを使用するためには、ネイバーマップのOpenAPIキーを取得しなければなりません。\nOpenAPIキーを 管理者 > ウィジウィグエディター > ネイバーマップコンポネント設定を選択した後、入力してください。"; +?> diff --git a/modules/editor/components/naver_map/lang/ko.lang.php b/modules/editor/components/naver_map/lang/ko.lang.php new file mode 100644 index 000000000..da1af2a8e --- /dev/null +++ b/modules/editor/components/naver_map/lang/ko.lang.php @@ -0,0 +1,21 @@ + + * @brief 위지윅에디터(editor) 모듈 > 멀티미디어 링크 (naver_map) 컴포넌트의 언어팩 + **/ + + $lang->map_width = "가로크기"; + $lang->map_height = "세로크기"; + + // 문구 + $lang->about_address = "예) 분당 정자동, 역삼"; + $lang->about_address_use = "검색창에서 원하는 주소를 검색하신후 출력된 결과물을 선택하시고 [추가] 버튼을 눌러주시면 글에 지도가 추가가 됩니다"; + + // 에러 메세지들 + $lang->msg_not_exists_addr = "검색하려는 대상이 없습니다"; + $lang->msg_fail_to_socket_open = "우편번호 검색 대상 서버 접속이 실패하였습니다"; + $lang->msg_no_result = "검색 결과가 없습니다"; + + $lang->msg_no_apikey = "네이버맵 사용을 위해서는 네이버맵 open api key가 있어야 합니다.\nopen api key를 관리자 > 위지윅에디터 > 네이버 지도 연동 컴포넌트 설정을 선택한 후 입력하여 주세요"; +?> diff --git a/modules/editor/components/naver_map/lang/zh-CN.lang.php b/modules/editor/components/naver_map/lang/zh-CN.lang.php new file mode 100644 index 000000000..8535f3252 --- /dev/null +++ b/modules/editor/components/naver_map/lang/zh-CN.lang.php @@ -0,0 +1,21 @@ + + * @brief 网页编辑器(editor) 模块 > naver地图 (naver_map) 组件语言包 + **/ + + $lang->map_width = "宽度"; + $lang->map_height = "高度"; + + // 词句 + $lang->about_address = "例) 王府井 餐厅, 月坛公园"; + $lang->about_address_use = "在搜索窗口搜索要找的地址后,按『添加』按钮即可把相关地图插入到文章当中。"; + + // 错误信息 + $lang->msg_not_exists_addr = "没有找到搜索的对象"; + $lang->msg_fail_to_socket_open = "链接搜索邮编服务器失败。"; + $lang->msg_no_result = "没有搜索结果"; + + $lang->msg_no_apikey = "要想使用naver地图,将需要一个open api key。\n 请选择管理员 > 网页编辑器 > naver地图设置后输入open api key。"; +?> diff --git a/modules/editor/components/naver_map/naver_map.class.php b/modules/editor/components/naver_map/naver_map.class.php new file mode 100644 index 000000000..5c1150839 --- /dev/null +++ b/modules/editor/components/naver_map/naver_map.class.php @@ -0,0 +1,183 @@ +upload_target_srl = $upload_target_srl; + $this->component_path = $component_path; + } + + /** + * @brief popup window요청시 popup window에 출력할 내용을 추가하면 된다 + **/ + function getPopupContent() { + // 템플릿을 미리 컴파일해서 컴파일된 소스를 return + $tpl_path = $this->component_path.'tpl'; + + if(!$this->api_key) $tpl_file = 'error.html'; + else $tpl_file = 'popup.html'; + + Context::set("tpl_path", $tpl_path); + + $oTemplate = &TemplateHandler::getInstance(); + return $oTemplate->compile($tpl_path, $tpl_file); + } + + /** + * @brief naver map open api에서 주소를 찾는 함수 + **/ + function search_address() { + $address = Context::get('address'); + if(!$address) return new Object(-1,'msg_not_exists_addr'); + + Context::loadLang($this->component_path."lang"); + + // 지정된 서버에 요청을 시도한다 + $query_string = iconv("UTF-8","EUC-KR",sprintf('/api/geocode.php?key=%s&query=%s', $this->api_key, $address)); + + $fp = fsockopen('maps.naver.com', 80, $errno, $errstr); + if(!$fp) return new Object(-1, 'msg_fail_to_socket_open'); + + fputs($fp, "GET {$query_string} HTTP/1.0\r\n"); + fputs($fp, "Host: maps.naver.com\r\n\r\n"); + + $buff = ''; + while(!feof($fp)) { + $str = fgets($fp, 1024); + if(trim($str)=='') $start = true; + if($start) $buff .= trim($str); + } + + fclose($fp); + + $buff = trim(iconv("EUC-KR", "UTF-8", $buff)); + $buff = str_replace('', '', $buff); + + $oXmlParser = new XmlParser(); + $xml_doc = $oXmlParser->parse($buff); + + $addrs = $xml_doc->geocode->item; + if(!is_array($addrs)) $addrs = array($addrs); + $addrs_count = count($addrs); + + $address_list = array(); + for($i=0;$i<$addrs_count;$i++) { + $item = $addrs[$i]; + + $address_list[] = sprintf("%s,%s,%s", $item->point->x->body, $item->point->y->body, $item->address->body); + + } + + $this->add("address_list", implode("\n", $address_list)); + } + + /** + * @brief 에디터 컴포넌트가 별도의 고유 코드를 이용한다면 그 코드를 html로 변경하여 주는 method + * + * 이미지나 멀티미디어, 설문등 고유 코드가 필요한 에디터 컴포넌트는 고유코드를 내용에 추가하고 나서 + * DocumentModule::transContent() 에서 해당 컴포넌트의 transHtml() method를 호출하여 고유코드를 html로 변경 + * + * 네이버 지도 open api 는 doctype에 대한 오류 및 기타 등등등등의 문제 때문에 iframe 을 만들고 컴포넌트를 다시 호출해서 html을 출력하게 한다. + * 네이버 지도 open api 가 xhtml1-transitional.dtd 를 지원하게 되면 다시 깔끔하게 고쳐야 함.. + * 2006년 3월 12일 하루 다 날렸다~~~ ㅡ.ㅜ + **/ + function transHTML($xml_obj) { + $x = $xml_obj->attrs->x; + $y = $xml_obj->attrs->y; + $marker = $xml_obj->attrs->marker; + $style = $xml_obj->attrs->style; + + preg_match_all('/(width|height)([^[:digit:]]+)([0-9]+)/i',$style,$matches); + $width = trim($matches[3][0]); + $height = trim($matches[3][1]); + if(!$width) $width = 400; + if(!$height) $height = 400; + + $body_code = sprintf('
      ', $width, $height, Context::getRequestUri(), $width, $height, $x, $y, $marker, $width, $height); + return $body_code; + } + + function displayMap() { + $id = "navermap".rand(11111111,99999999); + + $width = Context::get('width'); + if(!$width) $width = 640; + + $height = Context::get('height'); + if(!$height) $height = 480; + + $x = Context::get('x'); + if(!$x) $x = 321198; + + $y = Context::get('y'); + if(!$y) $y = 529730; + + $marker = Context::get('marker'); + + $html = ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + '
      '. + ''. + ''. + ''; + + print $html; + exit(); + } + } +?> diff --git a/modules/editor/components/naver_map/tpl/error.html b/modules/editor/components/naver_map/tpl/error.html new file mode 100644 index 000000000..1a909bf5d --- /dev/null +++ b/modules/editor/components/naver_map/tpl/error.html @@ -0,0 +1,10 @@ + + +
      +
      + {nl2br($lang->msg_no_apikey)} +
      +
      + +
      +
      diff --git a/modules/editor/components/naver_map/tpl/navermap_component.gif b/modules/editor/components/naver_map/tpl/navermap_component.gif new file mode 100644 index 0000000000000000000000000000000000000000..a9e22712beba37f4306f33b18d66f17f6adc8032 GIT binary patch literal 528 zcmV+r0`L7tNk%w1VLSjH0M$DH?d+=w2nhfG|JBNK-PeS?sZZC}*U)GRX;vhFd06uD z^5){3PC^=CVq?k1y{er-qWls+~mT<>j=ieayL7v#Wj7 z=*FgzYRklz{QmpY%5&=UHPiq_WAMo`T7*CH2?qq0000000000 z00000A^8LW0027xEC2ui06YL5000L6z@2bNEEUm0%ML0Syfp1%m|;E)=0x2@Iqg8xRE#4-E+vBd<{o2neJB2nh%s2nPV5 zzE2ei4+R|o)YJzT%gs>`A0GoO2iJ59+Ey482MMX20}AC)IoBvLD>Nz&?^YoPlrEu;w-8JWKE_onJ#sSv}r`18Z8DD SinM1>g-=w1Z6cOP5CA(a + + + +
      +

      {$component_info->title} ver. {$component_info->version}

      +
      + +
      + + + + + + + + +
      + + +
      {$lang->about_address_use}
      + + + + + + + + + +
      {$lang->map_width}px
      {$lang->map_height}px
      +
      + +
      +
      + + diff --git a/modules/editor/components/naver_map/tpl/popup.js b/modules/editor/components/naver_map/tpl/popup.js new file mode 100644 index 000000000..1e301f25e --- /dev/null +++ b/modules/editor/components/naver_map/tpl/popup.js @@ -0,0 +1,108 @@ +/** + * popup으로 열렸을 경우 부모창의 위지윅에디터에 select된 멀티미디어 컴포넌트 코드를 체크하여 + * 있으면 가져와서 원하는 곳에 삽입 + **/ +function getNaverMap() { + // 부모 위지윅 에디터에서 선택된 영역이 있는지 확인 + if(typeof(opener)=="undefined") return; + + var node = opener.editorPrevNode; + if(!node || node.nodeName != "IMG") return; + + var x = node.getAttribute("x"); + var y = node.getAttribute("y"); + var width = xWidth(node); + var height = xHeight(node); + var address = node.getAttribute("address"); + + if(x&&y) { + xGetElementById("map_x").value = x; + xGetElementById("map_y").value = y; + moveMap(x,y,3); + } + if(address) { + xGetElementById("address").value = address; + search_address(address); + } + + xGetElementById("map_width").value = width-4; + xGetElementById("map_height").value = height-4; +} + +function insertNaverMap(obj) { + if(typeof(opener)=="undefined") return; + + var x = xGetElementById("map_x").value; + var y = xGetElementById("map_y").value; + var marker = xGetElementById("marker").value; + var address = xGetElementById("address").value; + + var width = xGetElementById("map_width").value; + var height = xGetElementById("map_height").value; + + var text = ""; + + opener.editorFocus(opener.editorPrevSrl); + + var iframe_obj = opener.editorGetIFrame(opener.editorPrevSrl) + + opener.editorReplaceHTML(iframe_obj, text); + opener.editorFocus(opener.editorPrevSrl); + + window.close(); +} + +xAddEventListener(window, "load", getNaverMap); + +/* 네이버의 map openapi로 주소에 따른 좌표를 요청 */ +function search_address(selected_address) { + if(typeof(selected_address)=="undefined") selected_address = null; + var address = xGetElementById("address").value; + if(!address) return; + var params = new Array(); + params['component'] = "naver_map"; + params['address'] = address; + params['method'] = "search_address"; + + var response_tags = new Array('error','message','address_list'); + exec_xml('editor', 'procEditorCall', params, complete_search_address, response_tags, selected_address); +} + +function moveMap(x,y,scale) { + if(typeof(scale)=="undefined") scale = 3; + display_map.moveMap(x,y,scale); +} + +function mapClicked(pos) { + xGetElementById("map_x").value = pos.x; + xGetElementById("map_y").value = pos.y; +} + +var naver_address_list = new Array(); +function complete_search_address(ret_obj, response_tags, selected_address) { + var address_list = ret_obj['address_list']; + if(!address_list) return; + + naver_address_list = new Array(); + + var html = ""; + var address_list = address_list.split("\n"); + for(var i=0;i"+item[2]+"
      "; + } + + var list_zone = xGetElementById("address_list"); + xInnerHtml(list_zone, html); +} + +/* 마커 표시 */ +var marker_count = 1; +function addMarker(pos) { + if(marker_count>10) return; + xGetElementById("marker").value += '|@|'+pos; + marker_count++; + return true; +} From 801df3afd57f46a8efee1b9fa046bf65628a8303 Mon Sep 17 00:00:00 2001 From: zero Date: Mon, 3 Dec 2007 03:24:08 +0000 Subject: [PATCH 112/265] =?UTF-8?q?=EC=8A=A4=ED=94=84=EB=A7=81=EB=85=B8?= =?UTF-8?q?=ED=8A=B8=20=EB=AA=A8=EB=93=88=EC=9D=98=20message.html=20?= =?UTF-8?q?=EC=8A=A4=ED=82=A8=20=ED=8C=8C=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3136 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/springnote/skins/xe_official/message.html | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 modules/springnote/skins/xe_official/message.html diff --git a/modules/springnote/skins/xe_official/message.html b/modules/springnote/skins/xe_official/message.html new file mode 100644 index 000000000..eca9925a4 --- /dev/null +++ b/modules/springnote/skins/xe_official/message.html @@ -0,0 +1,7 @@ +
      + {$message} +
      + + + {$lang->cmd_login} + From a0598b43ed3be1bf7bff6d938b55eac6014f3873 Mon Sep 17 00:00:00 2001 From: zero Date: Mon, 3 Dec 2007 04:26:35 +0000 Subject: [PATCH 113/265] =?UTF-8?q?object=20=ED=81=B4=EB=9E=98=EC=8A=A4?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=9E=98=EB=AA=BB=EB=90=9C=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=EB=AA=85=20=EC=88=98=EC=A0=95.=20(=EC=9E=A5=EC=95=84?= =?UTF-8?q?=EC=82=B0=EB=8B=98=EC=9D=98=20=EC=A0=9C=EB=B3=B4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3137 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- classes/object/Object.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/object/Object.class.php b/classes/object/Object.class.php index 8cf027e78..9080604fd 100644 --- a/classes/object/Object.class.php +++ b/classes/object/Object.class.php @@ -86,7 +86,7 @@ $args_list = func_get_args(); for($i=0;$i<$num_args;$i++) { $key = $args_list[$i]; - $output->{$key} = $this->gets($key); + $output->{$key} = $this->get($key); } return $output; } From c83388c24ca74dd6f48a8590f3fd68b8e595f3f1 Mon Sep 17 00:00:00 2001 From: zero Date: Mon, 3 Dec 2007 05:13:25 +0000 Subject: [PATCH 114/265] =?UTF-8?q?xe=5Fofficial=20=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=95=84=EC=9B=83=EC=9D=98=20=EC=83=81=EB=8B=A8=EA=B2=80?= =?UTF-8?q?=EC=83=89=EC=B0=BD=EC=9D=98=20=EB=B0=B0=EA=B2=BD=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=EA=B0=80=20=EC=9B=80=EC=A7=81=EC=9D=B4?= =?UTF-8?q?=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3138 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- layouts/xe_official/css/black.css | 4 ++-- layouts/xe_official/css/default.css | 4 ++-- layouts/xe_official/css/white.css | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/layouts/xe_official/css/black.css b/layouts/xe_official/css/black.css index 8c354875c..9121e584a 100644 --- a/layouts/xe_official/css/black.css +++ b/layouts/xe_official/css/black.css @@ -42,9 +42,9 @@ body { background:#3d3d3d url(../images/black/bgBody.gif) repeat-x;} #isSearch ul li label.on { background:#2f4345; } #isSearch ul li label:hover, #isSearch ul li label:focus { background:#2f4345;} -#isSearch .inputText { vertical-align:middle; _position:relative; _top:-1px; padding:3px 3px 1px 3px; width:94px; height:15px; color:#ffffff; border:none; background:url(../images/black/bgSearch.gif) no-repeat;} +#isSearch .inputText { vertical-align:middle; position:relative; top:0; _top:-1px; left:1px; padding:3px 3px 1px 3px; width:94px; height:13px; color:#ffffff; border:1px solid #8E8E8D; background-color:#857C79; } #isSearch .inputText:hover, -#isSearch .inputText:focus { background:url(../images/black/bgSearchOn.gif) no-repeat;} +#isSearch .inputText:focus { border:1px solid #B0B0AF; background-color:#A9A4A3; } *:first-child+html #isSearch .inputText { position:relative; top:-1px;} #isSearch .submit { vertical-align:middle; _position:relative; _top:-1px;} *:first-child+html #isSearch .submit { position:relative; top:-1px;} diff --git a/layouts/xe_official/css/default.css b/layouts/xe_official/css/default.css index 0a41bde03..f37a55491 100644 --- a/layouts/xe_official/css/default.css +++ b/layouts/xe_official/css/default.css @@ -43,9 +43,9 @@ body { background:#FFFFFF url(../images/default/bgBody.gif) repeat-x left top; } #isSearch ul li label.on { background:#455a5b; } #isSearch ul li label:hover, #isSearch ul li label:focus { background:#455a5b;} -#isSearch .inputText { vertical-align:middle; _position:relative; _top:-1px; padding:3px 3px 1px 3px; width:94px; height:15px; color:#ffffff; border:none; background:url(../images/default/bgSearch.gif) no-repeat;} +#isSearch .inputText { vertical-align:middle; position:relative; top:0; _top:-1px; left:1px; padding:3px 3px 1px 3px; width:94px; height:13px; color:#ffffff; border:1px solid #8E8E8D; background-color:#857C79; } #isSearch .inputText:hover, -#isSearch .inputText:focus { background:url(../images/default/bgSearchOn.gif) no-repeat;} +#isSearch .inputText:focus { border:1px solid #B0B0AF; background-color:#A9A4A3; } *:first-child+html body#default #isSearch .inputText { position:relative; top:-1px;} #isSearch .submit { vertical-align:middle; _position:relative; _top:-1px;} *:first-child+html body#default #isSearch .submit { position:relative; top:-1px;} diff --git a/layouts/xe_official/css/white.css b/layouts/xe_official/css/white.css index 7a6d90b83..d8a4ae3c6 100644 --- a/layouts/xe_official/css/white.css +++ b/layouts/xe_official/css/white.css @@ -42,10 +42,10 @@ body { background:#ffffff;} #isSearch ul li label.on { background:#ededed; } #isSearch ul li label:hover, #isSearch ul li label:focus { background:#ededed;} -#isSearch .inputText { vertical-align:middle; _position:relative; _top:-1px; padding:3px 3px 1px 3px; width:94px; height:15px; color:#5c5c5c; border:none; background:url(../images/white/bgSearch.gif) no-repeat;} +#isSearch .inputText { vertical-align:middle; position:relative; top:0; _top:-1px; left:1px; padding:3px 3px 1px 3px; width:94px; height:13px; color:#000000; border:1px solid #B0B0AF; background-color:#FFFFFF; } #isSearch .inputText:hover, -#isSearch .inputText:focus { background:url(../images/white/bgSearchOn.gif) no-repeat;} -*:first-child+html #isSearch .inputText { position:relative; top:-1px;} +#isSearch .inputText:focus { border:1px solid #8E8E8D; background-color:#FFFFFF; } +*:first-child+html #isSearch .inputText { position:relative; top:-1px;} #isSearch .submit { vertical-align:middle; _position:relative; _top:-1px;} *:first-child+html #isSearch .submit { position:relative; top:-1px;} From 03006f144cad91daaec886e9b38ac912f28a2e21 Mon Sep 17 00:00:00 2001 From: zero Date: Mon, 3 Dec 2007 05:47:11 +0000 Subject: [PATCH 115/265] =?UTF-8?q?=EC=9B=B9=EC=A7=84=ED=98=95=20=EC=9C=84?= =?UTF-8?q?=EC=A0=AF=EC=9D=98=20IE/FF=20=EC=97=AC=EB=B0=B1=20=EC=A1=B0?= =?UTF-8?q?=EC=A0=88=EC=9D=B4=20=EB=8B=A4=EB=A5=B8=20=EB=B6=80=EB=B6=84=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3139 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- widgets/webzine/skins/xe_official/css/normal.css | 9 ++++----- widgets/webzine/skins/xe_official/list.html | 9 ++------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/widgets/webzine/skins/xe_official/css/normal.css b/widgets/webzine/skins/xe_official/css/normal.css index 70e988ca3..13cf54ef6 100644 --- a/widgets/webzine/skins/xe_official/css/normal.css +++ b/widgets/webzine/skins/xe_official/css/normal.css @@ -1,18 +1,17 @@ -.nw_box { padding-bottom:5px; overflow:hidden; position:relative;} +.nw_box { padding-bottom:5px; overflow:hidden; } .nw_box h2 { font-size:1em; display:block; height:21px; padding:9px 0 0 9px; margin-bottom:5px; color:#000000; background:url(../images/normal/lineNotice.gif) no-repeat left bottom;} -.nw_box .more { position:absolute; top:12px; right:11px; color:#000000; font:.8em Tahoma;} .nw_box a.more { text-decoration:none;} .nw_box a.more:hover { text-decoration:underline;} .nw_box .listTable { width:100%; table-layout:fixed; border:none;} -.nw_box .listTable tr td { border-bottom:1px dotted #DEDEDE; padding-bottom:3px; margin-bottom:3px; vertical-align:top; overflow:hidden; } +.nw_box .listTable tr td { border-bottom:1px dotted #DEDEDE; padding:0;margin:0; vertical-align:top; overflow:hidden; } -.nw_box .thumbnailBox { width:100%; border:none; } +.nw_box .thumbnailBox { width:100%; margin:0;padding:0;border:none; table-layout:fixed; } .nw_box .thumbnailBox tr td { border-bottom:none; padding:none; margin:none; } -.nw_box .thumbnailBox .thumbnail { text-align:center; padding:6px; } +.nw_box .thumbnailBox .thumbnail { text-align:center; padding:5px; white-space:nowrap;} .nw_box .thumbnailBox .thumbnail img { padding:4px; border:1px solid #DEDEDE; } .nw_box .thumbnailBox .thumbnail img:hover { border:1px solid #54564b; } diff --git a/widgets/webzine/skins/xe_official/list.html b/widgets/webzine/skins/xe_official/list.html index 91947c23b..36ab6e583 100644 --- a/widgets/webzine/skins/xe_official/list.html +++ b/widgets/webzine/skins/xe_official/list.html @@ -20,12 +20,10 @@ rows_list_count>1)-->class="bottomBorder"> - + - + @@ -57,7 +57,7 @@ - # + @@ -75,7 +75,7 @@ - # + From 2a66d2d8fe5c39d9a33ec0300c7134e0aa307262 Mon Sep 17 00:00:00 2001 From: zero Date: Mon, 3 Dec 2007 06:18:48 +0000 Subject: [PATCH 117/265] =?UTF-8?q?=EB=A6=AC=EC=82=AC=EC=9D=B4=EC=A6=88=20?= =?UTF-8?q?=EB=A3=A8=ED=8B=B4=20=EB=B3=80=EA=B2=BD.=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=EA=B0=80=20=EA=B2=8C=EC=8B=9C=EA=B8=80=EB=B3=B8?= =?UTF-8?q?=EB=AC=B8=EB=B3=B4=EB=8B=A4=20=ED=81=AC=EB=A9=B4=20=EB=A6=AC?= =?UTF-8?q?=EC=82=AC=EC=9D=B4=EC=A6=88+=ED=81=B4=EB=A6=AD=ED=95=B4?= =?UTF-8?q?=EC=84=9C=20=EC=9B=90=EB=B3=B8=EB=B3=B4=EA=B8=B0,=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=EA=B0=80=20=EC=9B=90=EB=B3=B8=EA=B3=BC=20?= =?UTF-8?q?=EB=8B=A4=EB=A5=B4=EB=A9=B4=20=ED=81=B4=EB=9E=99=ED=95=B4?= =?UTF-8?q?=EC=84=9C=20=EC=9B=90=EB=B3=B8=EB=B3=B4=EA=B8=B0=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3141 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- common/js/common.js | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/common/js/common.js b/common/js/common.js index ebbde13ce..e31674b03 100644 --- a/common/js/common.js +++ b/common/js/common.js @@ -233,27 +233,29 @@ function resizeImageContents() { parent.style.width = '100%'; parent.style.overflow = 'hidden'; + var parent_width = xWidth(parent); if(parent.parentNode && xWidth(parent.parentNode)= orig_img.width) continue; - - obj.style.cursor = "pointer"; - - obj.source_width = orig_img.width; - obj.source_height = orig_img.height; - - var new_w = parent_width-20; - var new_h = Math.round(orig_img.height * new_w/orig_img.width); - - xWidth(obj, new_w); - xHeight(obj, new_h); - - xAddEventListener(obj,"click", showOriginalImage); + // 만약 선택된 이미지의 가로 크기가 부모의 가로크기보다 크면 리사이즈 (이때 부모의 가로크기 - 20 정도로 지정해줌) + if(obj_width > parent_width - 20) { + obj.style.cursor = "pointer"; + var new_w = parent_width - 20; + var new_h = Math.round(obj_height * new_w/obj_width); + xWidth(obj, new_w); + xHeight(obj, new_h); + xAddEventListener(obj,"click", showOriginalImage); + // 선택된 이미지가 부모보다 작을 경우 일단 원본 이미지를 불러와서 비교 + } else { + var orig_img = new Image(); + orig_img.src = obj.src; + if(orig_img.width > parent_width - 20 || orig_img.width != obj_width) { + obj.style.cursor = "pointer"; + xAddEventListener(obj,"click", showOriginalImage); + } + } } } xAddEventListener(window, "load", resizeImageContents); From 24357566796b4f34eca4b93cbcdf793bb7079c46 Mon Sep 17 00:00:00 2001 From: zero Date: Mon, 3 Dec 2007 06:19:03 +0000 Subject: [PATCH 118/265] =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=EB=A7=81?= =?UTF-8?q?=ED=81=AC=20=EC=97=90=EB=94=94=ED=84=B0=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=EC=97=90=EC=84=9C=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=EA=B8=80=EC=97=90=20=EC=82=BD=EC=9E=85=ED=95=9C=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=EC=9D=84=20=EA=B7=B8=EB=8C=80=EB=A1=9C=20?= =?UTF-8?q?=EC=A4=80=EC=88=98=ED=95=98=EC=A7=80=20=EB=AA=BB=ED=95=98?= =?UTF-8?q?=EB=8D=98=20=EB=AC=B8=EC=A0=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3142 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- .../components/image_link/image_link.class.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/editor/components/image_link/image_link.class.php b/modules/editor/components/image_link/image_link.class.php index a15d4d620..ddfaeb81a 100644 --- a/modules/editor/components/image_link/image_link.class.php +++ b/modules/editor/components/image_link/image_link.class.php @@ -45,9 +45,10 @@ $height = $xml_obj->attrs->height; $align = $xml_obj->attrs->align; $alt = $xml_obj->attrs->alt; - $border = $xml_obj->attrs->border; + $border = (int)$xml_obj->attrs->border; $link_url = $xml_obj->attrs->link_url; $open_window = $xml_obj->attrs->open_window; + $style = $xml_obj->attrs->style; if(!$alt) { $tmp_arr = explode('/',$src); @@ -58,7 +59,6 @@ if(!$alt) $alt = $src; $attr_output = array(); - $style_output = array(); $attr_output = array("src=\"".$src."\""); if($alt) { $attr_output[] = "alt=\"".$alt."\""; @@ -68,11 +68,11 @@ if(eregi("\.png$",$src)) $attr_output[] = "class=\"iePngFix\""; - if($width) $style_output[] = "width:".$width."px"; - if($height) $style_output[] = "height:".$height."px"; - //if(!$align) $style_output[] = "display:block"; - if($border) $style_output[] = "border:".$border."px"; - $code = sprintf("", implode(" ",$attr_output), implode(";",$style_output)); + if($width) $attr_output[] = 'width="'.$width.'"'; + if($height) $attr_output[] = 'height="'.$height.'"'; + if($border) $attr_output[] = 'border="'.$border.'"'; + + $code = sprintf("", implode(" ",$attr_output), $style); if($link_url) { if($open_window =='Y') $code = sprintf('%s', $link_url, $code); From 65cac899a6ba7fb23ecba4d9640899de3ddfaf06 Mon Sep 17 00:00:00 2001 From: zero Date: Mon, 3 Dec 2007 07:05:07 +0000 Subject: [PATCH 119/265] =?UTF-8?q?=EC=9D=BC=EC=9E=90=20=ED=8F=AC=EB=A7=B7?= =?UTF-8?q?=EC=9D=84=20=EB=8B=B4=EB=8B=B9=ED=95=98=EB=8A=94=20zdate()?= =?UTF-8?q?=ED=95=A8=EC=88=98=EC=97=90=EC=84=9C=20=EC=9D=BC=EC=9E=90?= =?UTF-8?q?=EC=9D=98=20=EB=85=84=EB=8F=84=EA=B0=80=201970=EB=85=84=20?= =?UTF-8?q?=EC=9D=B4=EC=A0=84=EC=9D=B4=EB=A9=B4=20time()=ED=95=A8=EC=88=98?= =?UTF-8?q?=EB=A5=BC=20=EC=93=B0=EC=A7=80=20=EC=95=8A=EA=B3=A0=20=EC=A7=81?= =?UTF-8?q?=EC=A0=91=20=EB=AC=B8=EC=9E=90=EC=97=B4=20=ED=8C=8C=EC=8B=B1?= =?UTF-8?q?=ED=95=98=EC=97=AC=20=EC=9E=84=EC=8B=9C=EB=A1=9C=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=EB=90=98=EB=8F=84=EB=A1=9D=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3143 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- config/func.inc.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/config/func.inc.php b/config/func.inc.php index 7dc13b7ca..decb45b49 100644 --- a/config/func.inc.php +++ b/config/func.inc.php @@ -246,6 +246,15 @@ return mktime($hour, $min, $sec, $month?$month:1, $day?$day:1, $year)+$gap; } + /** + * @brief 월이름을 return + **/ + function getMonthName($month, $short = true) { + $short_month = array("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"); + $long_month = array("January","February","March","April","May","June","July","August","September","October","November","December"); + return !$short?$long_month[$month]:$short_month[$month]; + } + /** * @brief YYYYMMDDHHIISS 형식의 시간값을 원하는 시간 포맷으로 변형 * @param str YYYYMMDDHHIISS 형식의 시간값 @@ -253,8 +262,10 @@ * @return string **/ function zdate($str, $format = "Y-m-d H:i:s") { + // 대상 시간이 없으면 null return if(!$str) return; + // 언어권에 따라서 지정된 날짜 포맷을 변경 switch(Context::getLangType()) { case "en" : case "es" : @@ -264,6 +275,23 @@ break; } + + // 년도가 1970년 이전이면 별도 처리 + if((int)substr($str,0,4)<1970) { + $hour = (int)substr($str,8,2); + $min = (int)substr($str,10,2); + $sec = (int)substr($str,12,2); + $year = (int)substr($str,0,4); + $month = (int)substr($str,4,2); + $day = (int)substr($str,6,2); + return str_replace( + array("Y","m","d","H","h","i","s","a","M", "F"), + array($year,$month,$day,$hour,$hour/12,$min,$sec,$hour<=12?"am":"pm",getMonthName($month), getMonthName($month,false)), + $format + ); + } + + // 1970년 이후라면 ztime()함수로 unixtime을 구하고 date함수로 처리 return date($format, ztime($str)); } From 7a4accb7474e1aa9f92d808533843fb5cb1497ea Mon Sep 17 00:00:00 2001 From: zero Date: Mon, 3 Dec 2007 07:16:03 +0000 Subject: [PATCH 120/265] =?UTF-8?q?=ED=83=AD=EB=B0=A9=EC=8B=9D=20=EC=9C=84?= =?UTF-8?q?=EC=A0=AF=EC=97=90=EC=84=9C=20=ED=83=AD=EC=9D=98=20id=EB=A5=BC?= =?UTF-8?q?=20=EC=8B=9C=EA=B0=84=EC=9C=BC=EB=A1=9C=20=ED=95=98=EC=97=AC=20?= =?UTF-8?q?=EC=A4=91=EB=B3=B5=EB=90=98=EB=8A=94=20=EA=B2=BD=EC=9A=B0?= =?UTF-8?q?=EA=B0=80=20=EB=B0=9C=EC=83=9D=ED=95=98=EC=97=AC=20rand()?= =?UTF-8?q?=ED=95=A8=EC=88=98=EB=A1=9C=20id=EB=A5=BC=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3144 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- widgets/tab_newest_document/skins/xe_official/list.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widgets/tab_newest_document/skins/xe_official/list.html b/widgets/tab_newest_document/skins/xe_official/list.html index 9d90c3d17..59656c9d2 100644 --- a/widgets/tab_newest_document/skins/xe_official/list.html +++ b/widgets/tab_newest_document/skins/xe_official/list.html @@ -5,7 +5,7 @@ -{@ $_id_prefix = time() } +{@ $_id_prefix = rand(1111111,9999999)} {@ $_checked = false; }
      From 4c418919f4b2a078525316eee0c83a03d9688782 Mon Sep 17 00:00:00 2001 From: zero Date: Mon, 3 Dec 2007 07:28:15 +0000 Subject: [PATCH 121/265] =?UTF-8?q?=EC=B5=9C=EA=B7=BC=20=EB=AC=B8=EC=84=9C?= =?UTF-8?q?=20=EC=9C=84=EC=A0=AF=20>=20=EB=89=B4=EC=8A=A4=ED=8B=B0?= =?UTF-8?q?=EC=BB=A4=EC=9D=98=20div=20id=EA=B0=92=EC=9D=B4=20=EC=88=AB?= =?UTF-8?q?=EC=9E=90=EB=A1=9C=EB=A7=8C=20=EC=83=9D=EC=84=B1=EB=90=98?= =?UTF-8?q?=EB=8A=94=20=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3145 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- widgets/newest_document/skins/news_ticker/list.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widgets/newest_document/skins/news_ticker/list.html b/widgets/newest_document/skins/news_ticker/list.html index fe0f4212b..46d94dd9e 100644 --- a/widgets/newest_document/skins/news_ticker/list.html +++ b/widgets/newest_document/skins/news_ticker/list.html @@ -8,7 +8,7 @@ {@ $colorset = "none" } -{@ $_news_ticker_id = "news_ticker_"+time() } +{@ $_news_ticker_id = "news_ticker_".time() }
      - -
      @@ -85,7 +83,4 @@
      - - more - From 58ed59a79a50f8919ac3b2105d29a93cb0357b9e Mon Sep 17 00:00:00 2001 From: zero Date: Mon, 3 Dec 2007 05:47:32 +0000 Subject: [PATCH 116/265] =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=EC=8B=9C=20=EC=9C=84=EC=A0=AF=EB=B0=95=EC=8A=A4?= =?UTF-8?q?=EB=8A=94=20=ED=85=8C=EB=91=90=EB=A6=AC=EB=A5=BC=20=ED=8C=8C?= =?UTF-8?q?=EB=9E=80=EC=83=89=EC=9C=BC=EB=A1=9C=20=ED=95=98=EA=B3=A0,=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=EC=9D=84=20=EC=99=BC=EC=AA=BD=20=EC=83=81?= =?UTF-8?q?=EB=8B=A8=EC=9C=BC=EB=A1=9C=20=EC=9D=B4=EB=8F=99=EC=8B=9C?= =?UTF-8?q?=ED=82=B4(=EC=9C=84=EC=A0=AF=EA=B3=BC=20=EA=B2=B9=EC=B9=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8F=84=EB=A1=9D)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3140 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- classes/widget/WidgetHandler.class.php | 2 +- modules/widget/tpl/css/widget.css | 7 +++++ modules/widget/tpl/js/widget.js | 38 +++++++++++++++----------- modules/widget/tpl/widget_layer.html | 8 +++--- 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/classes/widget/WidgetHandler.class.php b/classes/widget/WidgetHandler.class.php index 48fd65729..4e576b4e9 100644 --- a/classes/widget/WidgetHandler.class.php +++ b/classes/widget/WidgetHandler.class.php @@ -73,7 +73,7 @@ $widget_padding_top = $args->widget_padding_top; $widget_padding_bottom = $args->widget_padding_bottom; if($include_info) { - $tpl = sprintf('
      ', $style, $widget_padding_top, $widget_padding_right, $widget_padding_bottom, $widget_padding_left, $widget_padding_top, $widget_padding_right, $widget_padding_bottom, $widget_padding_left); + $tpl = sprintf('
      ', $style, $widget_padding_top, $widget_padding_right, $widget_padding_bottom, $widget_padding_left, $widget_padding_top, $widget_padding_right, $widget_padding_bottom, $widget_padding_left); } else { $tpl = sprintf('
      %s', $style, $widget_padding_top, $widget_padding_right, $widget_padding_bottom, $widget_padding_left, $body); } diff --git a/modules/widget/tpl/css/widget.css b/modules/widget/tpl/css/widget.css index b21977244..f1e234da1 100644 --- a/modules/widget/tpl/css/widget.css +++ b/modules/widget/tpl/css/widget.css @@ -20,6 +20,13 @@ .widgetOutput .widgetResize { background:transparent url("../images/btn_resize.gif") no-repeat left bottom; width:12px; height:12px; position:absolute; bottom:1px; right:1px; cursor:pointer; z-index:1000;} .widgetOutput .widgetResizeLeft { background:transparent url("../images/btn_resize_left.gif") no-repeat left bottom; width:12px; height:12px; position:absolute; bottom:0; left:1px; cursor:pointer; z-index:1000;} +.widgetOutput .widgetBoxBorder { border:1px dotted #267BEE; z-index:999; } +.widgetOutput .widgetBoxCopy { background:transparent url("../images/widget_copy.gif") no-repeat 1px 1px; width:14px; height:14px; position:absolute; top:1px; left:1px; cursor:pointer; z-index:1000;} +.widgetOutput .widgetBoxSize { background:transparent url("../images/widget_size.gif") no-repeat 1px 1px; width:14px; height:14px; position:absolute; top:1px; left:15px; cursor:pointer; z-index:1000;} +.widgetOutput .widgetBoxRemove { background:transparent url("../images/widget_remove.gif") no-repeat 1px 1px; width:14px; height:14px; position:absolute; top:1px; left:30px; cursor:pointer; z-index:1000;} +.widgetOutput .widgetBoxResize { background:transparent url("../images/btn_resize.gif") no-repeat left bottom; width:12px; height:12px; position:absolute; bottom:1px; right:1px; cursor:pointer; z-index:1000;} +.widgetOutput .widgetBoxResizeLeft { background:transparent url("../images/btn_resize_left.gif") no-repeat left bottom; width:12px; height:12px; position:absolute; bottom:0; left:1px; cursor:pointer; z-index:1000;} + #pageSizeLayer { width:500px; overflow:hidden; border:1px solid #888888; background:#FFFFFF; z-index:2000; position:absolute; } #pageSizeLayer table { border:0; width:100%; table-layout:fixed; } #pageSizeLayer table th { padding:4px 0 4px 0; background-color:#DEDEDE; text-align:center; color:#888888;} diff --git a/modules/widget/tpl/js/widget.js b/modules/widget/tpl/js/widget.js index 30953cf5e..5ffd0f3e7 100644 --- a/modules/widget/tpl/js/widget.js +++ b/modules/widget/tpl/js/widget.js @@ -112,7 +112,7 @@ function getContentWidgetCode(childObj, widget) { function getWidgetBoxCode(childObj, widget) { var cobj = childObj.firstChild; while(cobj) { - if(cobj.className == "widgetBorder") { + if(cobj.className == "widgetBorder" || cobj.className == "widgetBoxBorder") { var c2obj = cobj.firstChild; while(c2obj) { if(c2obj.className == "nullWidget") { @@ -200,12 +200,12 @@ function completeAddContent(ret_obj) { function doAddWidgetBox() { var tpl = ''+ '
      '+ - '
      '+ - '
      '+ - '
      '+ - '
      '+ - '
      '+ - '
      '+ + '
      '+ + '
      '+ + '
      '+ + '
      '+ + '
      '+ + '
      '+ '
      '+ '
      '+ '
      '+ @@ -234,6 +234,12 @@ function doFitBorderSize() { xHeight(obj, xHeight(obj.parentNode)); obj.parentNode.style.clear = ''; } + var obj_list = xGetElementsByClassName('widgetBoxBorder', zonePageObj); + for(var i=0;i zoneRight) nx = zoneRight; @@ -677,7 +683,7 @@ function widgetDrag(tobj, dx, dy) { xHeight(tobj.parentNode, new_height); // 위젯 리사이즈 (좌측) - } else if(tobj.className == 'widgetResizeLeft') { + } else if(tobj.className == 'widgetResizeLeft' || tobj.className == 'widgetBoxResizeLeft') { if(nx < zoneLeft) nx = zoneLeft; diff --git a/modules/widget/tpl/widget_layer.html b/modules/widget/tpl/widget_layer.html index 05070289e..6437bbff2 100644 --- a/modules/widget/tpl/widget_layer.html +++ b/modules/widget/tpl/widget_layer.html @@ -47,7 +47,7 @@ - # +
      px @@ -65,7 +65,7 @@ - # +
      From 7a676e12b7ffb19b717aff66e2215185aa487f00 Mon Sep 17 00:00:00 2001 From: zero Date: Mon, 3 Dec 2007 09:00:14 +0000 Subject: [PATCH 122/265] check documents.extra_vars column existing git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3146 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/document/document.class.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/modules/document/document.class.php b/modules/document/document.class.php index 3230abce2..bfdf55fb8 100644 --- a/modules/document/document.class.php +++ b/modules/document/document.class.php @@ -84,6 +84,12 @@ // 2007. 11. 20 게시글에 module_srl + is_notice 복합인덱스 만들기 if(!$oDB->isIndexExists("documents","idx_module_notice")) return true; + /** + * 2007. 12. 03 : 확장변수(extra_vars) 컬럼이 없을 경우 추가 + **/ + if(!$oDB->isColumnExists("documents","extra_vars")) return true; + + return false; } @@ -157,6 +163,11 @@ // 2007. 11. 20 게시글에 module_srl + is_notice 복합인덱스 만들기 if(!$oDB->isIndexExists("documents","idx_module_notice")) $oDB->addIndex("documents","idx_module_notice", array("module_srl","is_notice")); + /** + * 2007. 12. 03 : 확장변수(extra_vars) 컬럼이 없을 경우 추가 + **/ + if(!$oDB->isColumnExists("documents","extra_vars")) $oDB->addColumn('documents','extra_vars','text'); + return new Object(0,'success_updated'); } From 18d67d3f6ef3818ddc6a317e038f25e68bb95705 Mon Sep 17 00:00:00 2001 From: supershop Date: Mon, 3 Dec 2007 10:06:18 +0000 Subject: [PATCH 123/265] =?UTF-8?q?=EC=98=81=EC=96=B4=20-=20=EA=B8=B0?= =?UTF-8?q?=EC=A1=B4=20=EB=B2=88=EC=97=AD=EB=AC=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3147 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/editor/components/naver_map/lang/en.lang.php | 2 +- modules/editor/lang/en.lang.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/editor/components/naver_map/lang/en.lang.php b/modules/editor/components/naver_map/lang/en.lang.php index b8840e7ed..2a5d9ec97 100644 --- a/modules/editor/components/naver_map/lang/en.lang.php +++ b/modules/editor/components/naver_map/lang/en.lang.php @@ -13,7 +13,7 @@ $lang->about_address_use = "Please search the address first and then press [Insert] button. Then, the map would be added to the article."; // Error Messages - $lang->msg_not_exists_addr = "Address doesn't exists"; + $lang->msg_not_exists_addr = "Address doesn't exist"; $lang->msg_fail_to_socket_open = "Failed to connect zip code searching server"; $lang->msg_no_result = "Nothing Found"; diff --git a/modules/editor/lang/en.lang.php b/modules/editor/lang/en.lang.php index c7e43f544..4149f8eb4 100644 --- a/modules/editor/lang/en.lang.php +++ b/modules/editor/lang/en.lang.php @@ -18,8 +18,8 @@ $lang->about_component = "About component"; $lang->about_component_grant = "Only selected groups are allowed to use. (Everyone can use it when mode is disabled)"; - $lang->msg_component_is_not_founded = 'Unabled to find editor component %s'; - $lang->msg_component_is_inserted = 'Selected component is already inputted'; + $lang->msg_component_is_not_founded = 'Cannot find editor component %s'; + $lang->msg_component_is_inserted = 'Selected component is already inserted'; $lang->msg_component_is_first_order = 'Selected component is located at the first position'; $lang->msg_component_is_last_order = 'Selected component is located at the last position'; $lang->msg_load_saved_doc = "There is an automatically saved article. Do you wish to recover it?\nThe auto-saved draft will be discarded after saving current article"; @@ -69,7 +69,7 @@ $lang->edit->help_remove_indent = "Remove indent"; $lang->edit->help_list_number = "Apply number list"; $lang->edit->help_list_bullet = "Apply bullet list"; - $lang->edit->help_use_paragrapth = "Press Ctrl+Enter to use paragraph. (Press Alt+S to save)"; + $lang->edit->help_use_paragrapth = "Press Ctrl+Enter to use paragraph. (Press Alt+S to submit)"; $lang->edit->upload = 'Attachment'; $lang->edit->upload_file = 'Attach'; @@ -81,5 +81,5 @@ $lang->edit->icon_align_middle = 'Align Center'; $lang->edit->icon_align_right = 'Align Right'; - $lang->about_dblclick_in_editor = 'You are able to set detail component configure by double-clicking on background, text, images, or quotations'; + $lang->about_dblclick_in_editor = 'You may set detail component configures by double-clicking background, text, images, or quotations'; ?> From cb4a4fe479d52c71bddba6099fed5cad9eeb0850 Mon Sep 17 00:00:00 2001 From: bnu Date: Mon, 3 Dec 2007 12:58:24 +0000 Subject: [PATCH 124/265] =?UTF-8?q?xquared=EC=97=90=EB=94=94=ED=84=B0=20?= =?UTF-8?q?=EC=8A=A4=ED=82=A8=EC=97=90=EC=84=9C=20=ED=95=84=EC=9A=94?= =?UTF-8?q?=EC=97=86=EB=8A=94=20=ED=8C=8C=EC=9D=BC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3148 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/editor/skins/xquared/doc/api/_01.html | 45 - modules/editor/skins/xquared/doc/api/_02.html | 143 -- modules/editor/skins/xquared/doc/api/_03.html | 161 -- modules/editor/skins/xquared/doc/api/_04.html | 45 - modules/editor/skins/xquared/doc/api/_05.html | 796 ------ modules/editor/skins/xquared/doc/api/_06.html | 216 -- modules/editor/skins/xquared/doc/api/_07.html | 71 - modules/editor/skins/xquared/doc/api/_08.html | 71 - modules/editor/skins/xquared/doc/api/_09.html | 71 - modules/editor/skins/xquared/doc/api/_10.html | 71 - modules/editor/skins/xquared/doc/api/_11.html | 125 - modules/editor/skins/xquared/doc/api/_12.html | 189 -- modules/editor/skins/xquared/doc/api/_13.html | 153 -- modules/editor/skins/xquared/doc/api/_14.html | 71 - modules/editor/skins/xquared/doc/api/_15.html | 71 - modules/editor/skins/xquared/doc/api/_16.html | 71 - modules/editor/skins/xquared/doc/api/_17.html | 71 - modules/editor/skins/xquared/doc/api/_18.html | 512 ---- modules/editor/skins/xquared/doc/api/_19.html | 45 - .../skins/xquared/doc/api/constructor.gif | Bin 363 -> 0 bytes .../editor/skins/xquared/doc/api/default.css | 116 - modules/editor/skins/xquared/doc/api/file.gif | Bin 242 -> 0 bytes .../skins/xquared/doc/api/file_list.html | 149 -- .../editor/skins/xquared/doc/api/function.gif | Bin 224 -> 0 bytes .../editor/skins/xquared/doc/api/index.html | 13 - .../editor/skins/xquared/doc/api/object.gif | Bin 585 -> 0 bytes .../editor/skins/xquared/doc/api/overview.gif | Bin 614 -> 0 bytes .../editor/skins/xquared/doc/api/splash.html | 7 - .../editor/skins/xquared/doc/api/src_01.html | 24 - .../editor/skins/xquared/doc/api/src_02.html | 344 --- .../editor/skins/xquared/doc/api/src_03.html | 325 --- .../editor/skins/xquared/doc/api/src_04.html | 163 -- .../editor/skins/xquared/doc/api/src_05.html | 2216 ---------------- .../editor/skins/xquared/doc/api/src_06.html | 2262 ----------------- .../editor/skins/xquared/doc/api/src_07.html | 54 - .../editor/skins/xquared/doc/api/src_08.html | 369 --- .../editor/skins/xquared/doc/api/src_09.html | 382 --- .../editor/skins/xquared/doc/api/src_10.html | 91 - .../editor/skins/xquared/doc/api/src_11.html | 209 -- .../editor/skins/xquared/doc/api/src_12.html | 135 - .../editor/skins/xquared/doc/api/src_13.html | 235 -- .../editor/skins/xquared/doc/api/src_14.html | 12 - .../editor/skins/xquared/doc/api/src_15.html | 147 -- .../editor/skins/xquared/doc/api/src_16.html | 112 - .../editor/skins/xquared/doc/api/src_17.html | 21 - .../editor/skins/xquared/doc/api/src_18.html | 157 -- .../editor/skins/xquared/doc/api/src_19.html | 16 - 47 files changed, 10557 deletions(-) delete mode 100644 modules/editor/skins/xquared/doc/api/_01.html delete mode 100644 modules/editor/skins/xquared/doc/api/_02.html delete mode 100644 modules/editor/skins/xquared/doc/api/_03.html delete mode 100644 modules/editor/skins/xquared/doc/api/_04.html delete mode 100644 modules/editor/skins/xquared/doc/api/_05.html delete mode 100644 modules/editor/skins/xquared/doc/api/_06.html delete mode 100644 modules/editor/skins/xquared/doc/api/_07.html delete mode 100644 modules/editor/skins/xquared/doc/api/_08.html delete mode 100644 modules/editor/skins/xquared/doc/api/_09.html delete mode 100644 modules/editor/skins/xquared/doc/api/_10.html delete mode 100644 modules/editor/skins/xquared/doc/api/_11.html delete mode 100644 modules/editor/skins/xquared/doc/api/_12.html delete mode 100644 modules/editor/skins/xquared/doc/api/_13.html delete mode 100644 modules/editor/skins/xquared/doc/api/_14.html delete mode 100644 modules/editor/skins/xquared/doc/api/_15.html delete mode 100644 modules/editor/skins/xquared/doc/api/_16.html delete mode 100644 modules/editor/skins/xquared/doc/api/_17.html delete mode 100644 modules/editor/skins/xquared/doc/api/_18.html delete mode 100644 modules/editor/skins/xquared/doc/api/_19.html delete mode 100644 modules/editor/skins/xquared/doc/api/constructor.gif delete mode 100644 modules/editor/skins/xquared/doc/api/default.css delete mode 100644 modules/editor/skins/xquared/doc/api/file.gif delete mode 100644 modules/editor/skins/xquared/doc/api/file_list.html delete mode 100644 modules/editor/skins/xquared/doc/api/function.gif delete mode 100644 modules/editor/skins/xquared/doc/api/index.html delete mode 100644 modules/editor/skins/xquared/doc/api/object.gif delete mode 100644 modules/editor/skins/xquared/doc/api/overview.gif delete mode 100644 modules/editor/skins/xquared/doc/api/splash.html delete mode 100644 modules/editor/skins/xquared/doc/api/src_01.html delete mode 100644 modules/editor/skins/xquared/doc/api/src_02.html delete mode 100644 modules/editor/skins/xquared/doc/api/src_03.html delete mode 100644 modules/editor/skins/xquared/doc/api/src_04.html delete mode 100644 modules/editor/skins/xquared/doc/api/src_05.html delete mode 100644 modules/editor/skins/xquared/doc/api/src_06.html delete mode 100644 modules/editor/skins/xquared/doc/api/src_07.html delete mode 100644 modules/editor/skins/xquared/doc/api/src_08.html delete mode 100644 modules/editor/skins/xquared/doc/api/src_09.html delete mode 100644 modules/editor/skins/xquared/doc/api/src_10.html delete mode 100644 modules/editor/skins/xquared/doc/api/src_11.html delete mode 100644 modules/editor/skins/xquared/doc/api/src_12.html delete mode 100644 modules/editor/skins/xquared/doc/api/src_13.html delete mode 100644 modules/editor/skins/xquared/doc/api/src_14.html delete mode 100644 modules/editor/skins/xquared/doc/api/src_15.html delete mode 100644 modules/editor/skins/xquared/doc/api/src_16.html delete mode 100644 modules/editor/skins/xquared/doc/api/src_17.html delete mode 100644 modules/editor/skins/xquared/doc/api/src_18.html delete mode 100644 modules/editor/skins/xquared/doc/api/src_19.html diff --git a/modules/editor/skins/xquared/doc/api/_01.html b/modules/editor/skins/xquared/doc/api/_01.html deleted file mode 100644 index bd7000e14..000000000 --- a/modules/editor/skins/xquared/doc/api/_01.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - JsDoc: Browser.js - - - - -
      -
      - -
      Library: Browser.js
      -
      -
      - Overview -
      -
      -
      -
      - -
      -
      -
      - -
      Constructors
      - - -
      Functions
      - - -
      Objects
      - -
      -
      -
      - Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:20 GMT. -
      - - diff --git a/modules/editor/skins/xquared/doc/api/_02.html b/modules/editor/skins/xquared/doc/api/_02.html deleted file mode 100644 index bc396fa0a..000000000 --- a/modules/editor/skins/xquared/doc/api/_02.html +++ /dev/null @@ -1,143 +0,0 @@ - - - - - - JsDoc: - - - - -
      -
      - -
      Library: Controls.js
      -
      -
      - Overview -
      -
      -
      xq.controls provides common UI elements such as dialog.
      -
      - -
      -
      -
      - -
      Constructors
      - - - - - - - - -
      Functions
      - - -
      -
      - - - - this.form.onsubmit() - -
      - - - - - - - - - - -
      - - - -
      -
      - - - - cancelButton.onclick() - -
      - - - - - - - - - - -
      - - - -
      -
      - - - - this.param.renderItem(item) - -
      - - - - - - -
      parameters
      -
      - - - - - - - -
      - - - item - - -
      - - - - - -
      - - - -
      Objects
      - - - - - - - - - - -
      -
      -
      - Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:20 GMT. -
      - - diff --git a/modules/editor/skins/xquared/doc/api/_03.html b/modules/editor/skins/xquared/doc/api/_03.html deleted file mode 100644 index 527f10740..000000000 --- a/modules/editor/skins/xquared/doc/api/_03.html +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - JsDoc: DomTree.js - - - - -
      -
      - -
      Library: DomTree.js
      -
      -
      - Overview -
      -
      -
      -
      - -
      -
      -
      - -
      Constructors
      - - - - - - - - -
      Functions
      - - - - -
      -
      - - - - findLeft(el) - -
      - - - - - - -
      parameters
      - - - - - - - - -
      - - - el - - -
      - - - - - -
      - - - -
      -
      - - - - findRight(el) - -
      - - - - - - -
      parameters
      - - - - - - - - -
      - - - el - - -
      - - - - - -
      - - - -
      Objects
      - - -
      -
      - - - - - xq.DomTree - -
      - - -
      Provide various tree operations. - -TODO: Add specs
      - - - - - -
      - - - - - - - - - -
      -
      -
      - Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:21 GMT. -
      - - diff --git a/modules/editor/skins/xquared/doc/api/_04.html b/modules/editor/skins/xquared/doc/api/_04.html deleted file mode 100644 index 080339233..000000000 --- a/modules/editor/skins/xquared/doc/api/_04.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - JsDoc: - - - - -
      -
      - -
      Library: EditHistory.js
      -
      -
      - Overview -
      -
      -
      xq.EditHistory manages editing history and performs UNDO/REDO.
      -
      - -
      -
      -
      - -
      Constructors
      - - -
      Functions
      - - -
      Objects
      - -
      -
      -
      - Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:21 GMT. -
      - - diff --git a/modules/editor/skins/xquared/doc/api/_05.html b/modules/editor/skins/xquared/doc/api/_05.html deleted file mode 100644 index 4b8bee6a9..000000000 --- a/modules/editor/skins/xquared/doc/api/_05.html +++ /dev/null @@ -1,796 +0,0 @@ - - - - - - JsDoc: - - - - -
      -
      - -
      Library: Editor.js
      -
      -
      - Overview -
      -
      -
      xq.Editor manages configurations such as autocompletion and autocorrection, edit mode/normal mode switching, handles editing commands, keyboard shortcuts and other events.
      -
      - -
      -
      -
      - -
      Constructors
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      Functions
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      -
      - - - - criteria(text) - -
      - - - - - - -
      parameters
      - - - - - - - - -
      - - - text - - -
      - - - - - -
      - - - -
      -
      - - - - criteria(text) - -
      - - - - - - -
      parameters
      - - - - - - - - -
      - - - text - - -
      - - - - - -
      - - - -
      -
      - - - - this.contentElement.form.onsubmit() - -
      - - - - - - - - - - -
      - - - -
      -
      - - - - cancelMousedown(e) - -
      - - - - - - -
      parameters
      - - - - - - - - -
      - - - e - - -
      - - - - - -
      - - - -
      -
      - - - - finder(node) - -
      - - - - - - -
      parameters
      - - - - - - - - -
      - - - node - - -
      - - - - - -
      - - - -
      -
      - - - - exitCondition(node) - -
      - - - - - - -
      parameters
      - - - - - - - - -
      - - - node - - -
      - - - - - -
      - - - -
      Objects
      - - -
      -
      - - - object - - - - this.config - -
      - - -
      Editor's configuration
      - - - - - -
      - - - - -
      -
      - - - Element - - - - this.contentElement - -
      - - -
      Original content element
      - - - - - -
      - - - - -
      -
      - - - Document - - - - this.doc - -
      - - -
      Owner document of content element
      - - - - - -
      - - - - -
      -
      - - - Element - - - - this.body - -
      - - -
      Body of content element
      - - - - - -
      - - - - -
      -
      - - - Object - - - - this.currentEditMode - -
      - - -
      False or 'readonly' means read-only mode, true or 'wysiwyg' means WYSIWYG editing mode, and 'source' means source editing mode.
      - - - - - -
      - - - - -
      -
      - - - xq.RichDom - - - - this.rdom - -
      - - -
      RichDom instance
      - - - - - -
      - - - - -
      -
      - - - xq.Validator - - - - this.validator - -
      - - -
      Validator instance
      - - - - - -
      - - - - -
      -
      - - - Element - - - - this.outmostWrapper - -
      - - -
      Outmost wrapper div
      - - - - - -
      - - - - -
      -
      - - - Element - - - - this.sourceEditorDiv - -
      - - -
      Source editor container
      - - - - - -
      - - - - -
      -
      - - - Element - - - - this.sourceEditorTextarea - -
      - - -
      Source editor textarea
      - - - - - -
      - - - - -
      -
      - - - Element - - - - this.wysiwygEditorDiv - -
      - - -
      WYSIWYG editor container
      - - - - - -
      - - - - -
      -
      - - - IFrame - - - - this.editorFrame - -
      - - -
      Design mode iframe
      - - - - - -
      - - - - -
      -
      - - - Window - - - - this.editorWin - -
      - - -
      Window that contains design mode iframe
      - - - - - -
      - - - - -
      -
      - - - Document - - - - this.editorDoc - -
      - - -
      Document that contained by design mode iframe
      - - - - - -
      - - - - -
      -
      - - - Element - - - - this.editorBody - -
      - - -
      Body that contained by design mode iframe
      - - - - - -
      - - - - -
      -
      - - - Element - - - - this.toolbarContainer - -
      - - -
      Toolbar container
      - - - - - -
      - - - - -
      -
      - - - Array - - - - this.toolbarButtons - -
      - - -
      Toolbar buttons
      - - - - - -
      - - - - -
      -
      - - - xq.EditHistory - - - - this.editHistory - -
      - - -
      Undo/redo manager
      - - - - - -
      - - - - - - - - - - - - - - - - - - - - - -
      -
      -
      - Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:34 GMT. -
      - - diff --git a/modules/editor/skins/xquared/doc/api/_06.html b/modules/editor/skins/xquared/doc/api/_06.html deleted file mode 100644 index 3aa42a640..000000000 --- a/modules/editor/skins/xquared/doc/api/_06.html +++ /dev/null @@ -1,216 +0,0 @@ - - - - - - JsDoc: RichDom.js - - - - -
      -
      - -
      Library: RichDom.js
      -
      -
      - Overview -
      -
      -
      -
      - -
      -
      -
      - -
      Constructors
      - - - - - - - - - - - - -
      Functions
      - - - - - - -
      -
      - - - - finder(node) - -
      - - - - - - -
      parameters
      - - - - - - - - -
      - - - node - - -
      - - - - - -
      - - - -
      -
      - - - - exitCondition(node) - -
      - - - - - - -
      parameters
      - - - - - - - - -
      - - - node - - -
      - - - - - -
      - - - -
      -
      - - - - xq.RichDom.createInstance() - -
      - - -
      Creates and returns instance of browser specific implementation.
      - - - - - - - - - -
      - - - -
      Objects
      - - -
      -
      - - - - - xq.RichDom - -
      - - -
      Encapsulates browser incompatibility problem and provides rich set of DOM manipulation API. - -RichDom provides basic CRUD + Advanced DOM manipulation API, various query methods and caret/selection management API
      - - - - - -
      - - - - -
      -
      - - - - - this.tree - -
      - - -
      instance of DomTree
      - - - - - -
      - - - - - - - - - - - - -
      -
      -
      - Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:48 GMT. -
      - - diff --git a/modules/editor/skins/xquared/doc/api/_07.html b/modules/editor/skins/xquared/doc/api/_07.html deleted file mode 100644 index 58e74f9aa..000000000 --- a/modules/editor/skins/xquared/doc/api/_07.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - JsDoc: RichDomGecko.js - - - - -
      -
      - -
      Library: RichDomGecko.js
      -
      -
      - Overview -
      -
      -
      -
      - -
      -
      -
      - -
      Constructors
      - - - - -
      Functions
      - - - - -
      Objects
      - - -
      -
      - - - - - xq.RichDomGecko - -
      - - -
      RichDom for Gecko
      - - - - - -
      - - - -
      -
      -
      - Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:48 GMT. -
      - - diff --git a/modules/editor/skins/xquared/doc/api/_08.html b/modules/editor/skins/xquared/doc/api/_08.html deleted file mode 100644 index 56f0609f3..000000000 --- a/modules/editor/skins/xquared/doc/api/_08.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - JsDoc: RichDomTrident.js - - - - -
      -
      - -
      Library: RichDomTrident.js
      -
      -
      - Overview -
      -
      -
      -
      - -
      -
      -
      - -
      Constructors
      - - - - -
      Functions
      - - - - -
      Objects
      - - -
      -
      - - - - - xq.RichDomTrident - -
      - - -
      RichDom for Internet Explorer 6 and 7
      - - - - - -
      - - - -
      -
      -
      - Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:48 GMT. -
      - - diff --git a/modules/editor/skins/xquared/doc/api/_09.html b/modules/editor/skins/xquared/doc/api/_09.html deleted file mode 100644 index 5a3a1fe0f..000000000 --- a/modules/editor/skins/xquared/doc/api/_09.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - JsDoc: RichDomW3.js - - - - -
      -
      - -
      Library: RichDomW3.js
      -
      -
      - Overview -
      -
      -
      -
      - -
      -
      -
      - -
      Constructors
      - - - - -
      Functions
      - - - - -
      Objects
      - - -
      -
      - - - - - xq.RichDomW3 - -
      - - -
      RichDom for W3C Standard Engine
      - - - - - -
      - - - -
      -
      -
      - Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:49 GMT. -
      - - diff --git a/modules/editor/skins/xquared/doc/api/_10.html b/modules/editor/skins/xquared/doc/api/_10.html deleted file mode 100644 index 9c4670246..000000000 --- a/modules/editor/skins/xquared/doc/api/_10.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - JsDoc: RichDomWebkit.js - - - - -
      -
      - -
      Library: RichDomWebkit.js
      -
      -
      - Overview -
      -
      -
      -
      - -
      -
      -
      - -
      Constructors
      - - - - -
      Functions
      - - - - -
      Objects
      - - -
      -
      - - - - - xq.RichDomWebkit - -
      - - -
      RichDom for Webkit
      - - - - - -
      - - - -
      -
      -
      - Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:49 GMT. -
      - - diff --git a/modules/editor/skins/xquared/doc/api/_11.html b/modules/editor/skins/xquared/doc/api/_11.html deleted file mode 100644 index c5409a591..000000000 --- a/modules/editor/skins/xquared/doc/api/_11.html +++ /dev/null @@ -1,125 +0,0 @@ - - - - - - JsDoc: RichTable.js - - - - -
      -
      - -
      Library: RichTable.js
      -
      -
      - Overview -
      -
      -
      -
      - -
      -
      -
      - -
      Constructors
      - - - - -
      Functions
      - - -
      -
      - - - - xq.RichTable.create(rdom, cols, rows, headerPositions) - -
      - - - - - - -
      parameters
      - - - - - - - - - - - - - - - - - - - - - - - - - - -
      - - - rdom - - -
      - - - cols - - -
      - - - rows - - -
      - - - headerPositions - - -
      - - - - - -
      - - - -
      Objects
      - - - - -
      -
      -
      - Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:49 GMT. -
      - - diff --git a/modules/editor/skins/xquared/doc/api/_12.html b/modules/editor/skins/xquared/doc/api/_12.html deleted file mode 100644 index 2d0bff85a..000000000 --- a/modules/editor/skins/xquared/doc/api/_12.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - JsDoc: Shortcut.js - - - - -
      -
      - -
      Library: Shortcut.js
      -
      -
      - Overview -
      -
      -
      -
      - -
      -
      -
      - -
      Constructors
      - - - - - - - - -
      Functions
      - - -
      -
      - - - - xq.Shortcut.interprete(expression) - -
      - - - - - - -
      parameters
      - - - - - - - - -
      - - - expression - - -
      - - - - - -
      - - - -
      -
      - - - - xq.Shortcut._interpreteModifier(expression, modifierName) - -
      - - - - - - -
      parameters
      - - - - - - - - - - - - - - -
      - - - expression - - -
      - - - modifierName - - -
      - - - - - -
      - - - -
      -
      - - - - xq.Shortcut._interpreteWhich(keyName) - -
      - - - - - - -
      parameters
      - - - - - - - - -
      - - - keyName - - -
      - - - - - -
      - - - -
      Objects
      - - - - - - - - - - -
      -
      -
      - Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:49 GMT. -
      - - diff --git a/modules/editor/skins/xquared/doc/api/_13.html b/modules/editor/skins/xquared/doc/api/_13.html deleted file mode 100644 index 46fe53499..000000000 --- a/modules/editor/skins/xquared/doc/api/_13.html +++ /dev/null @@ -1,153 +0,0 @@ - - - - - - JsDoc: Validator.js - - - - -
      -
      - -
      Library: Validator.js
      -
      -
      - Overview -
      -
      -
      -
      - -
      -
      -
      - -
      Constructors
      - - - - - - -
      Functions
      - - - - -
      -
      - - - - xq.Validator.createInstance(curUrl, urlValidationMode, allowedTags, allowedAttrs) - -
      - - -
      Creates and returns instance of browser specific implementation.
      - - - - - -
      parameters
      - - - - - - - - - - - - - - - - - - - - - - - - - - -
      - - - curUrl - - -
      - - - urlValidationMode - - -
      - - - allowedTags - - -
      - - - allowedAttrs - - -
      - - - - - -
      - - - -
      Objects
      - - -
      -
      - - - - - xq.Validator - -
      - - -
      Validates and invalidates designmode contents
      - - - - - -
      - - - - - - -
      -
      -
      - Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:49 GMT. -
      - - diff --git a/modules/editor/skins/xquared/doc/api/_14.html b/modules/editor/skins/xquared/doc/api/_14.html deleted file mode 100644 index 3a15872b4..000000000 --- a/modules/editor/skins/xquared/doc/api/_14.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - JsDoc: ValidatorGecko.js - - - - -
      -
      - -
      Library: ValidatorGecko.js
      -
      -
      - Overview -
      -
      -
      -
      - -
      -
      -
      - -
      Constructors
      - - - - -
      Functions
      - - - - -
      Objects
      - - -
      -
      - - - - - xq.ValidatorGecko - -
      - - -
      Validator for Gecko Engine
      - - - - - -
      - - - -
      -
      -
      - Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:49 GMT. -
      - - diff --git a/modules/editor/skins/xquared/doc/api/_15.html b/modules/editor/skins/xquared/doc/api/_15.html deleted file mode 100644 index ee41915a5..000000000 --- a/modules/editor/skins/xquared/doc/api/_15.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - JsDoc: ValidatorTrident.js - - - - -
      -
      - -
      Library: ValidatorTrident.js
      -
      -
      - Overview -
      -
      -
      -
      - -
      -
      -
      - -
      Constructors
      - - - - -
      Functions
      - - - - -
      Objects
      - - -
      -
      - - - - - xq.ValidatorTrident - -
      - - -
      Validator for Internet Explorer 6 and 7
      - - - - - -
      - - - -
      -
      -
      - Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:50 GMT. -
      - - diff --git a/modules/editor/skins/xquared/doc/api/_16.html b/modules/editor/skins/xquared/doc/api/_16.html deleted file mode 100644 index 5b7576800..000000000 --- a/modules/editor/skins/xquared/doc/api/_16.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - JsDoc: ValidatorW3.js - - - - -
      -
      - -
      Library: ValidatorW3.js
      -
      -
      - Overview -
      -
      -
      -
      - -
      -
      -
      - -
      Constructors
      - - - - -
      Functions
      - - - - -
      Objects
      - - -
      -
      - - - - - xq.ValidatorW3 - -
      - - -
      Validator for W3C Standard Engine
      - - - - - -
      - - - -
      -
      -
      - Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:50 GMT. -
      - - diff --git a/modules/editor/skins/xquared/doc/api/_17.html b/modules/editor/skins/xquared/doc/api/_17.html deleted file mode 100644 index b4e3818df..000000000 --- a/modules/editor/skins/xquared/doc/api/_17.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - JsDoc: ValidatorWebkit.js - - - - -
      -
      - -
      Library: ValidatorWebkit.js
      -
      -
      - Overview -
      -
      -
      -
      - -
      -
      -
      - -
      Constructors
      - - - - -
      Functions
      - - - - -
      Objects
      - - -
      -
      - - - - - xq.ValidatorWebkit - -
      - - -
      Validator for Webkit
      - - - - - -
      - - - -
      -
      -
      - Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:50 GMT. -
      - - diff --git a/modules/editor/skins/xquared/doc/api/_18.html b/modules/editor/skins/xquared/doc/api/_18.html deleted file mode 100644 index 88d060871..000000000 --- a/modules/editor/skins/xquared/doc/api/_18.html +++ /dev/null @@ -1,512 +0,0 @@ - - - - - - JsDoc: XQuared.js - - - - -
      -
      - -
      Library: XQuared.js
      -
      -
      - Overview -
      -
      -
      -
      - -
      -
      -
      - -
      Constructors
      - - - - - - - - - - - - - - - - - - - - - - - - - - -
      Functions
      - - - - -
      -
      - - - - xq.asEventSource(object, prefix, events) - -
      - - -
      Make given object as event source
      - - - - - -
      parameters
      - - - - - - - - - - - - - - - - - - - - -
      - Object - - object - - target object -
      - String - - prefix - - prefix for generated functions -
      - Array - - events - - array of string which contains name of events -
      - - - - - -
      - - - -
      -
      - - - Array.indexOf(n) - - -
      - - -
      Returns the index of given element
      - - - - - -
      parameters
      - - - - - - - - -
      - - - n - - -
      - - - -
      returns
      - - - - - - - -
      - Number - - index or -1 -
      - - - -
      - - - -
      -
      - - - - Date.pass(msec) - -
      - - - - - - -
      parameters
      - - - - - - - - -
      - - - msec - - -
      - - - - - -
      - - - -
      -
      - - - - Date.get() - -
      - - - - - - - - - - -
      - - - -
      -
      - - - Date.elapsed(msec) - - -
      - - - - - - -
      parameters
      - - - - - - - - -
      - - - msec - - -
      - - - - - -
      - - - -
      -
      - - - String.merge(data) - - -
      - - - - - - -
      parameters
      - - - - - - - - -
      - - - data - - -
      - - - - - -
      - - - -
      -
      - - - String.parseURL() - - -
      - - - - - - - - - - -
      - - - -
      -
      - - - - xq.findXquaredScript() - -
      - - - - - - - - - - -
      - - - -
      -
      - - - - xq.shouldLoadOthers() - -
      - - - - - - - - - - -
      - - - -
      -
      - - - - xq.loadScript(url) - -
      - - - - - - -
      parameters
      - - - - - - - - -
      - - - url - - -
      - - - - - -
      - - - -
      -
      - - - - xq.loadOthers() - -
      - - - - - - - - - - -
      - - - -
      Objects
      - - -
      -
      - - - - - xq - -
      - - -
      Namespace for entire Xquared classes
      - - - - - -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      -
      -
      - Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:50 GMT. -
      - - diff --git a/modules/editor/skins/xquared/doc/api/_19.html b/modules/editor/skins/xquared/doc/api/_19.html deleted file mode 100644 index 4616b926c..000000000 --- a/modules/editor/skins/xquared/doc/api/_19.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - JsDoc: _ui_templates.js - - - - -
      -
      - -
      Library: _ui_templates.js
      -
      -
      - Overview -
      -
      -
      -
      - -
      -
      -
      - -
      Constructors
      - - -
      Functions
      - - -
      Objects
      - -
      -
      -
      - Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:50 GMT. -
      - - diff --git a/modules/editor/skins/xquared/doc/api/constructor.gif b/modules/editor/skins/xquared/doc/api/constructor.gif deleted file mode 100644 index ba779972c2766b1dccbbc6e90f46fb9df4df374e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 363 zcmZ?wbhEHb6krfwxN6LB_{hP{n>VlBedfsd`xU)Q)~;Rk?c3K$OZU}G-u(CP-?lkB z_V3&K^6lsM@85m+@P6-!E8o9=zk2t@uV24DeE3k(wP?wb#ZMnUTCi~5mCKi_rfz-r z?(OO|D{Ch%-?ejF)zmFV4j;O5`O=#=uTGsjF?Zgq&!0aRb+4;!ZryU|`i|{eFI~Lw z=Jm_2p7xzPwtx8W?#bgv$BrCQ@M^zv=XOU|>;M1%8HfOiKUo+V7>pToKx#pLVqohy zFtflzM<{vI48sX3r$WvuZdTMj6?JuCjuQ8o3Gp*kq~j{njSjo9Z4}{2d@A5sl;Jct z<%`Da(?Oy}3~p{3MmnCHZafCPYOG4!)lNN3OdJLbMiP?@yNm@5_*q!k4HEVAo16@o pSVZJzIC&_@N3NBTR5f5OHWJ^?&c(IIl|i}LSiSdXi?btxH2^cNq~8Dl diff --git a/modules/editor/skins/xquared/doc/api/default.css b/modules/editor/skins/xquared/doc/api/default.css deleted file mode 100644 index cfe837beb..000000000 --- a/modules/editor/skins/xquared/doc/api/default.css +++ /dev/null @@ -1,116 +0,0 @@ -body,a -{ - color: #000; - font: 12px verdana; -} - -ul -{ - list-style-type: none; - margin-left: 10px; - padding-left: 10px; -} - -.content { } -.docs { } -.signature { font-weight: normal; } -.code { - font: 11px monaco,monospace; - padding: 4px; - margin-left: 18px; - border: 1px dashed #ccc; -} - -.itemTitle -{ - font-size: 12px; - font-weight: bold; - height: 16px; -} - -.item { } - -.sectionHead -{ - font-size: 18px; - font-weight: bold; - background-color: #C0C1DE; - color: #fff; - margin-top: 18px; - padding: 2px 4px 2px 4px; -} - -.section -{ - padding: 8px; - border: 1px #8A92BC solid; - margin: 4px; -} - -.detailHead -{ - border-bottom: 1px #8FB685 dotted; - font-size: 12px; - font-weight: bold; - color: #798E73; - margin-top: 18px; -} - -.desc { padding: 8px; } - -.fileHead -{ - background-image: url(file.gif); - background-repeat: no-repeat; - padding-left: 20px; - font-weight: bold; - font-size: 14px; - line-height: 20px; -} - -.overview .itemTitle -{ - background-image: url(overview.gif); - background-repeat: no-repeat; - padding-left: 20px; -} - -.constructor .itemTitle -{ - background-image: url(constructor.gif); - background-repeat: no-repeat; - padding-left: 20px; -} - -.function .itemTitle -{ - background-image: url(function.gif); - background-repeat: no-repeat; - padding-left: 20px; -} - -.object .itemTitle -{ - background-image: url(object.gif); - background-repeat: no-repeat; - padding-left: 20px; -} - -.type -{ - font-style: italic; - color: #999; - font-weight: normal; -} - -.itemTitle a.type { font-weight: bold; } - -.finePrint -{ - color: #878787; - font-family: verdana; - font-size: 10px; - text-align: right; -} - -.params td { padding-right: 10px; } \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/file.gif b/modules/editor/skins/xquared/doc/api/file.gif deleted file mode 100644 index 9c7446e41ef97d4b19d23b5a71f23beb27036206..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 242 zcmZ?wbhEHb6krfwI3mXI>eZ{GM~{B`^y%%}r#pA+|z#zt;15yIA zlYuoq!KpXJQf``SXwK_RA-lX79^9EE;uyLntiegaK+{je=KiT?CtfP`FIn?QL8|-2 zJ(2G+9*b_xfBdUL;=m~{J*HZddza=PSrK6H?qj6%z8CG`g6?JIwM_M*IeEMS0^Ce( WnfjCLIMk+zuxQSjJ!iHegEat^EN}e) diff --git a/modules/editor/skins/xquared/doc/api/file_list.html b/modules/editor/skins/xquared/doc/api/file_list.html deleted file mode 100644 index f6c3a20f5..000000000 --- a/modules/editor/skins/xquared/doc/api/file_list.html +++ /dev/null @@ -1,149 +0,0 @@ - - - - - JsDoc - - - - -
      File Index
      - - - \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/function.gif b/modules/editor/skins/xquared/doc/api/function.gif deleted file mode 100644 index be00b964ba12560f696afdb2dd6d01f89f8c109d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 224 zcmZ?wbhEHb6krfwI3mQ*KcV}~nbXr}PM$cqZ^y1JOP4R1JayvnQ-@csUOs=pytV7r z?A^a}(c%RM4(vN~_RPC?Z!TXy-_h0j|Nnmm;(+2$7DfgJAqE|ga*&-2tg#DJ`cg8z z0;{_GZrKG&&%Aiqh3AM1Z_K9&3j~U^w<@qSFl=Zz;;~X@fk1#niB_Pl28Rbz(*pnQ sW*&h?76xnSy&TO?55D|i+IC3kO4z-xw*m}Jn;O(LTeUm8v=tew0ga|o1^@s6 diff --git a/modules/editor/skins/xquared/doc/api/index.html b/modules/editor/skins/xquared/doc/api/index.html deleted file mode 100644 index 3df8e5bfc..000000000 --- a/modules/editor/skins/xquared/doc/api/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - JsDoc - - - - - - - \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/object.gif b/modules/editor/skins/xquared/doc/api/object.gif deleted file mode 100644 index 409b58e334dc59762dd2ccdb6b01f9312851872d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 585 zcmZ?wbhEHb6krfwcoxI(;rjXyS5~~gzV7&%#;J*XPcLnnoh3ahOYXzFN3JudZIx;(UEW$?R1Axp_)2j!#-qZG3fI z$=P)^cemGlxVm=Fyxa#zXMVW4`u^_bN2it_Sz0hFm2W~6%ZGC_4=*k}xw`t(^ULoq zFTb(1Zd$U?<9+R)pI=yzCGzOZ%Kj+k$?=@iQpL7U3Vm~S?whmoo^Q*#yCULvkMX5h zZvBx=|NsAIpchd5$->CM5W}DYvJey}4D8DqVw##;TAO&HJG;6&d1CmZRRaXLxmj6d z?UkG~qnY_-l!LgqG+fO5r7YF0LqyCyrCBz!u^Do58u-Zxv-{}kI4~YQtnVdn?Cim= zCuXbVCZR2^Aj!ukDrgey>dtWgJ_iTW6JB2LK<1v;UCc4jrjegMf3b>ginfXR{pYXB v_xH0BBt14H2sA_+Ihu#lxiagE0ujg4KRk_@#Ql2Z;%aCd5CV6X-NIMnZ- diff --git a/modules/editor/skins/xquared/doc/api/overview.gif b/modules/editor/skins/xquared/doc/api/overview.gif deleted file mode 100644 index 241c2574e50ec9d76119ca6729ae08d287c70e56..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 614 zcmZ?wbhEHb6krfwcvi%am=c$go|u#x|NZ;-^sJQZ+>Cwu_x}6$FDp0w(W6I&CHa{- z=^Hm~NJ>pOcKm2^TEgu+w;n!xc;N7!_wU~ULI1?w-FtRb)RaDX`namLe8Ieq4|y?gf-mE=#GHR<}TYaLx}KY#vg zYH3)%d38p1>V!%CyZ3K@`t<3v=~Es&ym#}?jYp3j9zAvN-u=6UrFoYwT|9r`+}(S3 z??1R(T~~ST+}Vp)fZRKO|Ngyn zy&YYB?aNjyy>{cu^XJbdPn}TPP<`~|p{dg+-@bGE>eVYbd6^e3oZqr_OIl`1VR7D^ zxwG23nk%ZyE?v2B?AX!u8`hPS7e0LSaMzxlTefV;%t>3cbY9=2?sMnQ*49_&7G~eR zb7RBCb*=5qa~I6MaPfRXa_s;A{~3q_ia%Kx85oKfbU?~Mal*iUxS^=2iM>FUD=1f~ zxu;0mM?BrkK!Z!Tw@EQp$T!MDH^Z-&Es0y+*~2^~JD9bXJHODr(7UP7sj!zZzRLcv07 z{#SB^3Njq-Y=vQry@f?bZZ@d$OjIhY`IG#FiHDJeF(jt*ahqemTS%Nif}=v;OhGk2 kiwu{8-BNmyCQ~METzZJnhgru(QE<6Kr-`EkD-(k?01Uk<1^@s6 diff --git a/modules/editor/skins/xquared/doc/api/splash.html b/modules/editor/skins/xquared/doc/api/splash.html deleted file mode 100644 index 8c7495195..000000000 --- a/modules/editor/skins/xquared/doc/api/splash.html +++ /dev/null @@ -1,7 +0,0 @@ - - - JsDoc - - - - \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_01.html b/modules/editor/skins/xquared/doc/api/src_01.html deleted file mode 100644 index 4d8272800..000000000 --- a/modules/editor/skins/xquared/doc/api/src_01.html +++ /dev/null @@ -1,24 +0,0 @@ -
        1 xq.Browser = {
      -  2 	// By Layout Engines
      -  3 	isTrident: navigator.appName == "Microsoft Internet Explorer",
      -  4 	isWebkit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
      -  5 	isGecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
      -  6 	isKHTML: navigator.userAgent.indexOf('KHTML') != -1,
      -  7 	isPresto: navigator.appName == "Opera",
      -  8 	
      -  9 	// By Platforms
      - 10 	isMac: navigator.userAgent.indexOf("Macintosh") != -1,
      - 11 	isUbuntu: navigator.userAgent.indexOf('Ubuntu') != -1,
      - 12 
      - 13 	// By Browsers
      - 14 	isIE: navigator.appName == "Microsoft Internet Explorer",
      - 15 	isIE6: navigator.userAgent.indexOf('MSIE 6') != -1,
      - 16 	isIE7: navigator.userAgent.indexOf('MSIE 7') != -1
      - 17 };
      \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_02.html b/modules/editor/skins/xquared/doc/api/src_02.html deleted file mode 100644 index 7d1de91f7..000000000 --- a/modules/editor/skins/xquared/doc/api/src_02.html +++ /dev/null @@ -1,344 +0,0 @@ -
        1 /**
      -  2  * @fileOverview xq.controls provides common UI elements such as dialog.
      -  3  */
      -  4 xq.controls = {};
      -  5 
      -  6 
      -  7 
      -  8 xq.controls.FormDialog = Class.create({
      -  9 	/**
      - 10      * @constructor
      - 11      *
      - 12      * @param {String} html HTML string which contains FORM
      - 13      * @param {Function} [onLoadHandler] callback function to be called when the form is loaded
      - 14 	 */
      - 15 	initialize: function(xed, html, onLoadHandler, onCloseHandler) {
      - 16 		this.xed = xed;
      - 17 		this.html = html;
      - 18 		this.onLoadHandler = onLoadHandler || function() {};
      - 19 		this.onCloseHandler = onCloseHandler || function() {};
      - 20 		this.form = null;
      - 21 	},
      - 22 	/**
      - 23 	 * Show dialog
      - 24 	 *
      - 25 	 * @param {Object} [options] collection of options
      - 26 	 */
      - 27 	show: function(options) {
      - 28 		options = options || {};
      - 29 		options.position = options.position || 'centerOfWindow';
      - 30 		options.mode = options.mode || 'modal';
      - 31 		options.cancelOnEsc = options.cancelOnEsc || true;
      - 32 		
      - 33 		var self = this;
      - 34 		
      - 35 		// create and append container
      - 36 		var container = $(document.createElement('DIV'));
      - 37 		container.style.display = 'none';
      - 38 		document.body.appendChild(container);
      - 39 		
      - 40 		// initialize form
      - 41 		container.innerHTML = this.html;
      - 42 		this.form = $(container.getElementsByTagName('FORM')[0]);
      - 43 		
      - 44 		this.form.onsubmit = function() {
      - 45 			self.onCloseHandler($(this).serialize(true));
      - 46 			self.close();
      - 47 			return false;
      - 48 		};
      - 49 		
      - 50 		var cancelButton = this.form.getElementsByClassName('cancel')[0];
      - 51 		cancelButton.onclick = function() {
      - 52 			self.onCloseHandler();
      - 53 			self.close();
      - 54 		};
      - 55 		
      - 56 		// append dialog
      - 57 		document.body.appendChild(this.form);
      - 58 		container.parentNode.removeChild(container);
      - 59 		
      - 60 		// place dialog to center of window
      - 61 		this.setPosition(options.position);
      - 62 		
      - 63 		// give focus
      - 64 		var elementToFocus = this.form.getElementsByClassName('initialFocus');
      - 65 		if(elementToFocus.length > 0) elementToFocus[0].focus();
      - 66 		
      - 67 		// handle cancelOnEsc option
      - 68 		if(options.cancelOnEsc) {
      - 69 			Event.observe(this.form, 'keydown', function(e) {
      - 70 				if(e.keyCode == 27) {
      - 71 					this.onCloseHandler();
      - 72 					this.close();
      - 73 				}
      - 74 				return false;
      - 75 			}.bind(this));
      - 76 		}
      - 77 		
      - 78 		this.onLoadHandler(this);
      - 79 	},
      - 80 	close: function() {
      - 81 		this.form.parentNode.removeChild(this.form);
      - 82 	},
      - 83 	setPosition: function(target) {
      - 84 		var targetElement;
      - 85 		
      - 86 		if(target == 'centerOfWindow') {
      - 87 			targetElement = document.documentElement;
      - 88 		} else if(target == 'centerOfEditor') {
      - 89 			targetElement = this.xed.getDoc()[xq.Browser.isTrident ? "body" : "documentElement"];
      - 90 		} else if(target == 'nearbyCaret') {
      - 91 			throw "Not implemented yet";
      - 92 		} else {
      - 93 			throw "Invalid argument: " + target;
      - 94 		}
      - 95 		
      - 96 		var targetWidth = targetElement.clientWidth;
      - 97 		var targetHeight = targetElement.clientHeight;
      - 98 		var dialogWidth = this.form.clientWidth;
      - 99 		var dialogHeight = this.form.clientHeight;
      -100 		
      -101 		var x = parseInt((targetWidth - dialogWidth) / 2);
      -102 		var y = parseInt((targetHeight - dialogHeight) / 2);
      -103 		
      -104 		this.form.style.left = x + "px";
      -105 		this.form.style.top = y + "px";
      -106 	}
      -107 })
      -108 
      -109 
      -110 
      -111 xq.controls.QuickSearchDialog = Class.create({
      -112 	/**
      -113      * @constructor
      -114 	 */
      -115 	initialize: function(xed, param) {
      -116 		this.xed = xed;
      -117 		
      -118 		this.rdom = xq.RichDom.createInstance();
      -119 		this.rdom.setRoot(document.body);
      -120 		
      -121 		this.param = param;
      -122 		if(!this.param.renderItem) this.param.renderItem = function(item) {
      -123 			return this.rdom.getInnerText(item);
      -124 		}.bind(this);
      -125 		
      -126 		this.container = null;
      -127 	},
      -128 	
      -129 	getQuery: function() {
      -130 		if(!this.container) return "";
      -131 		return this._getInputField().value;
      -132 	},
      -133 	
      -134 	onSubmit: function(e) {
      -135 		if(this.matchCount() > 0) {
      -136 			this.param.onSelect(this.xed, this.list[this._getSelectedIndex()]);
      -137 		}
      -138 		
      -139 		this.close();
      -140 		Event.stop(e);
      -141 		return false;
      -142 	},
      -143 	
      -144 	onCancel: function(e) {
      -145 		if(this.param.onCancel) this.param.onCancel(this.xed);
      -146 		this.close();
      -147 	},
      -148 	
      -149 	onBlur: function(e) {
      -150 		// TODO: Ugly
      -151 		setTimeout(function() {this.onCancel(e)}.bind(this), 400);
      -152 	},
      -153 	
      -154 	onKey: function(e) {
      -155 		var esc = new xq.Shortcut("ESC");
      -156 		var enter = new xq.Shortcut("ENTER");
      -157 		var up = new xq.Shortcut("UP");
      -158 		var down = new xq.Shortcut("DOWN");
      -159 		
      -160 		if(esc.matches(e)) {
      -161 			this.onCancel(e);
      -162 		} else if(enter.matches(e)) {
      -163 			this.onSubmit(e);
      -164 		} else if(up.matches(e)) {
      -165 			this._moveSelectionUp();
      -166 		} else if(down.matches(e)) {
      -167 			this._moveSelectionDown();
      -168 		} else {
      -169 			this.updateList();
      -170 		}
      -171 	},
      -172 	
      -173 	onClick: function(e) {
      -174 		var target = e.srcElement || e.target;
      -175 		if(target.nodeName == "LI") {
      -176 			
      -177 			var index = this._getIndexOfLI(target);
      -178 			this.param.onSelect(this.xed, this.list[index]);
      -179 		}
      -180 	},
      -181 	
      -182 	onList: function(list) {
      -183 		this.list = list;
      -184 		this.renderList(list);
      -185 	},
      -186 	
      -187 	updateList: function() {
      -188 		window.setTimeout(function() {
      -189 			this.param.listProvider(this.getQuery(), this.xed, this.onList.bind(this));
      -190 		}.bind(this), 0);
      -191 	},
      -192 	
      -193 	renderList: function(list) 
      -194 	{
      -195 		var ol = this._getListContainer();
      -196 		ol.innerHTML = "";
      -197 		
      -198 		for(var i = 0; i < list.length; i++) {
      -199 			var li = this.rdom.createElement('LI');
      -200 			li.innerHTML = this.param.renderItem(list[i]);
      -201 			ol.appendChild(li);
      -202 		}
      -203 		
      -204 		if(ol.hasChildNodes()) {
      -205 			ol.firstChild.className = "selected";
      -206 		}
      -207 	},
      -208 	
      -209 	show: function() {
      -210 		if(!this.container) this.container = this._create();
      -211 		
      -212 		var dialog = this.rdom.insertNodeAt(this.container, this.rdom.getRoot(), "end");
      -213 		this.setPosition('centerOfEditor');
      -214 		this.updateList();
      -215 		this.focus();
      -216 	},
      -217 	
      -218 	close: function() {
      -219 		this.rdom.deleteNode(this.container);
      -220 	},
      -221 	
      -222 	focus: function() {
      -223 		this._getInputField().focus();
      -224 	},
      -225 	
      -226 	setPosition: function(target) {
      -227 		var targetElement;
      -228 		
      -229 		if(target == 'centerOfWindow') {
      -230 			targetElement = document.documentElement;
      -231 		} else if(target == 'centerOfEditor') {
      -232 			targetElement = this.xed.getDoc().documentElement;
      -233 		} else if(target == 'nearbyCaret') {
      -234 			throw "Not implemented yet";
      -235 		} else {
      -236 			throw "Invalid argument: " + target;
      -237 		}
      -238 		
      -239 		var targetWidth = targetElement.clientWidth;
      -240 		var targetHeight = targetElement.clientHeight;
      -241 		var dialogWidth = this.container.clientWidth;
      -242 		var dialogHeight = this.container.clientHeight;
      -243 		
      -244 		var x = parseInt((targetWidth - dialogWidth) / 2);
      -245 		var y = parseInt((targetHeight - dialogHeight) / 2);
      -246 		this.container.style.left = x + "px";
      -247 		this.container.style.top = y + "px";
      -248 	},
      -249 	
      -250 	matchCount: function() {
      -251 		return this.list ? this.list.length : 0;
      -252 	},
      -253 	
      -254 	_create: function() {
      -255 		// make container
      -256 		var container = this.rdom.createElement("DIV");
      -257 		container.className = "xqQuickSearch";
      -258 		
      -259 		// make title
      -260 		if(this.param.title) {
      -261 			var title = this.rdom.createElement("H1");
      -262 			title.innerHTML = this.param.title;
      -263 			container.appendChild(title);
      -264 		}
      -265 		
      -266 		// make input field
      -267 		var inputWrapper = this.rdom.createElement("DIV");
      -268 		inputWrapper.className = "input";
      -269 		var form = this.rdom.createElement("FORM");
      -270 		var input = this.rdom.createElement("INPUT");
      -271 		input.type = "text";
      -272 		input.value = "";
      -273     	form.appendChild(input);
      -274 		inputWrapper.appendChild(form);
      -275 		container.appendChild(inputWrapper);
      -276 		
      -277 		// make list
      -278 		var list = this.rdom.createElement("OL");
      -279 
      -280 	    Event.observe(input, 'blur', this.onBlur.bindAsEventListener(this));
      -281     	Event.observe(input, 'keypress', this.onKey.bindAsEventListener(this));
      -282     	Event.observe(list, 'click', this.onClick.bindAsEventListener(this), true);
      -283     	Event.observe(form, 'submit', this.onSubmit.bindAsEventListener(this));
      -284     	Event.observe(form, 'reset', this.onCancel.bindAsEventListener(this));
      -285 
      -286 		container.appendChild(list);
      -287 		return container;
      -288 	},
      -289 	
      -290 	_getInputField: function() {
      -291 		return this.container.getElementsByTagName('INPUT')[0];
      -292 	},
      -293 	
      -294 	_getListContainer: function() {
      -295 		return this.container.getElementsByTagName('OL')[0];
      -296 	},
      -297 	
      -298 	_getSelectedIndex: function() {
      -299 		var ol = this._getListContainer();
      -300 		for(var i = 0; i < ol.childNodes.length; i++) {
      -301 			if(ol.childNodes[i].className == 'selected') return i;
      -302 		}
      -303 	},
      -304 	
      -305 	_getIndexOfLI: function(li) {
      -306 		var ol = this._getListContainer();
      -307 		for(var i = 0; i < ol.childNodes.length; i++) {
      -308 			if(ol.childNodes[i] == li) return i;
      -309 		}
      -310 	},
      -311 	
      -312 	_moveSelectionUp: function() {
      -313 		var count = this.matchCount();
      -314 		if(count == 0) return;
      -315 		var index = this._getSelectedIndex();
      -316 		var ol = this._getListContainer();
      -317 		ol.childNodes[index].className = "";
      -318 		
      -319 		index--;
      -320 		if(index < 0) index = count - 1;
      -321 
      -322 		ol.childNodes[index].className = "selected";
      -323 	},
      -324 	
      -325 	_moveSelectionDown: function() {
      -326 		var count = this.matchCount();
      -327 		if(count == 0) return;
      -328 		var index = this._getSelectedIndex();
      -329 		var ol = this._getListContainer();
      -330 		ol.childNodes[index].className = "";
      -331 
      -332 		index++;
      -333 		if(index >= count) index = 0;
      -334 		
      -335 		ol.childNodes[index].className = "selected";
      -336 	}
      -337 });
      \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_03.html b/modules/editor/skins/xquared/doc/api/src_03.html deleted file mode 100644 index 076de09f1..000000000 --- a/modules/editor/skins/xquared/doc/api/src_03.html +++ /dev/null @@ -1,325 +0,0 @@ -
        1 /**
      -  2  * Provide various tree operations.
      -  3  *
      -  4  * TODO: Add specs
      -  5  */
      -  6 xq.DomTree = Class.create({
      -  7 	initialize: function() {
      -  8 		this._blockTags = ["DIV", "DD", "LI", "ADDRESS", "CAPTION", "DT", "H1", "H2", "H3", "H4", "H5", "H6", "HR", "P", "BODY", "BLOCKQUOTE", "PRE", "PARAM", "DL", "OL", "UL", "TABLE", "THEAD", "TBODY", "TR", "TH", "TD"];
      -  9 		this._blockContainerTags = ["DIV", "DD", "LI", "BODY", "BLOCKQUOTE", "UL", "OL", "DL", "TABLE", "THEAD", "TBODY", "TR", "TH", "TD"];
      - 10 		this._listContainerTags = ["OL", "UL", "DL"];
      - 11 		this._tableCellTags = ["TH", "TD"];
      - 12 		this._blockOnlyContainerTags = ["BODY", "BLOCKQUOTE", "UL", "OL", "DL", "TABLE", "THEAD", "TBODY", "TR"];
      - 13 		this._atomicTags = ["IMG", "OBJECT", "BR", "HR"];
      - 14 	},
      - 15 	
      - 16 	getBlockTags: function() {
      - 17 		return this._blockTags;
      - 18 	},
      - 19 	
      - 20 	/**
      - 21 	 * Find common ancestor(parent) and his immediate children(left and right).
      - 22 	 *
      - 23 	 * A --- B -+- C -+- D -+- E
      - 24 	 *          |
      - 25 	 *          +- F -+- G
      - 26 	 *
      - 27 	 * For example:
      - 28 	 * > findCommonAncestorAndImmediateChildrenOf("E", "G")
      - 29 	 *
      - 30 	 * will return
      - 31 	 *
      - 32 	 * > {parent:"B", left:"C", right:"F"}
      - 33 	 */
      - 34 	findCommonAncestorAndImmediateChildrenOf: function(left, right) {
      - 35 		if(left.parentNode == right.parentNode) {
      - 36 			return {
      - 37 				left:left,
      - 38 				right:right,
      - 39 				parent:left.parentNode
      - 40 			};
      - 41 		} else {
      - 42 			var parentsOfLeft = this.collectParentsOf(left, true);
      - 43 			var parentsOfRight = this.collectParentsOf(right, true);
      - 44 			var ca = this.getCommonAncestor(parentsOfLeft, parentsOfRight);
      - 45 	
      - 46 			var leftAncestor = parentsOfLeft.find(function(node) {return node.parentNode == ca});
      - 47 			var rightAncestor = parentsOfRight.find(function(node) {return node.parentNode == ca});
      - 48 			
      - 49 			return {
      - 50 				left:leftAncestor,
      - 51 				right:rightAncestor,
      - 52 				parent:ca
      - 53 			};
      - 54 		}
      - 55 	},
      - 56 	
      - 57 	/**
      - 58 	 * Find leaves at edge.
      - 59 	 *
      - 60 	 * A --- B -+- C -+- D -+- E
      - 61 	 *          |
      - 62 	 *          +- F -+- G
      - 63 	 *
      - 64 	 * For example:
      - 65 	 * > getLeavesAtEdge("A")
      - 66 	 *
      - 67 	 * will return
      - 68 	 *
      - 69 	 * > ["E", "G"]
      - 70 	 */
      - 71 	getLeavesAtEdge: function(element) {
      - 72 		if(!element.hasChildNodes()) return [null, null];
      - 73 		
      - 74 		var findLeft = function(el) {
      - 75 			for (var i = 0; i < el.childNodes.length; i++) {
      - 76 				if (el.childNodes[i].nodeType == 1 && this.isBlock(el.childNodes[i])) return findLeft(el.childNodes[i]);
      - 77 			}
      - 78 			return el;
      - 79 		}.bind(this);
      - 80 		
      - 81 		var findRight=function(el) {
      - 82 			for (var i = el.childNodes.length; i--;) {
      - 83 				if (el.childNodes[i].nodeType == 1 && this.isBlock(el.childNodes[i])) return findRight(el.childNodes[i]);
      - 84 			}
      - 85 			return el;
      - 86 		}.bind(this);
      - 87 		
      - 88 		var left = findLeft(element);
      - 89 		var right = findRight(element);
      - 90 		return [left == element ? null : left, right == element ? null : right];
      - 91 	},
      - 92 	
      - 93 	getCommonAncestor: function(parents1, parents2) {
      - 94 		for(var i = 0; i < parents1.length; i++) {
      - 95 			for(var j = 0; j < parents2.length; j++) {
      - 96 				if(parents1[i] == parents2[j]) return parents1[i];
      - 97 			}
      - 98 		}
      - 99 	},
      -100 	
      -101 	collectParentsOf: function(node, includeSelf, exitCondition) {
      -102 		var parents = [];
      -103 		if(includeSelf) parents.push(node);
      -104 		
      -105 		while((node = node.parentNode) && (node.nodeName != "HTML") && !(typeof exitCondition == "function" && exitCondition(node))) parents.push(node);
      -106 		return parents;
      -107 	},
      -108 	
      -109 	isDescendantOf: function(parent, child) {
      -110 		if(parent.length > 0) {
      -111 			for(var i = 0; i < parent.length; i++) {
      -112 				if(this.isDescendantOf(parent[i], child)) return true;
      -113 			}
      -114 			return false;
      -115 		}
      -116 		
      -117 		if(parent == child) return false;
      -118 		
      -119 	    while (child = child.parentNode)
      -120 	      if (child == parent) return true;
      -121 	    return false;
      -122 	},
      -123 	
      -124 	/**
      -125 	 * Perform tree walking (foreward)
      -126 	 */
      -127 	walkForward: function(node) {
      -128 		if(node.hasChildNodes()) return node.firstChild;
      -129 		if(node.nextSibling) return node.nextSibling;
      -130 		
      -131 		while(node = node.parentNode) {
      -132 			if(node.nextSibling) return node.nextSibling;
      -133 		}
      -134 		
      -135 		return null;
      -136 	},
      -137 	
      -138 	/**
      -139 	 * Perform tree walking (backward)
      -140 	 */
      -141 	walkBackward: function(node) {
      -142 		if(node.previousSibling) {
      -143 			node = node.previousSibling;
      -144 			while(node.hasChildNodes()) {node = node.lastChild;}
      -145 			return node;
      -146 		}
      -147 		
      -148 		return node.parentNode;
      -149 	},
      -150 	
      -151 	/**
      -152 	 * Perform tree walking (to next siblings)
      -153 	 */
      -154 	walkNext: function(node) {return node.nextSibling},
      -155 	
      -156 	/**
      -157 	 * Perform tree walking (to next siblings)
      -158 	 */
      -159 	walkPrev: function(node) {return node.previousSibling},
      -160 	
      -161 	/**
      -162 	 * Returns true if target is followed by start
      -163 	 */
      -164 	checkTargetForward: function(start, target) {
      -165 		return this._check(start, this.walkForward, target);
      -166 	},
      -167 
      -168 	/**
      -169 	 * Returns true if start is followed by target
      -170 	 */
      -171 	checkTargetBackward: function(start, target) {
      -172 		return this._check(start, this.walkBackward, target);
      -173 	},
      -174 	
      -175 	findForward: function(start, condition, exitCondition) {
      -176 		return this._find(start, this.walkForward, condition, exitCondition);
      -177 	},
      -178 	
      -179 	findBackward: function(start, condition, exitCondition) {
      -180 		return this._find(start, this.walkBackward, condition, exitCondition);
      -181 	},
      -182 	
      -183 	/** @private */
      -184 	_check: function(start, direction, target) {
      -185 		if(start == target) return false;
      -186 		
      -187 		while(start = direction(start)) {
      -188 			if(start == target) return true;
      -189 		}
      -190 		return false;
      -191 	},
      -192 	
      -193 	/** @private */
      -194 	_find: function(start, direction, condition, exitCondition) {
      -195 		while(start = direction(start)) {
      -196 			if(exitCondition && exitCondition(start)) return null;
      -197 			if(condition(start)) return start;
      -198 		}
      -199 		return null;
      -200 	},
      -201 
      -202 	/**
      -203 	 * Walks Forward through DOM tree from start to end, and collects all nodes that matches with a filter.
      -204 	 * If no filter provided, it just collects all nodes.
      -205 	 *
      -206 	 * @param function filter a filter function
      -207 	 */
      -208 	collectNodesBetween: function(start, end, filter) {
      -209 		if(start == end) return [start, end].findAll(filter || function() {return true});
      -210 		
      -211 		var nodes = this.collectForward(start, function(node) {return node == end}, filter);
      -212 		if(
      -213 			start != end &&
      -214 			typeof filter == "function" &&
      -215 			filter(end)
      -216 		) nodes.push(end);
      -217 		
      -218 		return nodes;
      -219 	},
      -220 
      -221 	collectForward: function(start, exitCondition, filter) {
      -222 		return this.collect(start, this.walkForward, exitCondition, filter);
      -223 	},
      -224 	
      -225 	collectBackward: function(start, exitCondition, filter) {
      -226 		return this.collect(start, this.walkBackward, exitCondition, filter);
      -227 	},
      -228 	
      -229 	collectNext: function(start, exitCondition, filter) {
      -230 		return this.collect(start, this.walkNext, exitCondition, filter);
      -231 	},
      -232 	
      -233 	collectPrev: function(start, exitCondition, filter) {
      -234 		return this.collect(start, this.walkPrev, exitCondition, filter);
      -235 	},
      -236 	
      -237 	collect: function(start, next, exitCondition, filter) {
      -238 		var nodes = [start];
      -239 
      -240 		while(true) {
      -241 			start = next(start);
      -242 			if(
      -243 				(start == null) ||
      -244 				(typeof exitCondition == "function" && exitCondition(start))
      -245 			) break;
      -246 			
      -247 			nodes.push(start);
      -248 		}
      -249 
      -250 		return (typeof filter == "function") ? nodes.findAll(filter) : nodes;
      -251 	},
      -252 
      -253 
      -254 	hasBlocks: function(element) {
      -255 		var nodes = element.childNodes;
      -256 		for(var i = 0; i < nodes.length; i++) {
      -257 			if(this.isBlock(nodes[i])) return true;
      -258 		}
      -259 		return false;
      -260 	},
      -261 	
      -262 	hasMixedContents: function(element) {
      -263 		if(!this.isBlock(element)) return false;
      -264 		if(!this.isBlockContainer(element)) return false;
      -265 		
      -266 		var hasTextOrInline = false;
      -267 		var hasBlock = false;
      -268 		for(var i = 0; i < element.childNodes.length; i++) {
      -269 			var node = element.childNodes[i];
      -270 			if(!hasTextOrInline && this.isTextOrInlineNode(node)) hasTextOrInline = true;
      -271 			if(!hasBlock && this.isBlock(node)) hasBlock = true;
      -272 			
      -273 			if(hasTextOrInline && hasBlock) break;
      -274 		}
      -275 		if(!hasTextOrInline || !hasBlock) return false;
      -276 		
      -277 		return true;
      -278 	},
      -279 	
      -280 	isBlockOnlyContainer: function(element) {
      -281 		if(!element) return false;
      -282 		return this._blockOnlyContainerTags.include(typeof element == 'string' ? element : element.nodeName);
      -283 	},
      -284 	
      -285 	isTableCell: function(element) {
      -286 		if(!element) return false;
      -287 		return this._tableCellTags.include(typeof element == 'string' ? element : element.nodeName);
      -288 	},
      -289 	
      -290 	isBlockContainer: function(element) {
      -291 		if(!element) return false;
      -292 		return this._blockContainerTags.include(typeof element == 'string' ? element : element.nodeName);
      -293 	},
      -294 	
      -295 	isHeading: function(element) {
      -296 		if(!element) return false;
      -297 		return (typeof element == 'string' ? element : element.nodeName).match(/H\d/);
      -298 	},
      -299 	
      -300 	isBlock: function(element) {
      -301 		if(!element) return false;
      -302 		return this._blockTags.include(typeof element == 'string' ? element : element.nodeName);
      -303 	},
      -304 	
      -305 	isAtomic: function(element) {
      -306 		if(!element) return false;
      -307 		return this._atomicTags.include(typeof element == 'string' ? element : element.nodeName);
      -308 	},
      -309 	
      -310 	isListContainer: function(element) {
      -311 		if(!element) return false;
      -312 		return this._listContainerTags.include(typeof element == 'string' ? element : element.nodeName);
      -313 	},
      -314 	
      -315 	isTextOrInlineNode: function(node) {
      -316 		return node && (node.nodeType == 3 || !this.isBlock(node));
      -317 	}
      -318 });
      \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_04.html b/modules/editor/skins/xquared/doc/api/src_04.html deleted file mode 100644 index 50db4821a..000000000 --- a/modules/editor/skins/xquared/doc/api/src_04.html +++ /dev/null @@ -1,163 +0,0 @@ -
        1 /**
      -  2  * @fileOverview xq.EditHistory manages editing history and performs UNDO/REDO.
      -  3  */
      -  4 xq.EditHistory = Class.create({
      -  5     /**
      -  6 	 * Initializer
      -  7 	 *
      -  8      * @constructor
      -  9 	 * @param {xq.RichDom} rdom RichDom instance
      - 10 	 * @param {Number} [max] maximum UNDO buffer size(default value is 100).
      - 11 	 */
      - 12 	initialize: function(rdom, max) {
      - 13 		if (!rdom) throw "IllegalArgumentException";
      - 14 
      - 15 		this.disabled = false;
      - 16 		this.max = max || 100;
      - 17 		this.rdom = rdom;
      - 18 		this.root = rdom.getRoot();
      - 19 		this.clear();
      - 20 		
      - 21 		this.lastModified = Date.get();
      - 22 	},
      - 23 	getLastModifiedDate: function() {
      - 24 		return this.lastModified;
      - 25 	},
      - 26 	isUndoable: function() {
      - 27 		return this.queue.length > 0 && this.index > 0;
      - 28 	},
      - 29 	isRedoable: function() {
      - 30 		return this.queue.length > 0 && this.index < this.queue.length - 1;
      - 31 	},
      - 32 	disable: function() {
      - 33 		this.disabled = true;
      - 34 	},
      - 35 	enable: function() {
      - 36 		this.disabled = false;
      - 37 	},
      - 38 	undo: function() {
      - 39 		this.pushContent();
      - 40 		
      - 41 		if (this.isUndoable()) {
      - 42 			this.index--;
      - 43 			this.popContent();
      - 44 			return true;
      - 45 		} else {
      - 46 			return false;
      - 47 		}
      - 48 	},
      - 49 	redo: function() {
      - 50 		if (this.isRedoable()) {
      - 51 			this.index++;
      - 52 			this.popContent();
      - 53 			return true;
      - 54 		} else {
      - 55 			return false;
      - 56 		}
      - 57 	},
      - 58 	onCommand: function() {
      - 59 		this.lastModified = Date.get();
      - 60 		if(this.disabled) return false;
      - 61 
      - 62 		return this.pushContent();
      - 63 	},
      - 64 	onEvent: function(event) {
      - 65 		this.lastModified = Date.get();
      - 66 		if(this.disabled) return false;
      - 67 
      - 68 		// ignore normal keys
      - 69 		if('keydown' == event.type && !(event.ctrlKey || event.metaKey)) return false;
      - 70 		if(['keydown', 'keyup', 'keypress'].include(event.type) && !event.ctrlKey && !event.altKey && !event.metaKey && ![33,34,35,36,37,38,39,40].include(event.keyCode)) return false;
      - 71 		if(['keydown', 'keyup', 'keypress'].include(event.type) && (event.ctrlKey || event.metaKey) && [89,90].include(event.keyCode)) return false;
      - 72 		
      - 73 		// ignore ctrl/shift/alt/meta keys
      - 74 		if([16,17,18,224].include(event.keyCode)) return false;
      - 75 		
      - 76 		return this.pushContent();
      - 77 	},
      - 78 	popContent: function() {
      - 79 		this.lastModified = Date.get();
      - 80 		var entry = this.queue[this.index];
      - 81 		if (entry.caret > 0) {
      - 82 			var html=entry.html.substring(0, entry.caret) + '<span id="caret_marker_00700"></span>' + entry.html.substring(entry.caret);
      - 83 			this.root.innerHTML = html;
      - 84 		} else {
      - 85 			this.root.innerHTML = entry.html;
      - 86 		}
      - 87 		this.restoreCaret();
      - 88 	},
      - 89 	pushContent: function(ignoreCaret) {
      - 90 		if(xq.Browser.isTrident && !ignoreCaret && !this.rdom.hasFocus()) return false;
      - 91 		if(!this.rdom.getCurrentElement()) return false;
      - 92 		
      - 93 		var html = this.root.innerHTML;
      - 94 		if(html == (this.queue[this.index] ? this.queue[this.index].html : null)) return false;
      - 95 		var caret = ignoreCaret ? -1 : this.saveCaret();
      - 96 		
      - 97 		if(this.queue.length >= this.max) {
      - 98 			this.queue.shift();
      - 99 		} else {
      -100 			this.index++;
      -101 		}
      -102 		
      -103 		this.queue.splice(this.index, this.queue.length - this.index, {html:html, caret:caret});
      -104 		return true;
      -105 	},
      -106 	clear: function() {
      -107 		this.index = -1;
      -108 		this.queue = [];
      -109 		this.pushContent(true);
      -110 	},
      -111 	saveCaret: function() {
      -112 		if(this.rdom.hasSelection()) return null;
      -113 
      -114 		// FF on Mac has a caret problem with these lines. --2007/11/19
      -115 		var marker = this.rdom.pushMarker();
      -116 		var str = xq.Browser.isTrident ? '<SPAN class='+marker.className : '<span class="'+marker.className+'"';
      -117 		var caret = this.rdom.getRoot().innerHTML.indexOf(str);
      -118 		this.rdom.popMarker(true);
      -119 
      -120 		return caret;
      -121 
      -122 /*
      -123 		// This is old code. It also has same problem.
      -124 		
      -125 		if(this.rdom.hasSelection()) return null;
      -126 		
      -127 		var bookmark = this.rdom.saveSelection();
      -128 		var marker = this.rdom.pushMarker();
      -129 		
      -130 		var str = xq.Browser.isTrident ? '<SPAN class='+marker.className : '<span class="'+marker.className+'"';
      -131 		var caret = this.rdom.getRoot().innerHTML.indexOf(str);
      -132 		
      -133 		this.rdom.popMarker();
      -134 		this.rdom.restoreSelection(bookmark);
      -135 		
      -136 		return caret;
      -137 */
      -138 	},
      -139 	restoreCaret: function() {
      -140 		var marker = this.rdom.$('caret_marker_00700');
      -141 		
      -142 		if(marker) {
      -143 			this.rdom.selectElement(marker, true);
      -144 			this.rdom.collapseSelection(false);
      -145 			this.rdom.deleteNode(marker);
      -146 		} else {
      -147 			var node = this.rdom.tree.findForward(this.rdom.getRoot(), function(node) {
      -148 				return this.isBlock(node) && !this.hasBlocks(node);
      -149 			}.bind(this.rdom.tree));
      -150 			this.rdom.selectElement(node, false);
      -151 			this.rdom.collapseSelection(false);
      -152 			
      -153 		}
      -154 	}
      -155 });
      -156 
      \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_05.html b/modules/editor/skins/xquared/doc/api/src_05.html deleted file mode 100644 index c8bbff96a..000000000 --- a/modules/editor/skins/xquared/doc/api/src_05.html +++ /dev/null @@ -1,2216 +0,0 @@ -
        1 /**
      -  2  * @fileOverview xq.Editor manages configurations such as autocompletion and autocorrection, edit mode/normal mode switching, handles editing commands, keyboard shortcuts and other events.
      -  3  */
      -  4 xq.Editor = Class.create({
      -  5 	/**
      -  6 	 * Initialize editor but it doesn't automatically start designMode. setEditMode should be called after initialization.
      -  7 	 *
      -  8      * @constructor
      -  9 	 * @param {Element} contentElement HTML element(TEXTAREA or normal block element such as DIV) to be replaced with editable area
      - 10 	 * @param {Element} toolbarContainer HTML element which contains toolbar icons
      - 11 	 */
      - 12 	initialize: function(contentElement, toolbarContainer) {
      - 13 		if(!contentElement) throw "[contentElement] is null";
      - 14 		if(contentElement.nodeType != 1) throw "[contentElement] is not an element";
      - 15 		
      - 16 		xq.asEventSource(this, "Editor", ["ElementChanged", "BeforeEvent", "AfterEvent", "CurrentContentChanged", "StaticContentChanged", "CurrentEditModeChanged"]);
      - 17 		
      - 18 		/**
      - 19 		 * Editor's configuration
      - 20 		 * @type object
      - 21 		 */
      - 22 		this.config = {};
      - 23 		this.config.enableLinkClick = false;
      - 24 		this.config.changeCursorOnLink = false;
      - 25 		this.config.generateDefaultToolbar = true;
      - 26 		this.config.defaultToolbarButtonMap = [
      - 27 			[
      - 28 				{className:"foregroundColor", title:"Foreground color", handler:"xed.handleForegroundColor()"},
      - 29 				{className:"backgroundColor", title:"Background color", handler:"xed.handleBackgroundColor()"}
      - 30 			],
      - 31 			[
      - 32 				{className:"link", title:"Link", handler:"xed.handleLink()"},
      - 33 				{className:"strongEmphasis", title:"Strong emphasis", handler:"xed.handleStrongEmphasis()"},
      - 34 				{className:"emphasis", title:"Emphasis", handler:"xed.handleEmphasis()"},
      - 35 				{className:"underline", title:"Underline", handler:"xed.handleUnderline()"},
      - 36 				{className:"strike", title:"Strike", handler:"xed.handleStrike()"},
      - 37 				{className:"superscription", title:"Superscription", handler:"xed.handleSuperscription()"},
      - 38 				{className:"subscription", title:"Subscription", handler:"xed.handleSubscription()"}
      - 39 			],
      - 40 			[
      - 41 				{className:"removeFormat", title:"Remove format", handler:"xed.handleRemoveFormat()"}
      - 42 			],
      - 43 			[
      - 44 				{className:"justifyLeft", title:"Justify left", handler:"xed.handleJustify('left')"},
      - 45 				{className:"justifyCenter", title:"Justify center", handler:"xed.handleJustify('center')"},
      - 46 				{className:"justifyRight", title:"Justify right", handler:"xed.handleJustify('right')"},
      - 47 				{className:"justifyBoth", title:"Justify both", handler:"xed.handleJustify('both')"}
      - 48 			],
      - 49 			[
      - 50 				{className:"indent", title:"Indent", handler:"xed.handleIndent()"},
      - 51 				{className:"outdent", title:"Outdent", handler:"xed.handleOutdent()"}
      - 52 			],
      - 53 			[
      - 54 				{className:"unorderedList", title:"Unordered list", handler:"xed.handleList('UL')"},
      - 55 				{className:"orderedList", title:"Ordered list", handler:"xed.handleList('OL')"}
      - 56 			],
      - 57 			[
      - 58 				{className:"paragraph", title:"Paragraph", handler:"xed.handleApplyBlock('P')"},
      - 59 				{className:"heading1", title:"Heading 1", handler:"xed.handleApplyBlock('H1')"},
      - 60 				{className:"blockquote", title:"Blockquote", handler:"xed.handleApplyBlock('BLOCKQUOTE')"},
      - 61 				{className:"code", title:"Code", handler:"xed.handleList('CODE')"},
      - 62 				{className:"division", title:"Division", handler:"xed.handleApplyBlock('DIV')"}
      - 63 			],
      - 64 			[
      - 65 				{className:"table", title:"Table", handler:"xed.handleTable(3,3,'tl')"},
      - 66 				{className:"separator", title:"Separator", handler:"xed.handleSeparator()"}
      - 67 			],
      - 68 			[
      - 69 				{className:"html", title:"Edit source", handler:"xed.toggleSourceAndWysiwygMode()"}
      - 70 			],
      - 71 			[
      - 72 				{className:"undo", title:"Undo", handler:"xed.handleUndo()"},
      - 73 				{className:"redo", title:"Redo", handler:"xed.handleRedo()"}
      - 74 			]
      - 75 		];
      - 76 		
      - 77 		this.config.imagePathForDefaultToobar = 'img/toolbar/';
      - 78 		
      - 79 		// relative | host_relative | absolute | browser_default
      - 80 		this.config.urlValidationMode = 'absolute';
      - 81 		
      - 82 		this.config.automaticallyHookSubmitEvent = true;
      - 83 		
      - 84 		this.config.allowedTags = ['a', 'abbr', 'acronym', 'address', 'blockquote', 'br', 'caption', 'cite', 'code', 'dd', 'dfn', 'div', 'dl', 'dt', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'img', 'kbd', 'li', 'ol', 'p', 'pre', 'q', 'samp', 'span', 'sup', 'sub', 'strong', 'table', 'thead', 'tbody', 'td', 'th', 'tr', 'ul', 'var'];
      - 85 		this.config.allowedAttributes = ['alt', 'cite', 'class', 'datetime', 'height', 'href', 'id', 'rel', 'rev', 'src', 'style', 'title', 'width'];
      - 86 		
      - 87 		this.config.shortcuts = {};
      - 88 		this.config.autocorrections = {};
      - 89 		this.config.autocompletions = {};
      - 90 		this.config.templateProcessors = {};
      - 91 		this.config.contextMenuHandlers = {};
      - 92 		
      - 93 		/**
      - 94 		 * Original content element
      - 95 		 * @type Element
      - 96 		 */
      - 97 		this.contentElement = contentElement;
      - 98 		
      - 99 		/**
      -100 		 * Owner document of content element
      -101 		 * @type Document
      -102 		 */
      -103 		this.doc = this.contentElement.ownerDocument;
      -104 		
      -105 		/**
      -106 		 * Body of content element
      -107 		 * @type Element
      -108 		 */
      -109 		this.body = this.doc.body;
      -110 		
      -111 		/**
      -112 		 * False or 'readonly' means read-only mode, true or 'wysiwyg' means WYSIWYG editing mode, and 'source' means source editing mode.
      -113 		 * @type Object
      -114 		 */
      -115 		this.currentEditMode = 'readonly';
      -116 		
      -117 		/**
      -118 		 * RichDom instance
      -119 		 * @type xq.RichDom
      -120 		 */
      -121 		this.rdom = xq.RichDom.createInstance();
      -122 		
      -123 		/**
      -124 		 * Validator instance
      -125 		 * @type xq.Validator
      -126 		 */
      -127 		this.validator = null;
      -128 		
      -129 		/**
      -130 		 * Outmost wrapper div
      -131 		 * @type Element
      -132 		 */
      -133 		this.outmostWrapper = null;
      -134 		
      -135 		/**
      -136 		 * Source editor container
      -137 		 * @type Element
      -138 		 */
      -139 		this.sourceEditorDiv = null;
      -140 		
      -141 		/**
      -142 		 * Source editor textarea
      -143 		 * @type Element
      -144 		 */
      -145 		this.sourceEditorTextarea = null;
      -146 		
      -147 		/**
      -148 		 * WYSIWYG editor container
      -149 		 * @type Element
      -150 		 */
      -151 		this.wysiwygEditorDiv = null;
      -152 		
      -153 		/**
      -154 		 * Design mode iframe
      -155 		 * @type IFrame
      -156 		 */
      -157 		this.editorFrame = null;
      -158 		
      -159 		/**
      -160 		 * Window that contains design mode iframe
      -161 		 * @type Window
      -162 		 */
      -163 		this.editorWin = null;
      -164 		
      -165 		/**
      -166 		 * Document that contained by design mode iframe
      -167 		 * @type Document
      -168 		 */
      -169 		this.editorDoc = null;
      -170 		
      -171 		/**
      -172 		 * Body that contained by design mode iframe
      -173 		 * @type Element
      -174 		 */
      -175 		this.editorBody = null;
      -176 		
      -177 		/**
      -178 		 * Toolbar container
      -179 		 * @type Element
      -180 		 */
      -181 		this.toolbarContainer = toolbarContainer;
      -182 		
      -183 		/**
      -184 		 * Toolbar buttons
      -185 		 * @type Array
      -186 		 */
      -187 		this.toolbarButtons = null;
      -188 		
      -189 		/**
      -190 		 * Undo/redo manager
      -191 		 * @type xq.EditHistory
      -192 		 */
      -193 		this.editHistory = null;
      -194 		
      -195 		this._contextMenuContainer = null;
      -196 		this._contextMenuItems = null;
      -197 		
      -198 		this._validContentCache = null;
      -199 		this._lastModified = null;
      -200 		
      -201 		this.addShortcuts(this._getDefaultShortcuts());
      -202 		this.addTemplateProcessors(this._getDefaultTemplateProcessors());
      -203 		
      -204 		this.addListener({
      -205 			onEditorCurrentContentChanged: function(xed) {
      -206 				var curFocusElement = xed.rdom.getCurrentElement();
      -207 				if(!curFocusElement) return;
      -208 				
      -209 				if(xed._lastFocusElement != curFocusElement) {
      -210 					if(!xed.rdom.tree.isBlockOnlyContainer(xed._lastFocusElement) && xed.rdom.tree.isBlock(xed._lastFocusElement)) {
      -211 						xed.rdom.removeTrailingWhitespace(xed._lastFocusElement);
      -212 					}
      -213 					xed._fireOnElementChanged(xed._lastFocusElement, curFocusElement);
      -214 					xed._lastFocusElement = curFocusElement;
      -215 				}
      -216 
      -217 				xed.updateAllToolbarButtonsStatus(curFocusElement);
      -218 			}
      -219 		});
      -220 	},
      -221 	
      -222 	
      -223 	
      -224 	/////////////////////////////////////////////
      -225 	// Configuration Management
      -226 	
      -227 	_getDefaultShortcuts: function() {
      -228 		if(xq.Browser.isMac) {
      -229 			// Mac FF & Safari
      -230 			return [
      -231 				{event:"Ctrl+Shift+SPACE", handler:"this.handleAutocompletion(); stop = true;"},
      -232 				{event:"ENTER", handler:"this.handleEnter(false, false)"},
      -233 				{event:"Ctrl+ENTER", handler:"this.handleEnter(true, false)"},
      -234 				{event:"Ctrl+Shift+ENTER", handler:"this.handleEnter(true, true)"},
      -235 				{event:"TAB", handler:"this.handleTab()"},
      -236 				{event:"Shift+TAB", handler:"this.handleShiftTab()"},
      -237 				{event:"DELETE", handler:"this.handleDelete()"},
      -238 				{event:"BACKSPACE", handler:"this.handleBackspace()"},
      -239 				
      -240 				{event:"Ctrl+B", handler:"this.handleStrongEmphasis()"},
      -241 				{event:"Ctrl+I", handler:"this.handleEmphasis()"},
      -242 				{event:"Ctrl+U", handler:"this.handleUnderline()"},
      -243 				{event:"Ctrl+K", handler:"this.handleStrike()"},
      -244 				{event:"Meta+Z", handler:"this.handleUndo()"},
      -245 				{event:"Meta+Shift+Z", handler:"this.handleRedo()"},
      -246 				{event:"Meta+Y", handler:"this.handleRedo()"}
      -247 			];
      -248 		} else if(xq.Browser.isUbuntu) {
      -249 			//  Ubunto FF
      -250 			return [
      -251 				{event:"Ctrl+SPACE", handler:"this.handleAutocompletion(); stop = true;"},
      -252 				{event:"ENTER", handler:"this.handleEnter(false, false)"},
      -253 				{event:"Ctrl+ENTER", handler:"this.handleEnter(true, false)"},
      -254 				{event:"Ctrl+Shift+ENTER", handler:"this.handleEnter(true, true)"},
      -255 				{event:"TAB", handler:"this.handleTab()"},
      -256 				{event:"Shift+TAB", handler:"this.handleShiftTab()"},
      -257 				{event:"DELETE", handler:"this.handleDelete()"},
      -258 				{event:"BACKSPACE", handler:"this.handleBackspace()"},
      -259 			
      -260 				{event:"Ctrl+B", handler:"this.handleStrongEmphasis()"},
      -261 				{event:"Ctrl+I", handler:"this.handleEmphasis()"},
      -262 				{event:"Ctrl+U", handler:"this.handleUnderline()"},
      -263 				{event:"Ctrl+K", handler:"this.handleStrike()"},
      -264 				{event:"Ctrl+Z", handler:"this.handleUndo()"},
      -265 				{event:"Ctrl+Y", handler:"this.handleRedo()"}
      -266 			];
      -267 		} else {
      -268 			// Win IE & FF
      -269 			return [
      -270 				{event:"Ctrl+SPACE", handler:"this.handleAutocompletion(); stop = true;"},
      -271 				{event:"ENTER", handler:"this.handleEnter(false, false)"},
      -272 				{event:"Ctrl+ENTER", handler:"this.handleEnter(true, false)"},
      -273 				{event:"Ctrl+Shift+ENTER", handler:"this.handleEnter(true, true)"},
      -274 				{event:"TAB", handler:"this.handleTab()"},
      -275 				{event:"Shift+TAB", handler:"this.handleShiftTab()"},
      -276 				{event:"DELETE", handler:"this.handleDelete()"},
      -277 				{event:"BACKSPACE", handler:"this.handleBackspace()"},
      -278 			
      -279 				{event:"Ctrl+B", handler:"this.handleStrongEmphasis()"},
      -280 				{event:"Ctrl+I", handler:"this.handleEmphasis()"},
      -281 				{event:"Ctrl+U", handler:"this.handleUnderline()"},
      -282 				{event:"Ctrl+K", handler:"this.handleStrike()"},
      -283 				{event:"Ctrl+Z", handler:"this.handleUndo()"},
      -284 				{event:"Ctrl+Y", handler:"this.handleRedo()"}
      -285 			];
      -286 		}
      -287 	},
      -288 	
      -289 	_getDefaultTemplateProcessors: function() {
      -290 		return [
      -291 			{
      -292 				id:"predefinedKeywordProcessor",
      -293 				handler:function(html) {
      -294 					var today = Date.get();
      -295 					var keywords = {
      -296 						year: today.getFullYear(),
      -297 						month: today.getMonth() + 1,
      -298 						date: today.getDate(),
      -299 						hour: today.getHours(),
      -300 						min: today.getMinutes(),
      -301 						sec: today.getSeconds()
      -302 					};
      -303 					
      -304 					return html.replace(/\{xq:(year|month|date|hour|min|sec)\}/img, function(text, keyword) {
      -305 						return keywords[keyword] || keyword;
      -306 					});
      -307 				}
      -308 			}
      -309 		];
      -310 	},
      -311 	
      -312 	/**
      -313 	 * Adds or replaces keyboard shortcut.
      -314 	 *
      -315 	 * @param {String} shortcut keymap expression like "CTRL+Space"
      -316 	 * @param {Object} handler string or function to be evaluated or called
      -317 	 */
      -318 	addShortcut: function(shortcut, handler) {
      -319 		this.config.shortcuts[shortcut] = {"event":new xq.Shortcut(shortcut), "handler":handler};
      -320 	},
      -321 	
      -322 	/**
      -323 	 * Adds several keyboard shortcuts at once.
      -324 	 *
      -325 	 * @param {Array} list of shortcuts. each element should have following structure: {event:"keymap expression", handler:handler}
      -326 	 */
      -327 	addShortcuts: function(list) {
      -328 		list.each(function(shortcut) {
      -329 			this.addShortcut(shortcut.event, shortcut.handler);
      -330 		}.bind(this));
      -331 	},
      -332 
      -333 	/**
      -334 	 * Returns keyboard shortcut matches with given keymap expression.
      -335 	 *
      -336 	 * @param {String} shortcut keymap expression like "CTRL+Space"
      -337 	 */
      -338 	getShortcut: function(shortcut) {return this.config.shortcuts[shortcut];},
      -339 
      -340 	/**
      -341 	 * Returns entire keyboard shortcuts' map
      -342 	 */
      -343 	getShortcuts: function() {return this.config.shortcuts;},
      -344 	
      -345 	/**
      -346 	 * Remove keyboard shortcut matches with given keymap expression.
      -347 	 *
      -348 	 * @param {String} shortcut keymap expression like "CTRL+Space"
      -349 	 */
      -350 	removeShortcut: function(shortcut) {delete this.config.shortcuts[shortcut];},
      -351 	
      -352 	/**
      -353 	 * Adds or replaces autocorrection handler.
      -354 	 *
      -355 	 * @param {String} id unique identifier
      -356 	 * @param {Object} criteria regex pattern or function to be used as a criterion for match
      -357 	 * @param {Object} handler string or function to be evaluated or called when criteria met
      -358 	 */
      -359 	addAutocorrection: function(id, criteria, handler) {
      -360 		if(criteria.exec) {
      -361 			var pattern = criteria;
      -362 			criteria = function(text) {return text.match(pattern)};
      -363 		}
      -364 		this.config.autocorrections[id] = {"criteria":criteria, "handler":handler};
      -365 	},
      -366 	
      -367 	/**
      -368 	 * Adds several autocorrection handlers at once.
      -369 	 *
      -370 	 * @param {Array} list of autocorrection. each element should have following structure: {id:"identifier", criteria:criteria, handler:handler}
      -371 	 */
      -372 	addAutocorrections: function(list) {
      -373 		list.each(function(ac) {
      -374 			this.addAutocorrection(ac.id, ac.criteria, ac.handler);
      -375 		}.bind(this));
      -376 	},
      -377 	
      -378 	/**
      -379 	 * Returns autocorrection handler matches with given id
      -380 	 *
      -381 	 * @param {String} id unique identifier
      -382 	 */
      -383 	getAutocorrection: function(id) {return this.config.autocorrection[id];},
      -384 	
      -385 	/**
      -386 	 * Returns entire autocorrections' map
      -387 	 */
      -388 	getAutocorrections: function() {return this.config.autocorrections;},
      -389 	
      -390 	/**
      -391 	 * Removes autocorrection handler matches with given id
      -392 	 *
      -393 	 * @param {String} id unique identifier
      -394 	 */
      -395 	removeAutocorrection: function(id) {delete this.config.autocorrections[id];},
      -396 	
      -397 	/**
      -398 	 * Adds or replaces autocompletion handler.
      -399 	 *
      -400 	 * @param {String} id unique identifier
      -401 	 * @param {Object} criteria regex pattern or function to be used as a criterion for match
      -402 	 * @param {Object} handler string or function to be evaluated or called when criteria met
      -403 	 */
      -404 	addAutocompletion: function(id, criteria, handler) {
      -405 		if(criteria.exec) {
      -406 			var pattern = criteria;
      -407 			criteria = function(text) {
      -408 				var m = pattern.exec(text);
      -409 				return m ? m.index : -1;
      -410 			};
      -411 		}
      -412 		this.config.autocompletions[id] = {"criteria":criteria, "handler":handler};
      -413 	},
      -414 	
      -415 	/**
      -416 	 * Adds several autocompletion handlers at once.
      -417 	 *
      -418 	 * @param {Array} list of autocompletion. each element should have following structure: {id:"identifier", criteria:criteria, handler:handler}
      -419 	 */
      -420 	addAutocompletions: function(list) {
      -421 		list.each(function(ac) {
      -422 			this.addAutocompletion(ac.id, ac.criteria, ac.handler);
      -423 		}.bind(this));
      -424 	},
      -425 	
      -426 	/**
      -427 	 * Returns autocompletion handler matches with given id
      -428 	 *
      -429 	 * @param {String} id unique identifier
      -430 	 */
      -431 	getAutocompletion: function(id) {return this.config.autocompletions[id];},
      -432 	
      -433 	/**
      -434 	 * Returns entire autocompletions' map
      -435 	 */
      -436 	getAutocompletions: function() {return this.config.autocompletions;},
      -437 	
      -438 	/**
      -439 	 * Removes autocompletion handler matches with given id
      -440 	 *
      -441 	 * @param {String} id unique identifier
      -442 	 */
      -443 	removeAutocompletion: function(id) {delete this.config.autocompletions[id];},
      -444 	
      -445 	/**
      -446 	 * Adds or replaces template processor.
      -447 	 *
      -448 	 * @param {String} id unique identifier
      -449 	 * @param {Object} handler string or function to be evaluated or called when template inserted
      -450 	 */
      -451 	addTemplateProcessor: function(id, handler) {
      -452 		this.config.templateProcessors[id] = {"handler":handler};
      -453 	},
      -454 	
      -455 	/**
      -456 	 * Adds several template processors at once.
      -457 	 *
      -458 	 * @param {Array} list of template processors. Each element should have following structure: {id:"identifier", handler:handler}
      -459 	 */
      -460 	addTemplateProcessors: function(list) {
      -461 		list.each(function(tp) {
      -462 			this.addTemplateProcessor(tp.id, tp.handler);
      -463 		}.bind(this));
      -464 	},
      -465 	
      -466 	/**
      -467 	 * Returns template processor matches with given id
      -468 	 *
      -469 	 * @param {String} id unique identifier
      -470 	 */
      -471 	getTemplateProcessor: function(id) {return this.config.templateProcessors[id];},
      -472 
      -473 	/**
      -474 	 * Returns entire template processors' map
      -475 	 */
      -476 	getTemplateProcessors: function() {return this.config.templateProcessors;},
      -477 
      -478 	/**
      -479 	 * Removes template processor matches with given id
      -480 	 *
      -481 	 * @param {String} id unique identifier
      -482 	 */
      -483 	removeTemplateProcessor: function(id) {delete this.config.templateProcessors[id];},
      -484 
      -485 
      -486 
      -487 	/**
      -488 	 * Adds or replaces context menu handler.
      -489 	 *
      -490 	 * @param {String} id unique identifier
      -491 	 * @param {Object} handler string or function to be evaluated or called when onContextMenu occured
      -492 	 */
      -493 	addContextMenuHandler: function(id, handler) {
      -494 		this.config.contextMenuHandlers[id] = {"handler":handler};
      -495 	},
      -496 	
      -497 	/**
      -498 	 * Adds several context menu handlers at once.
      -499 	 *
      -500 	 * @param {Array} list of handlers. Each element should have following structure: {id:"identifier", handler:handler}
      -501 	 */
      -502 	addContextMenuHandlers: function(list) {
      -503 		list.each(function(mh) {
      -504 			this.addContextMenuHandler(mh.id, mh.handler);
      -505 		}.bind(this));
      -506 	},
      -507 	
      -508 	/**
      -509 	 * Returns context menu handler matches with given id
      -510 	 *
      -511 	 * @param {String} id unique identifier
      -512 	 */
      -513 	getContextMenuHandler: function(id) {return this.config.contextMenuHandlers[id];},
      -514 
      -515 	/**
      -516 	 * Returns entire context menu handlers' map
      -517 	 */
      -518 	getContextMenuHandlers: function() {return this.config.contextMenuHandlers;},
      -519 
      -520 	/**
      -521 	 * Removes context menu handler matches with given id
      -522 	 *
      -523 	 * @param {String} id unique identifier
      -524 	 */
      -525 	removeContextMenuHandler: function(id) {delete this.config.contextMenuHandlers[id];},
      -526 	
      -527 	
      -528 	
      -529 	/////////////////////////////////////////////
      -530 	// Edit mode management
      -531 	
      -532 	/**
      -533 	 * Returns current edit mode - readonly, wysiwyg, source
      -534 	 */
      -535 	getCurrentEditMode: function() {
      -536 		return this.currentEditMode;
      -537 	},
      -538 	
      -539 	toggleSourceAndWysiwygMode: function() {
      -540 		var mode = this.getCurrentEditMode();
      -541 		if(mode == 'readonly') return;
      -542 		this.setEditMode(mode == 'wysiwyg' ? 'source' : 'wysiwyg');
      -543 		
      -544 		return true;
      -545 	},
      -546 	
      -547 	/**
      -548 	 * Switches between edit-mode/normal mode.
      -549 	 *
      -550 	 * @param {Object} mode false or 'readonly' means read-only mode, true or 'wysiwyg' means WYSIWYG editing mode, and 'source' means source editing mode.
      -551 	 */
      -552 	setEditMode: function(mode) {
      -553 		if(this.currentEditMode == mode) return;
      -554 		
      -555 		var firstCall = mode != false && mode != 'readonly' && !this.outmostWrapper;
      -556 		if(firstCall) {
      -557 			// Create editor element if needed
      -558 			this._createEditorFrame();
      -559 			this._registerEventHandlers();
      -560 			
      -561 			this.loadCurrentContentFromStaticContent();
      -562 			this.editHistory = new xq.EditHistory(this.rdom);
      -563 		}
      -564 		
      -565 		if(mode == 'wysiwyg') {
      -566 			// Update contents
      -567 			if(this.currentEditMode == 'source') this.setStaticContent(this.getSourceContent());
      -568 			this.loadCurrentContentFromStaticContent();
      -569 			
      -570 			// Make static content invisible
      -571 			this.contentElement.style.display = "none";
      -572 			
      -573 			// Make WYSIWYG editor visible
      -574 			this.sourceEditorDiv.style.display = "none";
      -575 			this.wysiwygEditorDiv.style.display = "block";
      -576 			this.outmostWrapper.style.display = "block";
      -577 			
      -578 			this.currentEditMode = mode;
      -579 			
      -580 			if(!xq.Browser.isTrident) {
      -581 				window.setTimeout(function() {
      -582 					if(this.getDoc().designMode == 'On') return;
      -583 					
      -584 					// Without it, Firefox doesn't display embedded SWF
      -585 					this.getDoc().designMode = 'On';
      -586 					
      -587 					// turn off Firefox's table editing feature
      -588 					try {this.getDoc().execCommand("enableInlineTableEditing", false, "false")} catch(ignored) {}
      -589 				}.bind(this), 0);
      -590 			}
      -591 			
      -592 			this.enableToolbarButtons();
      -593 			if(!firstCall) this.focus();
      -594 		} else if(mode == 'source') {
      -595 			// Update contents
      -596 			if(this.currentEditMode == 'wysiwyg') this.setStaticContent(this.getWysiwygContent());
      -597 			this.loadCurrentContentFromStaticContent();
      -598 			
      -599 			// Make static content invisible
      -600 			this.contentElement.style.display = "none";
      -601 			
      -602 			// Make source editor visible
      -603 			this.sourceEditorDiv.style.display = "block";
      -604 			this.wysiwygEditorDiv.style.display = "none";
      -605 			this.outmostWrapper.style.display = "block";
      -606 			
      -607 			this.currentEditMode = mode;
      -608 
      -609 			this.disableToolbarButtons(['html']);
      -610 			if(!firstCall) this.focus();
      -611 		} else {
      -612 			// Update contents
      -613 			this.setStaticContent(this.getCurrentContent());
      -614 			this.loadCurrentContentFromStaticContent();
      -615 
      -616 			// Make editor and toolbar invisible
      -617 			this.outmostWrapper.style.display = "none";
      -618 			
      -619 			// Make static content visible
      -620 			this.contentElement.style.display = "block";
      -621 			
      -622 			this.currentEditMode = mode;
      -623 		}
      -624 		
      -625 		this._fireOnCurrentEditModeChanged(this, mode);
      -626 	},
      -627 	
      -628 	/**
      -629 	 * Load CSS into editing-mode document
      -630 	 *
      -631 	 * @param {string} path URL
      -632 	 */
      -633 	loadStylesheet: function(path) {
      -634 		var head = this.editorDoc.getElementsByTagName("HEAD")[0];
      -635 		var link = this.editorDoc.createElement("LINK");
      -636 		link.rel = "Stylesheet";
      -637 		link.type = "text/css";
      -638 		link.href = path;
      -639 		head.appendChild(link);
      -640 	},
      -641 	
      -642 	/**
      -643 	 * Sets editor's dynamic content from static content
      -644 	 */
      -645 	loadCurrentContentFromStaticContent: function() {
      -646 		// update WYSIWYG editor
      -647 		var html = this.validator.invalidate(this.getStaticContentAsDOM());
      -648 		html = this.removeUnnecessarySpaces(html);
      -649 		
      -650 		if(html.blank()) {
      -651 			this.rdom.clearRoot();
      -652 		} else {
      -653 			this.rdom.getRoot().innerHTML = html;
      -654 		}
      -655 		this.rdom.wrapAllInlineOrTextNodesAs("P", this.rdom.getRoot(), true);
      -656 		
      -657 		// update source editor
      -658 		var source = this.getWysiwygContent(true, true);
      -659 		
      -660 		this.sourceEditorTextarea.value = source;
      -661 		if(xq.Browser.isWebkit) {
      -662 			this.sourceEditorTextarea.innerHTML = source;
      -663 		}
      -664 		
      -665 		this._fireOnCurrentContentChanged(this);
      -666 	},
      -667 	
      -668 	/**
      -669 	 * Enables all toolbar buttons
      -670 	 *
      -671 	 * @param {Array} [exceptions] array of string containing classnames to exclude
      -672 	 */
      -673 	enableToolbarButtons: function(exceptions) {
      -674 		if(!this.toolbarContainer) return;
      -675 		
      -676 		this._execForAllToolbarButtons(exceptions, function(li, exception) {
      -677 			li.firstChild.className = !exception ? '' : 'disabled';
      -678 		});
      -679 		
      -680 		// Toolbar image icon disappears without following code:
      -681 		if(xq.Browser.isIE6) {
      -682 			this.toolbarContainer.style.display = 'none';
      -683 			setTimeout(function() {this.toolbarContainer.style.display = 'block';}.bind(this), 0);
      -684 		}
      -685 	},
      -686 	
      -687 	/**
      -688 	 * Disables all toolbar buttons
      -689 	 *
      -690 	 * @param {Array} [exceptions] array of string containing classnames to exclude
      -691 	 */
      -692 	disableToolbarButtons: function(exceptions) {
      -693 		this._execForAllToolbarButtons(exceptions, function(li, exception) {
      -694 			li.firstChild.className = exception ? '' : 'disabled';
      -695 		});
      -696 	},
      -697 	
      -698 	_execForAllToolbarButtons: function(exceptions, exec) {
      -699 		if(!this.toolbarContainer) return;
      -700 		exceptions = exceptions || [];
      -701 		
      -702 		$(this.toolbarContainer).select('li').each(function(li) {
      -703 			var buttonsClassName = li.classNames().find(function(name) {return name != 'xq_separator'});
      -704 			var exception = exceptions.include(buttonsClassName);
      -705 			exec(li, exception);
      -706 		});
      -707 	},
      -708 
      -709 	_updateToolbarButtonStatus: function(buttonClassName, selected) {
      -710 		var button = this.toolbarButtons.get(buttonClassName);
      -711 		if(button) button.firstChild.firstChild.className = selected ? 'selected' : '';
      -712 	},
      -713 	
      -714 	updateAllToolbarButtonsStatus: function(element) {
      -715 		if(!this.toolbarContainer) return;
      -716 		if(!this.toolbarButtons) {
      -717 			var classNames = [
      -718 				"emphasis", "strongEmphasis", "underline", "strike", "superscription", "subscription",
      -719 				"justifyLeft", "justifyCenter", "justifyRight", "justifyBoth",
      -720 				"unorderedList", "orderedList", "code",
      -721 				"paragraph", "heading1", "heading2", "heading3", "heading4", "heading5", "heading6"
      -722 			];
      -723 			
      -724 			this.toolbarButtons = $H({});
      -725 			
      -726 			classNames.each(function(className) {
      -727 				var found = $(this.toolbarContainer).getElementsBySelector("." + className);
      -728 				var button = found && found.length > 0 ? found[0] : null;
      -729 				if(button) this.toolbarButtons.set(className, button);
      -730 			}.bind(this));
      -731 		}
      -732 		
      -733 		var buttons = this.toolbarButtons;
      -734 		
      -735 		var info = this.rdom.collectStructureAndStyle(element);
      -736 		
      -737 		this._updateToolbarButtonStatus('emphasis', info.em);
      -738 		this._updateToolbarButtonStatus('strongEmphasis', info.strong);
      -739 		this._updateToolbarButtonStatus('underline', info.underline);
      -740 		this._updateToolbarButtonStatus('strike', info.strike);
      -741 		this._updateToolbarButtonStatus('superscription', info.superscription);
      -742 		this._updateToolbarButtonStatus('subscription', info.subscription);
      -743 		
      -744 		this._updateToolbarButtonStatus('justifyLeft', info.justification == 'left');
      -745 		this._updateToolbarButtonStatus('justifyCenter', info.justification == 'center');
      -746 		this._updateToolbarButtonStatus('justifyRight', info.justification == 'right');
      -747 		this._updateToolbarButtonStatus('justifyBoth', info.justification == 'justify');
      -748 		
      -749 		this._updateToolbarButtonStatus('orderedList', info.list == 'OL');
      -750 		this._updateToolbarButtonStatus('unorderedList', info.list == 'UL');
      -751 		this._updateToolbarButtonStatus('code', info.list == 'CODE');
      -752 		
      -753 		this._updateToolbarButtonStatus('paragraph', info.block == 'P');
      -754 		this._updateToolbarButtonStatus('heading1', info.block == 'H1');
      -755 		this._updateToolbarButtonStatus('heading2', info.block == 'H2');
      -756 		this._updateToolbarButtonStatus('heading3', info.block == 'H3');
      -757 		this._updateToolbarButtonStatus('heading4', info.block == 'H4');
      -758 		this._updateToolbarButtonStatus('heading5', info.block == 'H5');
      -759 		this._updateToolbarButtonStatus('heading6', info.block == 'H6');
      -760 	},
      -761 	
      -762 	removeUnnecessarySpaces: function(html) {
      -763 		var blocks = this.rdom.tree.getBlockTags().join("|");
      -764 		var regex = new RegExp("\\s*<(/?)(" + blocks + ")>\\s*", "img");
      -765 		return html.replace(regex, '<$1$2>');
      -766 	},
      -767 	
      -768 	/**
      -769 	 * Gets editor's dynamic content from current editor(source or WYSIWYG)
      -770 	 * 
      -771 	 * @return {Object} HTML String
      -772 	 */
      -773 	getCurrentContent: function(performFullValidation) {
      -774 		if(this.getCurrentEditMode() == 'source') {
      -775 			return this.getSourceContent(performFullValidation);
      -776 		} else {
      -777 			return this.getWysiwygContent(performFullValidation);
      -778 		}
      -779 	},
      -780 	
      -781 	/**
      -782 	 * Gets editor's dynamic content from WYSIWYG editor
      -783 	 * 
      -784 	 * @return {Object} HTML String
      -785 	 */
      -786 	getWysiwygContent: function(performFullValidation, dontUseCache) {
      -787 		if(dontUseCache || !performFullValidation) return this.validator.validate(this.rdom.getRoot(), performFullValidation);
      -788 		
      -789 		var lastModified = this.editHistory.getLastModifiedDate();
      -790 		if(this._lastModified != lastModified) {
      -791 			this._validContentCache = this.validator.validate(this.rdom.getRoot(), performFullValidation);
      -792 			this._lastModified = lastModified;
      -793 		}
      -794 		return this._validContentCache;
      -795 	},
      -796 	
      -797 	/**
      -798 	 * Gets editor's dynamic content from source editor
      -799 	 * 
      -800 	 * @return {Object} HTML String
      -801 	 */
      -802 	getSourceContent: function(performFullValidation) {
      -803 		var raw = this.sourceEditorTextarea[xq.Browser.isWebkit ? 'innerHTML' : 'value'];
      -804 		var tempDiv = document.createElement('div');
      -805 		tempDiv.innerHTML = this.removeUnnecessarySpaces(raw);
      -806 
      -807 		var rdom = xq.RichDom.createInstance();
      -808 		rdom.setRoot(document.body);
      -809 		rdom.wrapAllInlineOrTextNodesAs("P", tempDiv, true);
      -810 		
      -811 		return this.validator.validate(tempDiv, performFullValidation);
      -812 	},
      -813 	
      -814 	/**
      -815 	 * Sets editor's original content
      -816 	 *
      -817 	 * @param {Object} content HTML String
      -818 	 */
      -819 	setStaticContent: function(content) {
      -820 		if(this.contentElement.nodeName == 'TEXTAREA') {
      -821 			this.contentElement.value = content;
      -822 			if(xq.Browser.isWebkit) {
      -823 				this.contentElement.innerHTML = content;
      -824 			}
      -825 		} else {
      -826 			this.contentElement.innerHTML = content;
      -827 		}
      -828 		this._fireOnStaticContentChanged(this, content);
      -829 	},
      -830 	
      -831 	/**
      -832 	 * Gets editor's original content
      -833 	 *
      -834 	 * @return {Object} HTML String
      -835 	 */
      -836 	getStaticContent: function() {
      -837 		var content;
      -838 		if(this.contentElement.nodeName == 'TEXTAREA') {
      -839 			content = this.contentElement[xq.Browser.isWebkit ? 'innerHTML' : 'value'];
      -840 		} else {
      -841 			content = this.contentElement.innerHTML;
      -842 		}
      -843 		return content;
      -844 	},
      -845 	
      -846 	/**
      -847 	 * Gets editor's original content as DOM node
      -848 	 *
      -849 	 * @return {Object} HTML String
      -850 	 */
      -851 	getStaticContentAsDOM: function() {
      -852 		if(this.contentElement.nodeName == 'TEXTAREA') {
      -853 			var div = this.doc.createElement('DIV');
      -854 			div.innerHTML = this.contentElement[xq.Browser.isWebkit ? 'innerHTML' : 'value'];
      -855 			return div;
      -856 		} else {
      -857 			return this.contentElement;
      -858 		}
      -859 	},
      -860 	
      -861 	/**
      -862 	 * Gives focus to editor
      -863 	 */
      -864 	focus: function() {
      -865 		if(this.getCurrentEditMode() == 'wysiwyg') {
      -866 			this.rdom.focus();
      -867 			window.setTimeout(function() {
      -868 				this.updateAllToolbarButtonsStatus(this.rdom.getCurrentElement());
      -869 			}.bind(this), 0);
      -870 		} else if(this.getCurrentEditMode() == 'source') {
      -871 			this.sourceEditorTextarea.focus();
      -872 		}
      -873 	},
      -874 	
      -875 	/**
      -876 	 * Returns designmode iframe object
      -877 	 */
      -878 	getFrame: function() {
      -879 		return this.editorFrame;
      -880 	},
      -881 	
      -882 	/**
      -883 	 * Returns designmode window object
      -884 	 */
      -885 	getWin: function() {
      -886 		return this.editorWin;
      -887 	},
      -888 	
      -889 	/**
      -890 	 * Returns designmode document object
      -891 	 */
      -892 	getDoc: function() {
      -893 		return this.editorDoc;
      -894 	},
      -895 	
      -896 	/**
      -897 	 * Returns outmost wrapper element
      -898 	 */
      -899 	getOutmostWrapper: function() {
      -900 		return this.outmostWrapper;
      -901 	},
      -902 	
      -903 	/**
      -904 	 * Returns designmode body object
      -905 	 */
      -906 	getBody: function() {
      -907 		return this.editorBody;
      -908 	},
      -909 	
      -910 	_createEditorFrame: function() {
      -911 		// create outer DIV
      -912 		this.outmostWrapper = this.doc.createElement('div');
      -913 		this.outmostWrapper.className = "xquared";
      -914 		
      -915 		this.contentElement.parentNode.insertBefore(this.outmostWrapper, this.contentElement);
      -916 		
      -917 		// create toolbar is needed
      -918 		if(!this.toolbarContainer && this.config.generateDefaultToolbar) {
      -919 			this.toolbarContainer = this._generateDefaultToolbar();
      -920 			this.outmostWrapper.appendChild(this.toolbarContainer);
      -921 		}
      -922 		
      -923 		// create source editor div
      -924 		this.sourceEditorDiv = this.doc.createElement('div');
      -925 		this.sourceEditorDiv.className = "editor source_editor"; //TODO: remove editor
      -926 		this.sourceEditorDiv.style.display = "none";
      -927 		this.outmostWrapper.appendChild(this.sourceEditorDiv);
      -928 		
      -929 		// create TEXTAREA for source editor
      -930 		this.sourceEditorTextarea = this.doc.createElement('textarea');
      -931 		this.sourceEditorDiv.appendChild(this.sourceEditorTextarea);
      -932 		
      -933 		// create WYSIWYG editor div
      -934 		this.wysiwygEditorDiv = this.doc.createElement('div');
      -935 		this.wysiwygEditorDiv.className = "editor wysiwyg_editor"; //TODO: remove editor
      -936 		this.wysiwygEditorDiv.style.display = "none";
      -937 		this.outmostWrapper.appendChild(this.wysiwygEditorDiv);
      -938 		
      -939 		// create designmode iframe for WYSIWYG editor
      -940 		this.editorFrame = this.doc.createElement('iframe');
      -941 		this.rdom.setAttributes(this.editorFrame, {
      -942 			"frameBorder": "0",
      -943 			"marginWidth": "0",
      -944 			"marginHeight": "0",
      -945 			"leftMargin": "0",
      -946 			"topMargin": "0",
      -947 			"allowTransparency": "true"
      -948 		});
      -949 		this.wysiwygEditorDiv.appendChild(this.editorFrame);
      -950 		
      -951 		var doc = this.editorFrame.contentWindow.document;
      -952 		if(xq.Browser.isTrident) doc.designMode = 'On';
      -953 		
      -954 		doc.open();
      -955 		doc.write('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">');
      -956 		doc.write('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ko">');
      -957 		doc.write('<head>');
      -958 		
      -959 		// it is needed to force href of pasted content to be an absolute url
      -960 		if(!xq.Browser.isTrident) doc.write('<base href="./" />');
      -961 		
      -962 		doc.write('<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />');
      -963 		doc.write('<title>XQuared</title>');
      -964 		if(this.config.changeCursorOnLink) doc.write('<style>.xed a {cursor: pointer !important;}</style>');
      -965 		doc.write('</head>');
      -966 		doc.write('<body><p>' + this.rdom.makePlaceHolderString() + '</p></body>');
      -967 		doc.write('</html>');
      -968 		doc.close();
      -969 		
      -970 		this.editorWin = this.editorFrame.contentWindow;
      -971 		this.editorDoc = this.editorWin.document;
      -972 		this.editorBody = this.editorDoc.body;
      -973 		this.editorBody.className = "xed";
      -974 		
      -975 		// it is needed to fix IE6 horizontal scrollbar problem
      -976 		if(xq.Browser.isIE6) {
      -977 			this.editorDoc.documentElement.style.overflowY='auto';
      -978 			this.editorDoc.documentElement.style.overflowX='hidden';
      -979 		}
      -980 		
      -981 		this.rdom.setWin(this.editorWin);
      -982 		this.rdom.setRoot(this.editorBody);
      -983 		this.validator = xq.Validator.createInstance(this.doc.location.href, this.config.urlValidationMode, this.config.allowedTags, this.config.allowedAttributes);
      -984 		
      -985 		// hook onsubmit of form
      -986 		if(this.config.automaticallyHookSubmitEvent && this.contentElement.nodeName == 'TEXTAREA' && this.contentElement.form) {
      -987 			var original = this.contentElement.form.onsubmit;
      -988 			
      -989 			this.contentElement.form.onsubmit = function() {
      -990 				this.contentElement.value = this.getCurrentContent(true);
      -991 				if(original) {
      -992 					return original();
      -993 				} else {
      -994 					return true;
      -995 				}
      -996 			}.bind(this);
      -997 		}
      -998 	},
      -999 	
      -1000 	_addStyleRule: function(selector, rule) {
      -1001 		if(!this.dynamicStyle) {
      -1002 			if(xq.Browser.isTrident) {
      -1003 			    this.dynamicStyle = this.doc.createStyleSheet();
      -1004 			} else {
      -1005 	    		var style = this.doc.createElement('style');
      -1006 	    		this.doc.body.appendChild(style);
      -1007 		    	this.dynamicStyle = $A(this.doc.styleSheets).last();
      -1008 			}
      -1009 		}
      -1010 		
      -1011 		if(xq.Browser.isTrident) {
      -1012 			this.dynamicStyle.addRule(selector, rule);
      -1013 		} else {
      -1014 	    	this.dynamicStyle.insertRule(selector + " {" + rule + "}", this.dynamicStyle.cssRules.length);
      -1015     	}
      -1016 	},
      -1017 	
      -1018 	_generateDefaultToolbar: function() {
      -1019 		// override image path
      -1020 		this._addStyleRule(".xquared div.toolbar", "background-image: url(" + this.config.imagePathForDefaultToobar + "toolbarBg.gif)");
      -1021 		this._addStyleRule(".xquared ul.buttons li", "background-image: url(" + this.config.imagePathForDefaultToobar + "toolbarButtonBg.gif)");
      -1022 		this._addStyleRule(".xquared ul.buttons li.xq_separator", "background-image: url(" + this.config.imagePathForDefaultToobar + "toolbarSeparator.gif)");
      -1023 		
      -1024 		// outmost container
      -1025 		var container = this.doc.createElement('div');
      -1026 		container.className = 'toolbar';
      -1027 		
      -1028 		// button container
      -1029 		var buttons = this.doc.createElement('ul');
      -1030 		buttons.className = 'buttons';
      -1031 		container.appendChild(buttons);
      -1032 		
      -1033 		// Generate buttons from map and append it to button container
      -1034 		var cancelMousedown = function(e) {Event.stop(e); return false};
      -1035 		var map = this.config.defaultToolbarButtonMap;
      -1036 		for(var i = 0; i < map.length; i++) {
      -1037 			for(var j = 0; j < map[i].length; j++) {
      -1038 				var buttonConfig = map[i][j];
      -1039 
      -1040 				var li = this.doc.createElement('li');
      -1041 				buttons.appendChild(li);
      -1042 				li.className = buttonConfig.className;
      -1043 				
      -1044 				var span = this.doc.createElement('span');
      -1045 				li.appendChild(span);
      -1046 				
      -1047 				var a = this.doc.createElement('a');
      -1048 				span.appendChild(a);
      -1049 				a.href = '#';
      -1050 				a.title = buttonConfig.title;
      -1051 				a.handler = buttonConfig.handler;
      -1052 				a.xed = this;
      -1053 				Event.observe(a, 'mousedown', cancelMousedown);
      -1054 				Event.observe(a, 'click', function(e) {
      -1055 					var xed = this.xed;
      -1056 					
      -1057 					if($(this.parentNode).hasClassName('disabled') || xed.toolbarContainer.hasClassName('disabled')) {
      -1058 						Event.stop(e);
      -1059 						return false;
      -1060 					}
      -1061 					
      -1062 					if(xq.Browser.isTrident) xed.focus();
      -1063 					
      -1064 					var handler = this.handler;
      -1065 					var stop = (typeof handler == "function") ? handler(xed) : eval(handler);
      -1066 					if(stop) {
      -1067 						Event.stop(e);
      -1068 						return false;
      -1069 					} else {
      -1070 						return true;
      -1071 					}
      -1072 				}.bind(a));
      -1073 				
      -1074 				var img = this.doc.createElement('img');
      -1075 				a.appendChild(img);
      -1076 				img.src = this.config.imagePathForDefaultToobar + buttonConfig.className + '.gif';
      -1077 
      -1078 				if(j == 0 && i != 0) li.className += ' xq_separator';
      -1079 			}
      -1080 		}
      -1081 		
      -1082 		return container;
      -1083 	},
      -1084 	
      -1085 	
      -1086 	
      -1087 	/////////////////////////////////////////////
      -1088 	// Event Management
      -1089 	
      -1090 	_registerEventHandlers: function() {
      -1091 		var events = ['keydown', 'click', 'keyup', 'mouseup', 'contextmenu', 'scroll'];
      -1092 		
      -1093 		if(xq.Browser.isTrident && this.config.changeCursorOnLink) events.push('mousemove');
      -1094 		if(xq.Browser.isMac && xq.Browser.isGecko) events.push('keypress');
      -1095 		
      -1096 		for(var i = 0; i < events.length; i++) {
      -1097 			Event.observe(this.getDoc(), events[i], this._handleEvent.bindAsEventListener(this));
      -1098 		}
      -1099 	},
      -1100 	
      -1101 	_handleEvent: function(e) {
      -1102 		this._fireOnBeforeEvent(this, e);
      -1103 		
      -1104 		var stop = false;
      -1105 		
      -1106 		var modifiedByCorrection = false;
      -1107 		
      -1108 		if(e.type == 'mousemove' && this.config.changeCursorOnLink) {
      -1109 			// Trident only
      -1110 			var link = !!this.rdom.getParentElementOf(e.srcElement, ["A"]);
      -1111 			if(this.editorBody.contentEditable != link && !this.rdom.hasSelection()) this.editorBody.contentEditable = !link;
      -1112 		} else if(e.type == 'click' && e.button == 0 && this.config.enableLinkClick) {
      -1113 			var a = this.rdom.getParentElementOf(e.target || e.srcElement, ["A"]);
      -1114 			if(a) stop = this.handleClick(e, a);
      -1115 		} else if(e.type == (xq.Browser.isMac && xq.Browser.isGecko ? "keypress" : "keydown")) {
      -1116 			var undoPerformed = false;
      -1117 			
      -1118 			modifiedByCorrection = this.rdom.correctParagraph();
      -1119 			for(var key in this.config.shortcuts) {
      -1120 				if(!this.config.shortcuts[key].event.matches(e)) continue;
      -1121 				
      -1122 				var handler = this.config.shortcuts[key].handler;
      -1123 				var xed = this;
      -1124 				stop = (typeof handler == "function") ? handler(this) : eval(handler);
      -1125 				
      -1126 				if(key == "undo") undoPerformed = true;
      -1127 			}
      -1128 		} else if(["mouseup", "keyup"].include(e.type)) {
      -1129 			modifiedByCorrection = this.rdom.correctParagraph();
      -1130 		} else if(["contextmenu"].include(e.type)) {
      -1131 			this._handleContextMenu(e);
      -1132 		}
      -1133 		
      -1134 		if(stop) Event.stop(e);
      -1135 		
      -1136 		this._fireOnCurrentContentChanged(this);
      -1137 		this._fireOnAfterEvent(this, e);
      -1138 		
      -1139 		if(!undoPerformed && !modifiedByCorrection) this.editHistory.onEvent(e);
      -1140 		
      -1141 		return !stop;
      -1142 	},
      -1143 
      -1144 	/**
      -1145 	 * TODO: remove dup with handleAutocompletion
      -1146 	 */
      -1147 	handleAutocorrection: function() {
      -1148 		var block = this.rdom.getCurrentBlockElement();
      -1149 		
      -1150 		// TODO: use complete unescape algorithm
      -1151 		var text = this.rdom.getInnerText(block).replace(/ /gi, " ");
      -1152 		
      -1153 		var acs = this.config.autocorrections;
      -1154 		var performed = false;
      -1155 		
      -1156 		var stop = false;
      -1157 		for(var key in acs) {
      -1158 			var ac = acs[key];
      -1159 			if(ac.criteria(text)) {
      -1160 				try {
      -1161 					this.editHistory.onCommand();
      -1162 					this.editHistory.disable();
      -1163 					if(typeof ac.handler == "String") {
      -1164 						var xed = this;
      -1165 						var rdom = this.rdom;
      -1166 						eval(ac.handler);
      -1167 					} else {
      -1168 						stop = ac.handler(this, this.rdom, block, text);
      -1169 					}
      -1170 					this.editHistory.enable();
      -1171 				} catch(ignored) {}
      -1172 				
      -1173 				block = this.rdom.getCurrentBlockElement();
      -1174 				text = this.rdom.getInnerText(block);
      -1175 				
      -1176 				performed = true;
      -1177 				if(stop) break;
      -1178 			}
      -1179 		}
      -1180 		
      -1181 		return stop;
      -1182 	},
      -1183 	
      -1184 	/**
      -1185 	 * TODO: remove dup with handleAutocorrection
      -1186 	 */
      -1187 	handleAutocompletion: function() {
      -1188 		var acs = $H(this.config.autocompletions);
      -1189 		if(acs.size() == 0) return;
      -1190 
      -1191 		if(this.rdom.hasSelection()) {
      -1192 			var text = this.rdom.getSelectionAsText();
      -1193 			this.rdom.deleteSelection();
      -1194 			var wrapper = this.rdom.insertNode(this.rdom.createElement("SPAN"));
      -1195 			wrapper.innerHTML = text;
      -1196 			
      -1197 			var marker = this.rdom.pushMarker();
      -1198 
      -1199 			var filtered = 
      -1200 				acs.map(function(pair) {
      -1201 					return [pair.key, pair.value.criteria(text)];
      -1202 				}.bind(this)).findAll(function(elem) {
      -1203 					return elem[1] != -1;
      -1204 				}).sortBy(function(elem) {
      -1205 					return elem[1];
      -1206 				});
      -1207 			
      -1208 			if(filtered.length == 0) {
      -1209 				this.rdom.popMarker(true);
      -1210 				return;
      -1211 			}
      -1212 			var ac = acs.get(filtered[0][0]);
      -1213 			
      -1214 			this.editHistory.disable();
      -1215 		} else {
      -1216 			var marker = this.rdom.pushMarker();
      -1217 			
      -1218 			var filtered = 
      -1219 				acs.map(function(pair) {
      -1220 					return [pair.key, this.rdom.testSmartWrap(marker, pair.value.criteria).textIndex];
      -1221 				}.bind(this)).findAll(function(elem) {
      -1222 					return elem[1] != -1;
      -1223 				}).sortBy(function(elem) {
      -1224 					return elem[1];
      -1225 				});
      -1226 			
      -1227 			if(filtered.length == 0) {
      -1228 				this.rdom.popMarker(true);
      -1229 				return;
      -1230 			}
      -1231 			
      -1232 			var ac = acs.get(filtered[0][0]);
      -1233 			
      -1234 			this.editHistory.disable();
      -1235 			
      -1236 			var wrapper = this.rdom.smartWrap(marker, "SPAN", ac.criteria);
      -1237 		}
      -1238 		
      -1239 		var block = this.rdom.getCurrentBlockElement();
      -1240 		
      -1241 		// TODO: use complete unescape algorithm
      -1242 		var text = this.rdom.getInnerText(wrapper).replace(/ /gi, " ");
      -1243 		
      -1244 		try {
      -1245 			// call handler
      -1246 			if(typeof ac.handler == "String") {
      -1247 				var xed = this;
      -1248 				var rdom = this.rdom;
      -1249 				eval(ac.handler);
      -1250 			} else {
      -1251 				ac.handler(this, this.rdom, block, wrapper, text);
      -1252 			}
      -1253 		} catch(ignored) {}
      -1254 		
      -1255 		try {
      -1256 			this.rdom.unwrapElement(wrapper);
      -1257 		} catch(ignored) {}
      -1258 
      -1259 		
      -1260 		if(this.rdom.isEmptyBlock(block)) this.rdom.correctEmptyElement(block);
      -1261 		
      -1262 		this.editHistory.enable();
      -1263 		this.editHistory.onCommand();
      -1264 		
      -1265 		this.rdom.popMarker(true);
      -1266 	},
      -1267 
      -1268 	/**
      -1269 	 * Handles click event
      -1270 	 *
      -1271 	 * @param {Event} e click event
      -1272 	 * @param {Element} target target element(usually has A tag)
      -1273 	 */
      -1274 	handleClick: function(e, target) {
      -1275 		var href = decodeURI(target.href);
      -1276 		if(!xq.Browser.isTrident) {
      -1277 			if(!e.ctrlKey && !e.shiftKey && e.button != 1) {
      -1278 				window.location.href = href;
      -1279 				return true;
      -1280 			}
      -1281 		} else {
      -1282 			if(e.shiftKey) {
      -1283 				window.open(href, "_blank");
      -1284 			} else {
      -1285 				window.location.href = href;
      -1286 			}
      -1287 			return true;
      -1288 		}
      -1289 		
      -1290 		return false;
      -1291 	},
      -1292 
      -1293 	/**
      -1294 	 * Show link dialog
      -1295 	 *
      -1296 	 * TODO: should support modify/unlink
      -1297 	 */
      -1298 	handleLink: function() {
      -1299 		var text = this.rdom.getSelectionAsText() || '';
      -1300 		var dialog = new xq.controls.FormDialog(
      -1301 			this,
      -1302 			xq.ui_templates.basicLinkDialog,
      -1303 			function(dialog) {
      -1304 				if(text) {
      -1305 					dialog.form.text.value = text;
      -1306 					dialog.form.url.focus();
      -1307 					dialog.form.url.select();
      -1308 				}
      -1309 			},
      -1310 			function(data) {
      -1311 				this.focus();
      -1312 				
      -1313 				if(xq.Browser.isTrident) {
      -1314 					var rng = this.rdom.rng();
      -1315 					rng.moveToBookmark(bm);
      -1316 					rng.select();
      -1317 				}
      -1318 				
      -1319 				if(!data) return;
      -1320 				this.handleInsertLink(false, data.url, data.text, data.text);
      -1321 			}.bind(this)
      -1322 		);
      -1323 		
      -1324 		if(xq.Browser.isTrident) var bm = this.rdom.rng().getBookmark();
      -1325 		
      -1326 		dialog.show({position: 'centerOfEditor'});
      -1327 		
      -1328 		return true;
      -1329 	},
      -1330 	
      -1331 	/**
      -1332 	 * Inserts link or apply link into selected area
      -1333 	 * 
      -1334 	 * @param {boolean} autoSelection if set true and there's no selection, automatically select word to link(if possible)
      -1335 	 * @param {String} url url
      -1336 	 * @param {String} title title of link
      -1337 	 * @param {String} text text of link. If there's a selection(manually or automatically), it will be replaced with this text
      -1338 	 *
      -1339 	 * @returns {Element} created element
      -1340 	 */
      -1341 	handleInsertLink: function(autoSelection, url, title, text) {
      -1342 		if(autoSelection && !this.rdom.hasSelection()) {
      -1343 			var marker = this.rdom.pushMarker();
      -1344 			var a = this.rdom.smartWrap(marker, "A", function(text) {
      -1345 				var index = text.lastIndexOf(" ");
      -1346 				return index == -1 ? index : index + 1;
      -1347 			});
      -1348 			a.href = url;
      -1349 			a.title = title;
      -1350 			if(text) {
      -1351 				a.innerHTML = ""
      -1352 				a.appendChild(this.rdom.createTextNode(text));
      -1353 			} else if(!a.hasChildNodes()) {
      -1354 				this.rdom.deleteNode(a);
      -1355 			}
      -1356 			this.rdom.popMarker(true);
      -1357 		} else {
      -1358 			text = text || (this.rdom.hasSelection() ? this.rdom.getSelectionAsText() : null);
      -1359 			if(!text) return;
      -1360 			
      -1361 			this.rdom.deleteSelection();
      -1362 			
      -1363 			var a = this.rdom.createElement('A');
      -1364 			a.href = url;
      -1365 			a.title = title;
      -1366 			a.appendChild(this.rdom.createTextNode(text));
      -1367 			this.rdom.insertNode(a);
      -1368 		}
      -1369 		
      -1370 		var historyAdded = this.editHistory.onCommand();
      -1371 		this._fireOnCurrentContentChanged(this);
      -1372 		
      -1373 		return true;
      -1374 	},
      -1375 	
      -1376 	/**
      -1377 	 * Called when enter key pressed.
      -1378 	 *
      -1379 	 * @param {boolean} skipAutocorrection if set true, skips autocorrection
      -1380 	 * @param {boolean} forceInsertParagraph if set true, inserts paragraph
      -1381 	 */
      -1382 	handleEnter: function(skipAutocorrection, forceInsertParagraph) {
      -1383 		// If it has selection, perform default action.
      -1384 		if(this.rdom.hasSelection()) return false;
      -1385 		
      -1386 		// Perform autocorrection
      -1387 		if(!skipAutocorrection && this.handleAutocorrection()) return true;
      -1388 		
      -1389 		var atEmptyBlock = this.rdom.isCaretAtEmptyBlock();
      -1390 		var atStart = atEmptyBlock || this.rdom.isCaretAtBlockStart();
      -1391 		var atEnd = atEmptyBlock || (!atStart && this.rdom.isCaretAtBlockEnd());
      -1392 		var atEdge = atEmptyBlock || atStart || atEnd;
      -1393 		
      -1394 		if(!atEdge) {
      -1395 			var block = this.rdom.getCurrentBlockElement();
      -1396 			var marker = this.rdom.pushMarker();
      -1397 			
      -1398 			if(this.rdom.isFirstLiWithNestedList(block) && !forceInsertParagraph) {
      -1399 				var parent = block.parentNode;
      -1400 				this.rdom.unwrapElement(block);
      -1401 				block = parent;
      -1402 			} else if(block.nodeName != "LI" && this.rdom.tree.isBlockContainer(block)) {
      -1403 				block = this.rdom.wrapAllInlineOrTextNodesAs("P", block, true).first();
      -1404 			}
      -1405 			this.rdom.splitElementUpto(marker, block);
      -1406 			
      -1407 			this.rdom.popMarker(true);
      -1408 		} else if(atEmptyBlock) {
      -1409 			this._handleEnterAtEmptyBlock();
      -1410 		} else {
      -1411 			this._handleEnterAtEdge(atStart, forceInsertParagraph);
      -1412 		}
      -1413 		
      -1414 		return true;
      -1415 	},
      -1416 	
      -1417 	/**
      -1418 	 * Moves current block upward or downward
      -1419 	 *
      -1420 	 * @param {boolean} up moves current block upward
      -1421 	 */
      -1422 	handleMoveBlock: function(up) {
      -1423 		var block = this.rdom.moveBlock(this.rdom.getCurrentBlockElement(), up);
      -1424 		if(block) {
      -1425 			this.rdom.selectElement(block, false);
      -1426 			block.scrollIntoView(false);
      -1427 			
      -1428 			var historyAdded = this.editHistory.onCommand();
      -1429 			this._fireOnCurrentContentChanged(this);
      -1430 		}
      -1431 		return true;
      -1432 	},
      -1433 	
      -1434 	/**
      -1435 	 * Called when tab key pressed
      -1436 	 */
      -1437 	handleTab: function() {
      -1438 		var hasSelection = this.rdom.hasSelection();
      -1439 		var table = this.rdom.getParentElementOf(this.rdom.getCurrentBlockElement(), ["TABLE"]);
      -1440 		
      -1441 		if(hasSelection) {
      -1442 			this.handleIndent();
      -1443 		} else if (table && table.className == "datatable") {
      -1444 			this.handleMoveToNextCell();
      -1445 		} else if (this.rdom.isCaretAtBlockStart()) {
      -1446 			this.handleIndent();
      -1447 		} else {
      -1448 			this.handleInsertTab();
      -1449 		}
      -1450 
      -1451 		return true;
      -1452 	},
      -1453 	
      -1454 	/**
      -1455 	 * Called when shift+tab key pressed
      -1456 	 */
      -1457 	handleShiftTab: function() {
      -1458 		var hasSelection = this.rdom.hasSelection();
      -1459 		var table = this.rdom.getParentElementOf(this.rdom.getCurrentBlockElement(), ["TABLE"]);
      -1460 		
      -1461 		if(hasSelection) {
      -1462 			this.handleOutdent();
      -1463 		} else if (table && table.className == "datatable") {
      -1464 			this.handleMoveToPreviousCell();
      -1465 		} else {
      -1466 			this.handleOutdent();
      -1467 		}
      -1468 		
      -1469 		return true;
      -1470 	},
      -1471 	
      -1472 	/**
      -1473 	 * Inserts three non-breaking spaces
      -1474 	 */
      -1475 	handleInsertTab: function() {
      -1476 		this.rdom.insertHtml(' ');
      -1477 		this.rdom.insertHtml(' ');
      -1478 		this.rdom.insertHtml(' ');
      -1479 		
      -1480 		return true;
      -1481 	},
      -1482 	
      -1483 	/**
      -1484 	 * Called when delete key pressed
      -1485 	 */
      -1486 	handleDelete: function() {
      -1487 		if(this.rdom.hasSelection() || !this.rdom.isCaretAtBlockEnd()) return false;
      -1488 		return this._handleMerge(true);
      -1489 	},
      -1490 	
      -1491 	/**
      -1492 	 * Called when backspace key pressed
      -1493 	 */
      -1494 	handleBackspace: function() {
      -1495 		if(this.rdom.hasSelection() || !this.rdom.isCaretAtBlockStart()) return false;
      -1496 		return this._handleMerge(false);
      -1497 	},
      -1498 	
      -1499 	_handleMerge: function(withNext) {
      -1500 		var block = this.rdom.getCurrentBlockElement();
      -1501 		
      -1502 		// save caret position;
      -1503 		var marker = this.rdom.pushMarker();
      -1504 		
      -1505 		// perform merge
      -1506 		var merged = this.rdom.mergeElement(block, withNext, withNext);
      -1507 		if(!merged && !withNext) this.rdom.extractOutElementFromParent(block);
      -1508 		
      -1509 		// restore caret position
      -1510 		this.rdom.popMarker(true);
      -1511 		if(merged) this.rdom.correctEmptyElement(merged);
      -1512 		
      -1513 		var historyAdded = this.editHistory.onCommand();
      -1514 		this._fireOnCurrentContentChanged(this);
      -1515 		
      -1516 		return !!merged;
      -1517 	},
      -1518 	
      -1519 	/**
      -1520 	 * (in table) Moves caret to the next cell
      -1521 	 */
      -1522 	handleMoveToNextCell: function() {
      -1523 		this._handleMoveToCell("next");
      -1524 	},
      -1525 
      -1526 	/**
      -1527 	 * (in table) Moves caret to the previous cell
      -1528 	 */
      -1529 	handleMoveToPreviousCell: function() {
      -1530 		this._handleMoveToCell("prev");
      -1531 	},
      -1532 
      -1533 	/**
      -1534 	 * (in table) Moves caret to the above cell
      -1535 	 */
      -1536 	handleMoveToAboveCell: function() {
      -1537 		this._handleMoveToCell("above");
      -1538 	},
      -1539 
      -1540 	/**
      -1541 	 * (in table) Moves caret to the below cell
      -1542 	 */
      -1543 	handleMoveToBelowCell: function() {
      -1544 		this._handleMoveToCell("below");
      -1545 	},
      -1546 
      -1547 	_handleMoveToCell: function(dir) {
      -1548 		var block = this.rdom.getCurrentBlockElement();
      -1549 		var cell = this.rdom.getParentElementOf(block, ["TD", "TH"]);
      -1550 		var table = this.rdom.getParentElementOf(cell, ["TABLE"]);
      -1551 		var rtable = new xq.RichTable(this.rdom, table);
      -1552 		var target = null;
      -1553 		
      -1554 		if(["next", "prev"].include(dir)) {
      -1555 			var toNext = dir == "next";
      -1556 			target = toNext ? rtable.getNextCellOf(cell) : rtable.getPreviousCellOf(cell);
      -1557 		} else {
      -1558 			var toBelow = dir == "below";
      -1559 			target = toBelow ? rtable.getBelowCellOf(cell) : rtable.getAboveCellOf(cell);
      -1560 		}
      -1561 
      -1562 		if(!target) {
      -1563 			var finder = function(node) {return !['TD', 'TH'].include(node.nodeName) && this.tree.isBlock(node) && !this.tree.hasBlocks(node);}.bind(this.rdom);
      -1564 			var exitCondition = function(node) {return this.tree.isBlock(node) && !this.tree.isDescendantOf(this.getRoot(), node)}.bind(this.rdom);
      -1565 			
      -1566 			target = (toNext || toBelow) ? 
      -1567 				this.rdom.tree.findForward(cell, finder, exitCondition) :
      -1568 				this.rdom.tree.findBackward(table, finder, exitCondition);
      -1569 		}
      -1570 		
      -1571 		if(target) this.rdom.placeCaretAtStartOf(target);
      -1572 	},
      -1573 	
      -1574 	/**
      -1575 	 * Applies STRONG tag
      -1576 	 */
      -1577 	handleStrongEmphasis: function() {
      -1578 		this.rdom.applyStrongEmphasis();
      -1579 		
      -1580 		var historyAdded = this.editHistory.onCommand();
      -1581 		this._fireOnCurrentContentChanged(this);
      -1582 		
      -1583 		return true;
      -1584 	},
      -1585 	
      -1586 	/**
      -1587 	 * Applies EM tag
      -1588 	 */
      -1589 	handleEmphasis: function() {
      -1590 		this.rdom.applyEmphasis();
      -1591 		
      -1592 		var historyAdded = this.editHistory.onCommand();
      -1593 		this._fireOnCurrentContentChanged(this);
      -1594 		
      -1595 		return true;
      -1596 	},
      -1597 	
      -1598 	/**
      -1599 	 * Applies EM.underline tag
      -1600 	 */
      -1601 	handleUnderline: function() {
      -1602 		this.rdom.applyUnderline();
      -1603 		
      -1604 		var historyAdded = this.editHistory.onCommand();
      -1605 		this._fireOnCurrentContentChanged(this);
      -1606 		
      -1607 		return true;
      -1608 	},
      -1609 	
      -1610 	/**
      -1611 	 * Applies SPAN.strike tag
      -1612 	 */
      -1613 	handleStrike: function() {
      -1614 		this.rdom.applyStrike();
      -1615 
      -1616 		var historyAdded = this.editHistory.onCommand();
      -1617 		this._fireOnCurrentContentChanged(this);
      -1618 
      -1619 		return true;
      -1620 	},
      -1621 	
      -1622 	/**
      -1623 	 * Removes all style
      -1624 	 */
      -1625 	handleRemoveFormat: function() {
      -1626 		this.rdom.applyRemoveFormat();
      -1627 
      -1628 		var historyAdded = this.editHistory.onCommand();
      -1629 		this._fireOnCurrentContentChanged(this);
      -1630 
      -1631 		return true;
      -1632 	},
      -1633 	
      -1634 	/**
      -1635 	 * Inserts table
      -1636 	 *
      -1637 	 * @param {Number} cols number of columns
      -1638 	 * @param {Number} rows number of rows
      -1639 	 * @param {String} headerPosition position of THs. "T" or "L" or "TL". "T" means top, "L" means left.
      -1640 	 */
      -1641 	handleTable: function(cols, rows, headerPositions) {
      -1642 		var cur = this.rdom.getCurrentBlockElement();
      -1643 		if(this.rdom.getParentElementOf(cur, ["TABLE"])) return true;
      -1644 		
      -1645 		var rtable = xq.RichTable.create(this.rdom, cols, rows, headerPositions);
      -1646 		if(this.rdom.tree.isBlockContainer(cur)) {
      -1647 			var wrappers = this.rdom.wrapAllInlineOrTextNodesAs("P", cur, true);
      -1648 			cur = wrappers.last();
      -1649 		}
      -1650 		var tableDom = this.rdom.insertNodeAt(rtable.getDom(), cur, "after");
      -1651 		this.rdom.placeCaretAtStartOf(rtable.getCellAt(0, 0));
      -1652 		
      -1653 		if(this.rdom.isEmptyBlock(cur)) this.rdom.deleteNode(cur, true);
      -1654 		
      -1655 		var historyAdded = this.editHistory.onCommand();
      -1656 		this._fireOnCurrentContentChanged(this);
      -1657 		
      -1658 		return true;
      -1659 	},
      -1660 	
      -1661 	handleInsertNewRowAt: function(where) {
      -1662 		var cur = this.rdom.getCurrentBlockElement();
      -1663 		var tr = this.rdom.getParentElementOf(cur, ["TR"]);
      -1664 		if(!tr) return true;
      -1665 		
      -1666 		var table = this.rdom.getParentElementOf(tr, ["TABLE"]);
      -1667 		var rtable = new xq.RichTable(this.rdom, table);
      -1668 		var row = rtable.insertNewRowAt(tr, where);
      -1669 		
      -1670 		this.rdom.placeCaretAtStartOf(row.cells[0]);
      -1671 		return true;
      -1672 	},
      -1673 	handleInsertNewColumnAt: function(where) {
      -1674 		var cur = this.rdom.getCurrentBlockElement();
      -1675 		var td = this.rdom.getParentElementOf(cur, ["TD"], true);
      -1676 		if(!td) return true;
      -1677 		
      -1678 		var table = this.rdom.getParentElementOf(td, ["TABLE"]);
      -1679 		var rtable = new xq.RichTable(this.rdom, table);
      -1680 		rtable.insertNewCellAt(td, where);
      -1681 		
      -1682 		this.rdom.placeCaretAtStartOf(cur);
      -1683 		return true;
      -1684 	},
      -1685 	
      -1686 	handleDeleteRow: function() {
      -1687 		var cur = this.rdom.getCurrentBlockElement();
      -1688 		var tr = this.rdom.getParentElementOf(cur, ["TR"]);
      -1689 		if(!tr) return true;
      -1690 
      -1691 		var table = this.rdom.getParentElementOf(tr, ["TABLE"]);
      -1692 		var rtable = new xq.RichTable(this.rdom, table);
      -1693 		var blockToMove = rtable.deleteRow(tr);
      -1694 		
      -1695 		this.rdom.placeCaretAtStartOf(blockToMove);
      -1696 		return true;
      -1697 	},
      -1698 	
      -1699 	handleDeleteColumn: function() {
      -1700 		var cur = this.rdom.getCurrentBlockElement();
      -1701 		var td = this.rdom.getParentElementOf(cur, ["TD"], true);
      -1702 		if(!td) return true;
      -1703 
      -1704 		var table = this.rdom.getParentElementOf(td, ["TABLE"]);
      -1705 		var rtable = new xq.RichTable(this.rdom, table);
      -1706 		rtable.deleteCell(td);
      -1707 
      -1708 		return true;
      -1709 	},
      -1710 	
      -1711 	/**
      -1712 	 * Performs block indentation
      -1713 	 */
      -1714 	handleIndent: function() {
      -1715 		if(this.rdom.hasSelection()) {
      -1716 			var blocks = this.rdom.getBlockElementsAtSelectionEdge(true, true);
      -1717 			if(blocks.first() != blocks.last()) {
      -1718 				var affected = this.rdom.indentElements(blocks.first(), blocks.last());
      -1719 				this.rdom.selectBlocksBetween(affected.first(), affected.last());
      -1720 				
      -1721 				var historyAdded = this.editHistory.onCommand();
      -1722 				this._fireOnCurrentContentChanged(this);
      -1723 				
      -1724 				return true;
      -1725 			}
      -1726 		}
      -1727 		
      -1728 		var block = this.rdom.getCurrentBlockElement();
      -1729 		var affected = this.rdom.indentElement(block);
      -1730 		
      -1731 		if(affected) {
      -1732 			this.rdom.placeCaretAtStartOf(affected);
      -1733 			
      -1734 			var historyAdded = this.editHistory.onCommand();
      -1735 			this._fireOnCurrentContentChanged(this);
      -1736 		}
      -1737 		
      -1738 		return true;
      -1739 	},
      -1740 
      -1741 	/**
      -1742 	 * Performs block outdentation
      -1743 	 */
      -1744 	handleOutdent: function() {
      -1745 		if(this.rdom.hasSelection()) {
      -1746 			var blocks = this.rdom.getBlockElementsAtSelectionEdge(true, true);
      -1747 			if(blocks.first() != blocks.last()) {
      -1748 				var affected = this.rdom.outdentElements(blocks.first(), blocks.last());
      -1749 				this.rdom.selectBlocksBetween(affected.first(), affected.last());
      -1750 				
      -1751 				var historyAdded = this.editHistory.onCommand();
      -1752 				this._fireOnCurrentContentChanged(this);
      -1753 				
      -1754 				return true;
      -1755 			}
      -1756 		}
      -1757 		
      -1758 		var block = this.rdom.getCurrentBlockElement();
      -1759 		var affected = this.rdom.outdentElement(block);
      -1760 		
      -1761 		if(affected) {
      -1762 			this.rdom.placeCaretAtStartOf(affected);
      -1763 
      -1764 			var historyAdded = this.editHistory.onCommand();
      -1765 			this._fireOnCurrentContentChanged(this);
      -1766 		}
      -1767 		
      -1768 		return true;
      -1769 	},
      -1770 	
      -1771 	/**
      -1772 	 * Applies list.
      -1773 	 *
      -1774 	 * @param {String} type "UL" or "OL" or "CODE". CODE generates OL.code
      -1775 	 */
      -1776 	handleList: function(type) {
      -1777 		if(this.rdom.hasSelection()) {
      -1778 			var blocks = this.rdom.getBlockElementsAtSelectionEdge(true, true);
      -1779 			if(blocks.first() != blocks.last()) {
      -1780 				blocks = this.rdom.applyLists(blocks.first(), blocks.last(), type);
      -1781 			} else {
      -1782 				blocks[0] = blocks[1] = this.rdom.applyList(blocks.first(), type);
      -1783 			}
      -1784 			this.rdom.selectBlocksBetween(blocks.first(), blocks.last());
      -1785 		} else {
      -1786 			var block = this.rdom.applyList(this.rdom.getCurrentBlockElement(), type);
      -1787 			this.rdom.placeCaretAtStartOf(block);
      -1788 		}
      -1789 		var historyAdded = this.editHistory.onCommand();
      -1790 		this._fireOnCurrentContentChanged(this);
      -1791 		
      -1792 		return true;
      -1793 	},
      -1794 	
      -1795 	/**
      -1796 	 * Applies justification
      -1797 	 *
      -1798 	 * @param {String} dir "left", "center", "right" or "both"
      -1799 	 */
      -1800 	handleJustify: function(dir) {
      -1801 		var block = this.rdom.getCurrentBlockElement();
      -1802 		var dir = (dir == "left" || dir == "both") && (block.style.textAlign == "left" || block.style.textAlign == "") ? "both" : dir;
      -1803 		
      -1804 		if(this.rdom.hasSelection()) {
      -1805 			var blocks = this.rdom.getSelectedBlockElements();
      -1806 			this.rdom.justifyBlocks(blocks, dir);
      -1807 			this.rdom.selectBlocksBetween(blocks.first(), blocks.last());
      -1808 		} else {
      -1809 			this.rdom.justifyBlock(block, dir);
      -1810 		}
      -1811 		var historyAdded = this.editHistory.onCommand();
      -1812 		this._fireOnCurrentContentChanged(this);
      -1813 		
      -1814 		return true;
      -1815 	},
      -1816 	
      -1817 	/**
      -1818 	 * Removes current block element
      -1819 	 */
      -1820 	handleRemoveBlock: function() {
      -1821 		var block = this.rdom.getCurrentBlockElement();
      -1822 		var blockToMove = this.rdom.removeBlock(block);
      -1823 		this.rdom.placeCaretAtStartOf(blockToMove);
      -1824 		blockToMove.scrollIntoView(false);
      -1825 	},
      -1826 	
      -1827 	/**
      -1828 	 * Applies background color
      -1829 	 *
      -1830 	 * @param {String} color CSS color string
      -1831 	 */
      -1832 	handleBackgroundColor: function(color) {
      -1833 		if(color) {
      -1834 			this.rdom.applyBackgroundColor(color);
      -1835 
      -1836 			var historyAdded = this.editHistory.onCommand();
      -1837 			this._fireOnCurrentContentChanged(this);
      -1838 		} else {
      -1839 			var dialog = new xq.controls.FormDialog(
      -1840 				this,
      -1841 				xq.ui_templates.basicColorPickerDialog,
      -1842 				function(dialog) {},
      -1843 				function(data) {
      -1844 					this.focus();
      -1845 					
      -1846 					if(xq.Browser.isTrident) {
      -1847 						var rng = this.rdom.rng();
      -1848 						rng.moveToBookmark(bm);
      -1849 						rng.select();
      -1850 					}
      -1851 					
      -1852 					if(!data) return;
      -1853 					
      -1854 					this.handleBackgroundColor(data.color);
      -1855 				}.bind(this)
      -1856 			);
      -1857 			
      -1858 			if(xq.Browser.isTrident) var bm = this.rdom.rng().getBookmark();
      -1859 			
      -1860 			dialog.show({position: 'centerOfEditor'});
      -1861 		}
      -1862 		return true;
      -1863 	},
      -1864 	
      -1865 	/**
      -1866 	 * Applies foreground color
      -1867 	 *
      -1868 	 * @param {String} color CSS color string
      -1869 	 */
      -1870 	handleForegroundColor: function(color) {
      -1871 		if(color) {
      -1872 			this.rdom.applyForegroundColor(color);
      -1873 
      -1874 			var historyAdded = this.editHistory.onCommand();
      -1875 			this._fireOnCurrentContentChanged(this);
      -1876 		} else {
      -1877 			var dialog = new xq.controls.FormDialog(
      -1878 				this,
      -1879 				xq.ui_templates.basicColorPickerDialog,
      -1880 				function(dialog) {},
      -1881 				function(data) {
      -1882 					this.focus();
      -1883 					
      -1884 					if(xq.Browser.isTrident) {
      -1885 						var rng = this.rdom.rng();
      -1886 						rng.moveToBookmark(bm);
      -1887 						rng.select();
      -1888 					}
      -1889 					
      -1890 					if(!data) return;
      -1891 					
      -1892 					this.handleForegroundColor(data.color);
      -1893 				}.bind(this)
      -1894 			);
      -1895 			
      -1896 			if(xq.Browser.isTrident) var bm = this.rdom.rng().getBookmark();
      -1897 			
      -1898 			dialog.show({position: 'centerOfEditor'});
      -1899 		}
      -1900 		return true;
      -1901 	},
      -1902 
      -1903 	/**
      -1904 	 * Applies superscription
      -1905 	 */	
      -1906 	handleSuperscription: function() {
      -1907 		this.rdom.applySuperscription();
      -1908 
      -1909 		var historyAdded = this.editHistory.onCommand();
      -1910 		this._fireOnCurrentContentChanged(this);
      -1911 
      -1912 		return true;
      -1913 	},
      -1914 	
      -1915 	/**
      -1916 	 * Applies subscription
      -1917 	 */	
      -1918 	handleSubscription: function() {
      -1919 		this.rdom.applySubscription();
      -1920 
      -1921 		var historyAdded = this.editHistory.onCommand();
      -1922 		this._fireOnCurrentContentChanged(this);
      -1923 
      -1924 		return true;
      -1925 	},
      -1926 	
      -1927 	/**
      -1928 	 * Change of wrap current block's tag
      -1929 	 */	
      -1930 	handleApplyBlock: function(tagName) {
      -1931 		if(this.rdom.hasSelection()) {
      -1932 			var blocks = this.rdom.getBlockElementsAtSelectionEdge(true, true);
      -1933 			if(blocks.first() != blocks.last()) {
      -1934 				var applied = this.rdom.applyTagIntoElements(tagName, blocks.first(), blocks.last());
      -1935 				this.rdom.selectBlocksBetween(applied.first(), applied.last());
      -1936 				
      -1937 				var historyAdded = this.editHistory.onCommand();
      -1938 				this._fireOnCurrentContentChanged(this);
      -1939 				
      -1940 				return true;
      -1941 			}
      -1942 		}
      -1943 		
      -1944 		var block = this.rdom.getCurrentBlockElement();
      -1945 		this.rdom.pushMarker();
      -1946 		var applied =
      -1947 			this.rdom.applyTagIntoElement(tagName, block) ||
      -1948 			block;
      -1949 		this.rdom.popMarker(true);
      -1950 
      -1951 		if(this.rdom.isEmptyBlock(applied)) {
      -1952 			this.rdom.correctEmptyElement(applied);
      -1953 			this.rdom.placeCaretAtStartOf(applied);
      -1954 		}
      -1955 		
      -1956 		var historyAdded = this.editHistory.onCommand();
      -1957 		this._fireOnCurrentContentChanged(this);
      -1958 		
      -1959 		return true;
      -1960 	},
      -1961 
      -1962 	/**
      -1963 	 * Inserts seperator (HR)
      -1964 	 */
      -1965 	handleSeparator: function() {
      -1966 		this.rdom.collapseSelection();
      -1967 		
      -1968 		var curBlock = this.rdom.getCurrentBlockElement();
      -1969 		var atStart = this.rdom.isCaretAtBlockStart();
      -1970 		if(this.rdom.tree.isBlockContainer(curBlock)) curBlock = this.rdom.wrapAllInlineOrTextNodesAs("P", curBlock, true)[0];
      -1971 		
      -1972 		this.rdom.insertNodeAt(this.rdom.createElement("HR"), curBlock, atStart ? "before" : "after");
      -1973 		this.rdom.placeCaretAtStartOf(curBlock);
      -1974 
      -1975 		// add undo history
      -1976 		var historyAdded = this.editHistory.onCommand();
      -1977 		this._fireOnCurrentContentChanged(this);
      -1978 		
      -1979 		return true;
      -1980 	},
      -1981 	
      -1982 	/**
      -1983 	 * Performs UNDO
      -1984 	 */
      -1985 	handleUndo: function() {
      -1986 		var performed = this.editHistory.undo();
      -1987 		this._fireOnCurrentContentChanged(this);
      -1988 		
      -1989 		var curBlock = this.rdom.getCurrentBlockElement();
      -1990 		if(!xq.Browser.isTrident && curBlock) {
      -1991 			curBlock.scrollIntoView(false);
      -1992 		}
      -1993 		return true;
      -1994 	},
      -1995 	
      -1996 	/**
      -1997 	 * Performs REDO
      -1998 	 */
      -1999 	handleRedo: function() {
      -2000 		var performed = this.editHistory.redo();
      -2001 		this._fireOnCurrentContentChanged(this);
      -2002 		
      -2003 		var curBlock = this.rdom.getCurrentBlockElement();
      -2004 		if(!xq.Browser.isTrident && curBlock) {
      -2005 			curBlock.scrollIntoView(false);
      -2006 		}
      -2007 		return true;
      -2008 	},
      -2009 	
      -2010 	
      -2011 	
      -2012 	_handleContextMenu: function(e) {
      -2013 		if (xq.Browser.isWebkit) {
      -2014 			if (e.metaKey || Event.isLeftClick(e)) return false;
      -2015 		} else if (e.shiftKey || e.ctrlKey || e.altKey) {
      -2016 			return false;
      -2017 		}
      -2018 		
      -2019 		var x=Event.pointerX(e);
      -2020 		var y=Event.pointerY(e);
      -2021 		var pos=Position.cumulativeOffset(this.getFrame());
      -2022 		x+=pos[0];
      -2023 		y+=pos[1];
      -2024 		this._contextMenuTargetElement = e.target || e.srcElement;
      -2025 		
      -2026 		//TODO: Safari on Windows doesn't work with context key(app key)
      -2027 		if (!x || !y || xq.Browser.isTrident) {
      -2028 			var pos = Position.cumulativeOffset(this._contextMenuTargetElement);
      -2029 			var posFrame = Position.cumulativeOffset(this.getFrame());
      -2030 			x = pos[0] + posFrame[0] - this.getDoc().documentElement.scrollLeft;
      -2031 			y = pos[1] + posFrame[1] - this.getDoc().documentElement.scrollTop;
      -2032 		}
      -2033 		
      -2034 		if (!xq.Browser.isTrident) {
      -2035 			var doc = this.getDoc();
      -2036 			var body = this.getBody();
      -2037 			
      -2038 			x -= doc.documentElement.scrollLeft;
      -2039 			y -= doc.documentElement.scrollTop;
      -2040 			
      -2041 			if (doc != body) {
      -2042 				x -= body.scrollLeft;
      -2043 				y -= body.scrollTop;
      -2044 			}
      -2045 		}
      -2046 		
      -2047 		for(var cmh in this.config.contextMenuHandlers) {
      -2048 			var stop = this.config.contextMenuHandlers[cmh].handler(this, this._contextMenuTargetElement, x, y);
      -2049 			if(stop) {
      -2050 				Event.stop(e);
      -2051 				return true;
      -2052 			}
      -2053 		}
      -2054 		
      -2055 		return false;
      -2056 	},
      -2057 	
      -2058 	showContextMenu: function(menuItems, x, y) {
      -2059 		if (!menuItems || menuItems.length <= 0) return;
      -2060 		
      -2061 		if (!this._contextMenuContainer) {
      -2062 			this._contextMenuContainer = this.doc.createElement('UL');
      -2063 			this._contextMenuContainer.className = 'xqContextMenu';
      -2064 			this._contextMenuContainer.style.display='none';
      -2065 			
      -2066 			Event.observe(this.doc, 'click', this._contextMenuClicked.bindAsEventListener(this));
      -2067 			Event.observe(this.rdom.getDoc(), 'click', this.hideContextMenu.bindAsEventListener(this));
      -2068 			
      -2069 			this.body.appendChild(this._contextMenuContainer);
      -2070 		} else {
      -2071 			while (this._contextMenuContainer.childNodes.length > 0)
      -2072 				this._contextMenuContainer.removeChild(this._contextMenuContainer.childNodes[0]);
      -2073 		}
      -2074 		
      -2075 		for (var i=0; i < menuItems.length; i++) {
      -2076 			menuItems[i]._node = this._addContextMenuItem(menuItems[i]);
      -2077 		}
      -2078 
      -2079 		this._contextMenuContainer.style.display='block';
      -2080 		this._contextMenuContainer.style.left=Math.min(Math.max(this.doc.body.scrollWidth, this.doc.documentElement.clientWidth)-this._contextMenuContainer.offsetWidth, x)+'px';
      -2081 		this._contextMenuContainer.style.top=Math.min(Math.max(this.doc.body.scrollHeight, this.doc.documentElement.clientHeight)-this._contextMenuContainer.offsetHeight, y)+'px';
      -2082 
      -2083 		this._contextMenuItems = menuItems;
      -2084 	},
      -2085 	
      -2086 	hideContextMenu: function() {
      -2087 		if (this._contextMenuContainer)
      -2088 			this._contextMenuContainer.style.display='none';
      -2089 	},
      -2090 	
      -2091 	_addContextMenuItem: function(item) {
      -2092 		if (!this._contextMenuContainer) throw "No conext menu container exists";
      -2093 		
      -2094 		var node = this.doc.createElement('LI');
      -2095 		if (item.disabled) node.className += ' disabled'; 
      -2096 		
      -2097 		if (item.title == '----') {
      -2098 			node.innerHTML = ' ';
      -2099 			node.className = 'separator';
      -2100 		} else {
      -2101 			if(item.handler) {
      -2102 				node.innerHTML = '<a href="javascript:;" onclick="return false;">'+(item.title.toString().escapeHTML())+'</a>';
      -2103 			} else {
      -2104 				node.innerHTML = (item.title.toString().escapeHTML());
      -2105 			}
      -2106 		}
      -2107 		
      -2108 		if(item.className) node.className = item.className;
      -2109 		
      -2110 		this._contextMenuContainer.appendChild(node);
      -2111 		
      -2112 		return node;
      -2113 	},
      -2114 	
      -2115 	_contextMenuClicked: function(e) {
      -2116 		this.hideContextMenu();
      -2117 		
      -2118 		if (!this._contextMenuContainer) return;
      -2119 		
      -2120 		var node = Event.findElement(e, 'LI');
      -2121 		if (!node || !this.rdom.tree.isDescendantOf(this._contextMenuContainer, node)) return;
      -2122 
      -2123 		for (var i=0; i < this._contextMenuItems.length; i++) {
      -2124 			if (this._contextMenuItems[i]._node == node) {
      -2125 				var handler = this._contextMenuItems[i].handler;
      -2126 				if (!this._contextMenuItems[i].disabled && handler) {
      -2127 					var xed = this;
      -2128 					var element = this._contextMenuTargetElement;
      -2129 					if(typeof handler == "function") {
      -2130 						handler(xed, element);
      -2131 					} else {
      -2132 						eval(handler);
      -2133 					}
      -2134 				}
      -2135 				break;
      -2136 			}
      -2137 		}
      -2138 	},
      -2139 	
      -2140 	/**
      -2141 	 * Inserts HTML template
      -2142 	 *
      -2143 	 * @param {String} html Template string. It should have single root element
      -2144 	 * @returns {Element} inserted element
      -2145 	 */
      -2146 	insertTemplate: function(html) {
      -2147 		return this.rdom.insertHtml(this._processTemplate(html));
      -2148 	},
      -2149 	
      -2150 	/**
      -2151 	 * Places given HTML template nearby target.
      -2152 	 *
      -2153 	 * @param {String} html Template string. It should have single root element
      -2154 	 * @param {Node} target Target node.
      -2155 	 * @param {String} where Possible values: "before", "start", "end", "after"
      -2156 	 *
      -2157 	 * @returns {Element} Inserted element.
      -2158 	 */
      -2159 	insertTemplateAt: function(html, target, where) {
      -2160 		return this.rdom.insertHtmlAt(this._processTemplate(html), target, where);
      -2161 	},
      -2162 	
      -2163 	_processTemplate: function(html) {
      -2164 		// apply template processors
      -2165 		var tps = $H(this.getTemplateProcessors()).values();
      -2166 		for(var i = 0; i < tps.length; i++) {
      -2167 			html = tps[i].handler(html);
      -2168 		}
      -2169 		
      -2170 		// remove all whitespace characters between block tags
      -2171 		return html = this.removeUnnecessarySpaces(html);
      -2172 	},
      -2173 	
      -2174 	
      -2175 	
      -2176 	/** @private */
      -2177 	_handleEnterAtEmptyBlock: function() {
      -2178 		var block = this.rdom.getCurrentBlockElement();
      -2179 		if(this.rdom.tree.isTableCell(block) && this.rdom.isFirstBlockOfBody(block)) {
      -2180 			block = this.rdom.insertNodeAt(this.rdom.makeEmptyParagraph(), this.rdom.getRoot(), "start");
      -2181 		} else {
      -2182 			block = 
      -2183 				this.rdom.outdentElement(block) ||
      -2184 				this.rdom.extractOutElementFromParent(block) ||
      -2185 				this.rdom.replaceTag("P", block) ||
      -2186 				this.rdom.insertNewBlockAround(block);
      -2187 		}
      -2188 		
      -2189 		this.rdom.placeCaretAtStartOf(block);
      -2190 		if(!xq.Browser.isTrident) block.scrollIntoView(false);
      -2191 	},
      -2192 	
      -2193 	/** @private */
      -2194 	_handleEnterAtEdge: function(atStart, forceInsertParagraph) {
      -2195 		var block = this.rdom.getCurrentBlockElement();
      -2196 		var blockToPlaceCaret;
      -2197 		
      -2198 		if(atStart && this.rdom.isFirstBlockOfBody(block)) {
      -2199 			blockToPlaceCaret = this.rdom.insertNodeAt(this.rdom.makeEmptyParagraph(), this.rdom.getRoot(), "start");
      -2200 		} else {
      -2201 			if(this.rdom.tree.isTableCell(block)) forceInsertParagraph = true;
      -2202 			var newBlock = this.rdom.insertNewBlockAround(block, atStart, forceInsertParagraph ? "P" : null);
      -2203 			blockToPlaceCaret = !atStart ? newBlock : newBlock.nextSibling;
      -2204 		}
      -2205 		
      -2206 		this.rdom.placeCaretAtStartOf(blockToPlaceCaret);
      -2207 		if(!xq.Browser.isTrident) blockToPlaceCaret.scrollIntoView(false);
      -2208 	}
      -2209 });
      \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_06.html b/modules/editor/skins/xquared/doc/api/src_06.html deleted file mode 100644 index 32b20a15b..000000000 --- a/modules/editor/skins/xquared/doc/api/src_06.html +++ /dev/null @@ -1,2262 +0,0 @@ -
        1 /**
      -  2  * Encapsulates browser incompatibility problem and provides rich set of DOM manipulation API.
      -  3  *
      -  4  * RichDom provides basic CRUD + Advanced DOM manipulation API, various query methods and caret/selection management API
      -  5  */
      -  6 xq.RichDom = Class.create({
      -  7 	/**
      -  8 	 * Initialize RichDom. Target window and root element should be set after initialization. See setWin and setRoot.
      -  9 	 *
      - 10      * @constructor
      - 11 	 */
      - 12 	initialize: function() {
      - 13 		/**
      - 14 		 * {xq.DomTree} instance of DomTree
      - 15 		 */
      - 16 		this.tree = new xq.DomTree();
      - 17 		
      - 18 		this._lastMarkerId = 0;
      - 19 	},
      - 20 	
      - 21 	
      - 22 	
      - 23 	/**
      - 24 	 * @param {Window} win Browser's window object
      - 25 	 */
      - 26 	setWin: function(win) {
      - 27 		if(!win) throw "[win] is null";
      - 28 		this.win = win;
      - 29 	},
      - 30 	
      - 31 	/**
      - 32 	 * @param {Element} root Root element
      - 33 	 */
      - 34 	setRoot: function(root) {
      - 35 		if(!root) throw "[root] is null";
      - 36 		if(this.win && (root.ownerDocument != this.win.document)) throw "root.ownerDocument != this.win.document";
      - 37 		this.root = root;
      - 38 		this.doc = this.root.ownerDocument;
      - 39 	},
      - 40 	
      - 41 	/**
      - 42 	 * @returns Browser's window object.
      - 43 	 */
      - 44 	getWin: function() {return this.win},
      - 45 	
      - 46 	/**
      - 47 	 * @returns Document object of root element.
      - 48 	 */
      - 49 	getDoc: function() {return this.doc},
      - 50 	
      - 51 	/**
      - 52 	 * @returns Root element.
      - 53 	 */
      - 54 	getRoot: function() {return this.root},
      - 55 	
      - 56 	
      - 57 	
      - 58 	/////////////////////////////////////////////
      - 59 	// CRUDs
      - 60 	
      - 61 	clearRoot: function() {
      - 62 		this.root.innerHTML = "";
      - 63 		this.root.appendChild(this.makeEmptyParagraph());
      - 64 	},
      - 65 	
      - 66 	/**
      - 67 	 * Removes place holders and empty text nodes of given element.
      - 68 	 *
      - 69 	 * @param {Element} element target element
      - 70 	 */
      - 71 	removePlaceHoldersAndEmptyNodes: function(element) {
      - 72 		var children = element.childNodes;
      - 73 		if(!children) return;
      - 74 		var stopAt = this.getBottommostLastChild(element);
      - 75 		if(!stopAt) return;
      - 76 		stopAt = this.tree.walkForward(stopAt);
      - 77 		
      - 78 		while(true) {
      - 79 			if(!element || element == stopAt) break;
      - 80 			
      - 81 			if(
      - 82 				this.isPlaceHolder(element) ||
      - 83 				(element.nodeType == 3 && element.nodeValue == "") ||
      - 84 				(!this.getNextSibling(element) && element.nodeType == 3 && element.nodeValue.strip() == "")
      - 85 			) {
      - 86 				var deleteTarget = element;
      - 87 				element = this.tree.walkForward(element);
      - 88 				
      - 89 				this.deleteNode(deleteTarget);
      - 90 			} else {
      - 91 				element = this.tree.walkForward(element);
      - 92 			}
      - 93 		}
      - 94 	},
      - 95 	
      - 96 	/**
      - 97 	 * Sets multiple attributes into element at once
      - 98 	 *
      - 99 	 * @param {Element} element target element
      -100 	 * @param {Object} map key-value pairs
      -101 	 */
      -102 	setAttributes: function(element, map) {
      -103 		for(key in map) element.setAttribute(key, map[key]);
      -104 	},
      -105 
      -106 	/**
      -107 	 * Creates textnode by given node value.
      -108 	 *
      -109 	 * @param {String} value value of textnode
      -110 	 * @returns {Node} Created text node
      -111 	 */	
      -112 	createTextNode: function(value) {return this.doc.createTextNode(value);},
      -113 
      -114 	/**
      -115 	 * Creates empty element by given tag name.
      -116 	 *
      -117 	 * @param {String} tagName name of tag
      -118 	 * @returns {Element} Created element
      -119 	 */	
      -120 	createElement: function(tagName) {return this.doc.createElement(tagName);},
      -121 
      -122 	/**
      -123 	 * Creates element from HTML string
      -124 	 * 
      -125 	 * @param {String} html HTML string
      -126 	 * @returns {Element} Created element
      -127 	 */
      -128 	createElementFromHtml: function(html) {
      -129 		var node = this.createElement("div");
      -130 		node.innerHTML = html;
      -131 		if(node.childNodes.length != 1) {
      -132 			throw "Illegal HTML fragment";
      -133 		}
      -134 		return this.getFirstChild(node);
      -135 	},
      -136 	
      -137 	/**
      -138 	 * Deletes node from DOM tree.
      -139 	 *
      -140 	 * @param {Node} node Target node which should be deleted
      -141 	 * @param {boolean} deleteEmptyParentsRecursively Recursively delete empty parent elements
      -142 	 * @param {boolean} correctEmptyParent Call #correctEmptyElement on empty parent element after deletion
      -143 	 */	
      -144 	deleteNode: function(node, deleteEmptyParentsRecursively, correctEmptyParent) {
      -145 		if(!node || !node.parentNode) return;
      -146 		
      -147 		var parent = node.parentNode;
      -148 		parent.removeChild(node);
      -149 		
      -150 		if(deleteEmptyParentsRecursively) {
      -151 			while(!parent.hasChildNodes()) {
      -152 				node = parent;
      -153 				parent = node.parentNode;
      -154 				if(!parent || this.getRoot() == node) break;
      -155 				parent.removeChild(node);
      -156 			}
      -157 		}
      -158 		
      -159 		if(correctEmptyParent && this.isEmptyBlock(parent)) {
      -160 			parent.innerHTML = "";
      -161 			this.correctEmptyElement(parent);
      -162 		}
      -163 	},
      -164 
      -165 	/**
      -166 	 * Inserts given node into current caret position
      -167 	 *
      -168 	 * @param {Node} node Target node
      -169 	 * @returns {Node} Inserted node. It could be different with given node.
      -170 	 */
      -171 	insertNode: function(node) {throw "Not implemented"},
      -172 
      -173 	/**
      -174 	 * Inserts given html into current caret position
      -175 	 *
      -176 	 * @param {String} html HTML string
      -177 	 * @returns {Node} Inserted node. It could be different with given node.
      -178 	 */
      -179 	insertHtml: function(html) {
      -180 		return this.insertNode(this.createElementFromHtml(html));
      -181 	},
      -182 	
      -183 	/**
      -184 	 * Creates textnode from given text and inserts it into current caret position
      -185 	 *
      -186 	 * @param {String} text Value of textnode
      -187 	 * @returns {Node} Inserted node
      -188 	 */
      -189 	insertText: function(text) {
      -190 		this.insertNode(this.createTextNode(text));
      -191 	},
      -192 	
      -193 	/**
      -194 	 * Places given node nearby target.
      -195 	 *
      -196 	 * @param {Node} node Node to be inserted.
      -197 	 * @param {Node} target Target node.
      -198 	 * @param {String} where Possible values: "before", "start", "end", "after"
      -199 	 * @param {boolean} performValidation Validate node if needed. For example when P placed into UL, its tag name automatically replaced with LI
      -200 	 *
      -201 	 * @returns {Node} Inserted node. It could be different with given node.
      -202 	 */
      -203 	insertNodeAt: function(node, target, where, performValidation) {
      -204 		if(
      -205 			["HTML", "HEAD"].include(target.nodeName) ||
      -206 			["BODY"].include(target.nodeName) && ["before", "after"].include(where)
      -207 		) throw "Illegal argument. Cannot move node[" + node.nodeName + "] to '" + where + "' of target[" + target.nodeName + "]"
      -208 		
      -209 		var object;
      -210 		var message;
      -211 		var secondParam;
      -212 		
      -213 		switch(where.toLowerCase()) {
      -214 			case "before":
      -215 				object = target.parentNode;
      -216 				message = 'insertBefore';
      -217 				secondParam = target;
      -218 				break
      -219 			case "start":
      -220 				if(target.firstChild) {
      -221 					object = target;
      -222 					message = 'insertBefore';
      -223 					secondParam = target.firstChild;
      -224 				} else {
      -225 					object = target;
      -226 					message = 'appendChild';
      -227 				}
      -228 				break
      -229 			case "end":
      -230 				object = target;
      -231 				message = 'appendChild';
      -232 				break
      -233 			case "after":
      -234 				if(target.nextSibling) {
      -235 					object = target.parentNode;
      -236 					message = 'insertBefore';
      -237 					secondParam = target.nextSibling;
      -238 				} else {
      -239 					object = target.parentNode;
      -240 					message = 'appendChild';
      -241 				}
      -242 				break
      -243 		}
      -244 
      -245 		if(performValidation && this.tree.isListContainer(object) && node.nodeName != "LI") {
      -246 			var li = this.createElement("LI");
      -247 			li.appendChild(node);
      -248 			node = li;
      -249 			object[message](node, secondParam);		
      -250 		} else if(performValidation && !this.tree.isListContainer(object) && node.nodeName == "LI") {
      -251 			this.wrapAllInlineOrTextNodesAs("P", node, true);
      -252 			var div = this.createElement("DIV");
      -253 			this.moveChildNodes(node, div);
      -254 			this.deleteNode(node);
      -255 			object[message](div, secondParam);
      -256 			node = this.unwrapElement(div, true);
      -257 		} else {
      -258 			object[message](node, secondParam);
      -259 		}
      -260 		
      -261 		return node;
      -262 	},
      -263 
      -264 	/**
      -265 	 * Creates textnode from given text and places given node nearby target.
      -266 	 *
      -267 	 * @param {String} text Text to be inserted.
      -268 	 * @param {Node} target Target node.
      -269 	 * @param {String} where Possible values: "before", "start", "end", "after"
      -270 	 *
      -271 	 * @returns {Node} Inserted node.
      -272 	 */
      -273 	insertTextAt: function(text, target, where) {
      -274 		return this.insertNodeAt(this.createTextNode(text), target, where);
      -275 	},
      -276 
      -277 	/**
      -278 	 * Creates element from given HTML string and places given it nearby target.
      -279 	 *
      -280 	 * @param {String} html HTML to be inserted.
      -281 	 * @param {Node} target Target node.
      -282 	 * @param {String} where Possible values: "before", "start", "end", "after"
      -283 	 *
      -284 	 * @returns {Node} Inserted node.
      -285 	 */
      -286 	insertHtmlAt: function(html, target, where) {
      -287 		return this.insertNodeAt(this.createElementFromHtml(html), target, where);
      -288 	},
      -289 
      -290 	/**
      -291 	 * Replaces element's tag by removing current element and creating new element by given tag name.
      -292 	 *
      -293 	 * @param {String} tag New tag name
      -294 	 * @param {Element} element Target element
      -295 	 *
      -296 	 * @returns {Element} Replaced element
      -297 	 */	
      -298 	replaceTag: function(tag, element) {
      -299 		if(element.nodeName == tag) return null;
      -300 		if(this.tree.isTableCell(element)) return null;
      -301 		
      -302 		var newElement = this.createElement(tag);
      -303 		this.moveChildNodes(element, newElement);
      -304 		this.copyAttributes(element, newElement, true);
      -305 		element.parentNode.replaceChild(newElement, element);
      -306 		
      -307 		if(!newElement.hasChildNodes()) this.correctEmptyElement(newElement);
      -308 		
      -309 		return newElement;
      -310 	},
      -311 
      -312 	/**
      -313 	 * Unwraps unnecessary paragraph.
      -314 	 *
      -315 	 * Unnecessary paragraph is P which is the only child of given container element.
      -316 	 * For example, P which is contained by LI and is the only child is the unnecessary paragraph.
      -317 	 * But if given container element is a block-only-container(BLOCKQUOTE, BODY), this method does nothing.
      -318 	 *
      -319 	 * @param {Element} element Container element
      -320 	 * @returns {boolean} True if unwrap performed.
      -321 	 */
      -322 	unwrapUnnecessaryParagraph: function(element) {
      -323 		if(!element) return false;
      -324 		
      -325 		if(!this.tree.isBlockOnlyContainer(element) && element.childNodes.length == 1 && element.firstChild.nodeName == "P" && !this.hasImportantAttributes(element.firstChild)) {
      -326 			var p = element.firstChild;
      -327 			this.moveChildNodes(p, element);
      -328 			this.deleteNode(p);
      -329 			return true;
      -330 		}
      -331 		return false;
      -332 	},
      -333 	
      -334 	/**
      -335 	 * Unwraps element by extracting all children out and removing the element.
      -336 	 *
      -337 	 * @param {Element} element Target element
      -338 	 * @param {boolean} wrapInlineAndTextNodes Wrap all inline and text nodes with P before unwrap
      -339 	 * @returns {Node} First child of unwrapped element
      -340 	 */
      -341 	unwrapElement: function(element, wrapInlineAndTextNodes) {
      -342 		if(wrapInlineAndTextNodes) this.wrapAllInlineOrTextNodesAs("P", element);
      -343 		
      -344 		var nodeToReturn = element.firstChild;
      -345 		
      -346 		while(element.firstChild) this.insertNodeAt(element.firstChild, element, "before");
      -347 		this.deleteNode(element);
      -348 		
      -349 		return nodeToReturn;
      -350 	},
      -351 	
      -352 	/**
      -353 	 * Wraps element by given tag
      -354 	 *
      -355 	 * @param {String} tag tag name
      -356 	 * @param {Element} element target element to wrap
      -357 	 * @returns {Element} wrapper
      -358 	 */
      -359 	wrapElement: function(tag, element) {
      -360 		var wrapper = this.insertNodeAt(this.createElement(tag), element, "before");
      -361 		wrapper.appendChild(element);
      -362 		return wrapper;
      -363 	},
      -364 	
      -365 	/**
      -366 	 * Tests #smartWrap with given criteria but doesn't change anything
      -367 	 */
      -368 	testSmartWrap: function(endElement, criteria) {
      -369 		return this.smartWrap(endElement, null, criteria, true);
      -370 	},
      -371 	
      -372 	/**
      -373 	 * Create inline element with given tag name and wraps nodes nearby endElement by given criteria
      -374 	 *
      -375 	 * @param {Element} endElement Boundary(end point, exclusive) of wrapper.
      -376 	 * @param {String} tag Tag name of wrapper.
      -377 	 * @param {Object} function which returns text index of start boundary.
      -378 	 * @param {boolean} testOnly just test boundary and do not perform actual wrapping.
      -379 	 *
      -380 	 * @returns {Element} wrapper
      -381 	 */
      -382 	smartWrap: function(endElement, tag, criteria, testOnly) {
      -383 		var block = this.getParentBlockElementOf(endElement);
      -384 
      -385 		tag = tag || "SPAN";
      -386 		criteria = criteria || function(text) {return -1};
      -387 		
      -388 		// check for empty wrapper
      -389 		if(!testOnly && (!endElement.previousSibling || this.isEmptyBlock(block))) {
      -390 			var wrapper = this.insertNodeAt(this.createElement(tag), endElement, "before");
      -391 			return wrapper;
      -392 		}
      -393 		
      -394 		// collect all textnodes
      -395 		var textNodes = this.tree.collectForward(block, function(node) {return node == endElement}, function(node) {return node.nodeType == 3});
      -396 		
      -397 		// find textnode and break-point
      -398 		var nodeIndex = 0;
      -399 		var nodeValues = textNodes.pluck("nodeValue");
      -400 		var textToWrap = nodeValues.join("");
      -401 		var textIndex = criteria(textToWrap)
      -402 		var breakPoint = textIndex;
      -403 		
      -404 		if(breakPoint == -1) {
      -405 			breakPoint = 0;
      -406 		} else {
      -407 			textToWrap = textToWrap.substring(breakPoint);
      -408 		}
      -409 		
      -410 		for(var i = 0; i < textNodes.length; i++) {
      -411 			if(breakPoint > nodeValues[i].length) {
      -412 				breakPoint -= nodeValues[i].length;
      -413 			} else {
      -414 				nodeIndex = i;
      -415 				break;
      -416 			}
      -417 		}
      -418 		
      -419 		if(testOnly) return {text:textToWrap, textIndex:textIndex, nodeIndex:nodeIndex, breakPoint:breakPoint};
      -420 		
      -421 		// break textnode if necessary 
      -422 		if(breakPoint != 0) {
      -423 			var splitted = textNodes[nodeIndex].splitText(breakPoint);
      -424 			nodeIndex++;
      -425 			textNodes.splice(nodeIndex, 0, splitted);
      -426 		}
      -427 		var startElement = textNodes[nodeIndex] || block.firstChild;
      -428 		
      -429 		// split inline elements up to parent block if necessary
      -430 		var family = this.tree.findCommonAncestorAndImmediateChildrenOf(startElement, endElement);
      -431 		var ca = family.parent;
      -432 		if(ca) {
      -433 			if(startElement.parentNode != ca) startElement = this.splitElementUpto(startElement, ca, true);
      -434 			if(endElement.parentNode != ca) endElement = this.splitElementUpto(endElement, ca, true);
      -435 			
      -436 			var prevStart = startElement.previousSibling;
      -437 			var nextEnd = endElement.nextSibling;
      -438 			
      -439 			// remove empty inline elements
      -440 			if(prevStart && prevStart.nodeType == 1 && this.isEmptyBlock(prevStart)) this.deleteNode(prevStart);
      -441 			if(nextEnd && nextEnd.nodeType == 1 && this.isEmptyBlock(nextEnd)) this.deleteNode(nextEnd);
      -442 			
      -443 			// wrap
      -444 			var wrapper = this.insertNodeAt(this.createElement(tag), startElement, "before");
      -445 			while(wrapper.nextSibling != endElement) wrapper.appendChild(wrapper.nextSibling);
      -446 			return wrapper;
      -447 		} else {
      -448 			// wrap
      -449 			var wrapper = this.insertNodeAt(this.createElement(tag), endElement, "before");
      -450 			return wrapper;
      -451 		}
      -452 	},
      -453 	
      -454 	/**
      -455 	 * Wraps all adjust inline elements and text nodes into block element.
      -456 	 *
      -457 	 * TODO: empty element should return empty array when it is not forced and (at least) single item array when forced
      -458 	 *
      -459 	 * @param {String} tag Tag name of wrapper
      -460 	 * @param {Element} element Target element
      -461 	 * @param {boolean} force Force wrapping. If it is set to false, this method do not makes unnecessary wrapper.
      -462 	 *
      -463 	 * @returns {Array} Array of wrappers. If nothing performed it returns empty array
      -464 	 */
      -465 	wrapAllInlineOrTextNodesAs: function(tag, element, force) {
      -466 		var wrappers = [];
      -467 		
      -468 		if(!force && !this.tree.hasMixedContents(element)) return wrappers;
      -469 		
      -470 		var node = element.firstChild;
      -471 		while(node) {
      -472 			if(this.tree.isTextOrInlineNode(node)) {
      -473 				var wrapper = this.wrapInlineOrTextNodesAs(tag, node);
      -474 				wrappers.push(wrapper);
      -475 				node = wrapper.nextSibling;
      -476 			} else {
      -477 				node = node.nextSibling;
      -478 			}
      -479 		}
      -480 
      -481 		return wrappers;
      -482 	},
      -483 
      -484 	/**
      -485 	 * Wraps node and its adjust next siblings into an element
      -486 	 */
      -487 	wrapInlineOrTextNodesAs: function(tag, node) {
      -488 		var wrapper = this.createElement(tag);
      -489 		var from = node;
      -490 
      -491 		from.parentNode.replaceChild(wrapper, from);
      -492 		wrapper.appendChild(from);
      -493 
      -494 		// move nodes into wrapper
      -495 		while(wrapper.nextSibling && this.tree.isTextOrInlineNode(wrapper.nextSibling)) wrapper.appendChild(wrapper.nextSibling);
      -496 
      -497 		return wrapper;
      -498 	},
      -499 	
      -500 	/**
      -501 	 * Turns block element into list item
      -502 	 *
      -503 	 * @param {Element} element Target element
      -504 	 * @param {String} type One of "UL", "OL", "CODE". "CODE" is same with "OL" but it gives "OL" a class name "code"
      -505 	 *
      -506 	 * @return {Element} LI element
      -507 	 */
      -508 	turnElementIntoListItem: function(element, type) {
      -509 		type = type.toUpperCase();
      -510 		
      -511 		var container = this.createElement(type == "UL" ? "UL" : "OL");
      -512 		if(type == "CODE") container.className = "code";
      -513 		
      -514 		if(this.tree.isTableCell(element)) {
      -515 			var p = this.wrapAllInlineOrTextNodesAs("P", element, true)[0];
      -516 			container = this.insertNodeAt(container, element, "start");
      -517 			var li = this.insertNodeAt(this.createElement("LI"), container, "start");
      -518 			li.appendChild(p);
      -519 		} else {
      -520 			container = this.insertNodeAt(container, element, "after");
      -521 			var li = this.insertNodeAt(this.createElement("LI"), container, "start");
      -522 			li.appendChild(element);
      -523 		}
      -524 		
      -525 		this.unwrapUnnecessaryParagraph(li);
      -526 		this.mergeAdjustLists(container);
      -527 		
      -528 		return li;
      -529 	},
      -530 	
      -531 	/**
      -532 	 * Extracts given element out from its parent element.
      -533 	 * 
      -534 	 * @param {Element} element Target element
      -535 	 */
      -536 	extractOutElementFromParent: function(element) {
      -537 		if(element == this.root || this.root == element.parentNode || !element.offsetParent) return null;
      -538 		
      -539 		if(element.nodeName == "LI") {
      -540 			this.wrapAllInlineOrTextNodesAs("P", element, true);
      -541 			element = element.firstChild;
      -542 		}
      -543 
      -544 		var container = element.parentNode;
      -545 		var nodeToReturn = null;
      -546 		
      -547 		if(container.nodeName == "LI" && container.parentNode.parentNode.nodeName == "LI") {
      -548 			// nested list item
      -549 			if(element.previousSibling) {
      -550 				this.splitContainerOf(element, true);
      -551 				this.correctEmptyElement(element);
      -552 			}
      -553 			
      -554 			this.outdentListItem(element);
      -555 			nodeToReturn = element;
      -556 		} else if(container.nodeName == "LI") {
      -557 			// not-nested list item
      -558 			
      -559 			if(this.tree.isListContainer(element.nextSibling)) {
      -560 				// 1. split listContainer
      -561 				var listContainer = container.parentNode;
      -562 				this.splitContainerOf(container, true);
      -563 				this.correctEmptyElement(element);
      -564 				
      -565 				// 2. extract out LI's children
      -566 				nodeToReturn = container.firstChild;
      -567 				while(container.firstChild) {
      -568 					this.insertNodeAt(container.firstChild, listContainer, "before");
      -569 				}
      -570 				
      -571 				// 3. remove listContainer and merge adjust lists
      -572 				var prevContainer = listContainer.previousSibling;
      -573 				this.deleteNode(listContainer);
      -574 				if(prevContainer && this.tree.isListContainer(prevContainer)) this.mergeAdjustLists(prevContainer);
      -575 			} else {
      -576 				// 1. split LI
      -577 				this.splitContainerOf(element, true);
      -578 				this.correctEmptyElement(element);
      -579 				
      -580 				// 2. split list container
      -581 				var listContainer = this.splitContainerOf(container);
      -582 				
      -583 				// 3. extract out
      -584 				this.insertNodeAt(element, listContainer.parentNode, "before");
      -585 				this.deleteNode(listContainer.parentNode);
      -586 				
      -587 				nodeToReturn = element;
      -588 			}
      -589 		} else if(this.tree.isTableCell(container) || this.tree.isTableCell(element)) {
      -590 			// do nothing
      -591 		} else {
      -592 			// normal block
      -593 			this.splitContainerOf(element, true);
      -594 			this.correctEmptyElement(element);
      -595 			nodeToReturn = this.insertNodeAt(element, container, "before");
      -596 			
      -597 			this.deleteNode(container);
      -598 		}
      -599 		
      -600 		return nodeToReturn;
      -601 	},
      -602 	
      -603 	/**
      -604 	 * Insert new block above or below given element.
      -605 	 *
      -606 	 * @param {Element} block Target block
      -607 	 * @param {boolean} before Insert new block above(before) target block
      -608 	 * @param {String} forceTag New block's tag name. If omitted, target block's tag name will be used.
      -609 	 *
      -610 	 * @returns {Element} Inserted block
      -611 	 */
      -612 	insertNewBlockAround: function(block, before, forceTag) {
      -613 		var isListItem = block.nodeName == "LI" || block.parentNode.nodeName == "LI";
      -614 		
      -615 		this.removeTrailingWhitespace(block);
      -616 		if(this.isFirstLiWithNestedList(block) && !forceTag && before) {
      -617 			var li = this.getParentElementOf(block, ["LI"]);
      -618 			var newBlock = this._insertNewBlockAround(li, before);
      -619 			return newBlock;
      -620 		} else if(isListItem && !forceTag) {
      -621 			var li = this.getParentElementOf(block, ["LI"]);
      -622 			var newBlock = this._insertNewBlockAround(block, before);
      -623 			if(li != block) newBlock = this.splitContainerOf(newBlock, false, "prev");
      -624 			return newBlock;
      -625 		} else if(this.tree.isBlockContainer(block)) {
      -626 			this.wrapAllInlineOrTextNodesAs("P", block, true);
      -627 			return this._insertNewBlockAround(block.firstChild, before, forceTag);
      -628 		} else {
      -629 			return this._insertNewBlockAround(block, before, this.tree.isHeading(block) ? "P" : forceTag);
      -630 		}
      -631 	},
      -632 	
      -633 	/**
      -634 	 * @private
      -635 	 *
      -636 	 * TODO: Rename
      -637 	 */
      -638 	_insertNewBlockAround: function(element, before, tagName) {
      -639 		var newElement = this.createElement(tagName || element.nodeName);
      -640 		this.copyAttributes(element, newElement, false);
      -641 		this.correctEmptyElement(newElement);
      -642 		newElement = this.insertNodeAt(newElement, element, before ? "before" : "after");
      -643 		return newElement;
      -644 	},
      -645 	
      -646 	/**
      -647 	 * Wrap or replace element with given tag name.
      -648 	 *
      -649 	 * @param {String} tag Tag name
      -650 	 * @param {Element} element Target element
      -651 	 *
      -652 	 * @return {Element} wrapper element or replaced element.
      -653 	 */
      -654 	applyTagIntoElement: function(tag, element) {
      -655 		if(this.tree.isBlockOnlyContainer(tag)) {
      -656 			return this.wrapBlock(tag, element);
      -657 		} else if(this.tree.isBlockContainer(element)) {
      -658 			var wrapper = this.createElement(tag);
      -659 			this.moveChildNodes(element, wrapper);
      -660 			return this.insertNodeAt(wrapper, element, "start");
      -661 		} else {
      -662 			if(this.tree.isBlockContainer(tag) && this.hasImportantAttributes(element)) {
      -663 				return this.wrapBlock(tag, element);
      -664 			} else {
      -665 				return this.replaceTag(tag, element);
      -666 			}
      -667 		}
      -668 		
      -669 		throw "IllegalArgumentException - [" + tag + ", " + element + "]";
      -670 	},
      -671 	
      -672 	/**
      -673 	 * Wrap or replace elements with given tag name.
      -674 	 *
      -675 	 * @param {String} tag Tag name
      -676 	 * @param {Element} from Start boundary (inclusive)
      -677 	 * @param {Element} to End boundary (inclusive)
      -678 	 *
      -679 	 * @returns {Array} Array of wrappers or replaced elements
      -680 	 */
      -681 	applyTagIntoElements: function(tagName, from, to) {
      -682 		var applied = [];
      -683 		
      -684 		if(this.tree.isBlockContainer(tagName)) {
      -685 			var family = this.tree.findCommonAncestorAndImmediateChildrenOf(from, to);
      -686 			var node = family.left;
      -687 			var wrapper = this.insertNodeAt(this.createElement(tagName), node, "before");
      -688 			
      -689 			var coveringWholeList =
      -690 				family.parent.nodeName == "LI" &&
      -691 				family.parent.parentNode.childNodes.length == 1 &&
      -692 				!family.left.previousSilbing &&
      -693 				!family.right.nextSibling;
      -694 				
      -695 			if(coveringWholeList) {
      -696 				var ul = node.parentNode.parentNode;
      -697 				this.insertNodeAt(wrapper, ul, "before");
      -698 				wrapper.appendChild(ul);
      -699 			} else {
      -700 				while(node != family.right) {
      -701 					next = node.nextSibling;
      -702 					wrapper.appendChild(node);
      -703 					node = next;
      -704 				}
      -705 				wrapper.appendChild(family.right);
      -706 			}
      -707 			applied.push(wrapper);
      -708 		} else {
      -709 			// is normal tagName
      -710 			var elements = this.getBlockElementsBetween(from, to);
      -711 			for(var i = 0; i < elements.length; i++) {
      -712 				if(this.tree.isBlockContainer(elements[i])) {
      -713 					applied.push(this.wrapAllInlineOrTextNodesAs(tagName, elements[i], true));
      -714 				} else {
      -715 					applied.push(this.replaceTag(tagName, elements[i]));
      -716 				}
      -717 			}
      -718 		}
      -719 		return applied.flatten();
      -720 	},
      -721 	
      -722 	/**
      -723 	 * Moves block up or down
      -724 	 *
      -725 	 * @param {Element} block Target block
      -726 	 * @param {boolean} up Move up if true
      -727 	 * 
      -728 	 * @returns {Element} Moved block. It could be different with given block.
      -729 	 */
      -730 	moveBlock: function(block, up) {
      -731 		// if block is table cell or contained by table cell, select its row as mover
      -732 		block = this.getParentElementOf(block, ["TR"]) || block;
      -733 		
      -734 		// if block is only child, select its parent as mover
      -735 		while(block.nodeName != "TR" && block.parentNode != this.getRoot() && !block.previousSibling && !block.nextSibling && !this.tree.isListContainer(block.parentNode)) {
      -736 			block = block.parentNode;
      -737 		}
      -738 		
      -739 		// find target and where
      -740 		var target, where;
      -741 		if (up) {
      -742 			target = block.previousSibling;
      -743 			
      -744 			if(target) {
      -745 				var singleNodeLi = target.nodeName == 'LI' && ((target.childNodes.length == 1 && this.tree.isBlock(target.firstChild)) || !this.tree.hasBlocks(target));
      -746 				var table = ['TABLE', 'TR'].include(target.nodeName);
      -747 
      -748 				where = this.tree.isBlockContainer(target) && !singleNodeLi && !table ? "end" : "before";
      -749 			} else if(block.parentNode != this.getRoot()) {
      -750 				target = block.parentNode;
      -751 				where = "before";
      -752 			}
      -753 		} else {
      -754 			target = block.nextSibling;
      -755 			
      -756 			if(target) {
      -757 				var singleNodeLi = target.nodeName == 'LI' && ((target.childNodes.length == 1 && this.tree.isBlock(target.firstChild)) || !this.tree.hasBlocks(target));
      -758 				var table = ['TABLE', 'TR'].include(target.nodeName);
      -759 				
      -760 				where = this.tree.isBlockContainer(target) && !singleNodeLi && !table ? "start" : "after";
      -761 			} else if(block.parentNode != this.getRoot()) {
      -762 				target = block.parentNode;
      -763 				where = "after";
      -764 			}
      -765 		}
      -766 		
      -767 		
      -768 		// no way to go?
      -769 		if(!target) return null;
      -770 		if(["TBODY", "THEAD"].include(target.nodeName)) return null;
      -771 		
      -772 		// normalize
      -773 		this.wrapAllInlineOrTextNodesAs("P", target, true);
      -774 		
      -775 		// make placeholder if needed
      -776 		if(this.isFirstLiWithNestedList(block)) {
      -777 			this.insertNewBlockAround(block, false, "P");
      -778 		}
      -779 		
      -780 		// perform move
      -781 		var parent = block.parentNode;
      -782 		var moved = this.insertNodeAt(block, target, where, true);
      -783 		
      -784 		// cleanup
      -785 		if(!parent.hasChildNodes()) this.deleteNode(parent, true);
      -786 		this.unwrapUnnecessaryParagraph(moved);
      -787 		this.unwrapUnnecessaryParagraph(target);
      -788 
      -789 		// remove placeholder
      -790 		if(up) {
      -791 			if(moved.previousSibling && this.isEmptyBlock(moved.previousSibling) && !moved.previousSibling.previousSibling && moved.parentNode.nodeName == "LI" && this.tree.isListContainer(moved.nextSibling)) {
      -792 				this.deleteNode(moved.previousSibling);
      -793 			}
      -794 		} else {
      -795 			if(moved.nextSibling && this.isEmptyBlock(moved.nextSibling) && !moved.previousSibling && moved.parentNode.nodeName == "LI" && this.tree.isListContainer(moved.nextSibling.nextSibling)) {
      -796 				this.deleteNode(moved.nextSibling);
      -797 			}
      -798 		}
      -799 		
      -800 		return moved;
      -801 	},
      -802 	
      -803 	/**
      -804 	 * Remove given block
      -805 	 *
      -806 	 * @param {Element} block Target block
      -807 	 * @returns {Element} Nearest block of remove element
      -808 	 */
      -809 	removeBlock: function(block) {
      -810 		var blockToMove;
      -811 
      -812 		// if block is only child, select its parent as mover
      -813 		while(block.parentNode != this.getRoot() && !block.previousSibling && !block.nextSibling && !this.tree.isListContainer(block.parentNode)) {
      -814 			block = block.parentNode;
      -815 		}
      -816 		
      -817 		var finder = function(node) {return this.tree.isBlock(node) && !this.tree.isAtomic(node) && !this.tree.isDescendantOf(block, node) && !this.tree.hasBlocks(node);}.bind(this);
      -818 		var exitCondition = function(node) {return this.tree.isBlock(node) && !this.tree.isDescendantOf(this.getRoot(), node)}.bind(this);
      -819 		
      -820 		if(this.isFirstLiWithNestedList(block)) {
      -821 			blockToMove = this.outdentListItem(block.nextSibling.firstChild);
      -822 			this.deleteNode(blockToMove.previousSibling, true);
      -823 		} else if(this.tree.isTableCell(block)) {
      -824 			var rtable = new xq.RichTable(this, this.getParentElementOf(block, ["TABLE"]));
      -825 			blockToMove = rtable.getBelowCellOf(block);
      -826 			
      -827 			// should not delete row when there's thead and the row is the only child of tbody
      -828 			if(
      -829 				block.parentNode.parentNode.nodeName == "TBODY" &&
      -830 				rtable.hasHeadingAtTop() &&
      -831 				rtable.getDom().tBodies[0].rows.length == 1) return blockToMove;
      -832 			
      -833 			blockToMove = blockToMove ||
      -834 				this.tree.findForward(block, finder, exitCondition) ||
      -835 				this.tree.findBackward(block, finder, exitCondition);
      -836 			
      -837 			this.deleteNode(block.parentNode, true);
      -838 		} else {
      -839 			blockToMove = blockToMove ||
      -840 				this.tree.findForward(block, finder, exitCondition) ||
      -841 				this.tree.findBackward(block, finder, exitCondition);
      -842 			
      -843 			if(!blockToMove) blockToMove = this.insertNodeAt(this.makeEmptyParagraph(), block, "after");
      -844 			
      -845 			this.deleteNode(block, true);
      -846 		}
      -847 		if(!this.getRoot().hasChildNodes()) {
      -848 			blockToMove = this.createElement("P");
      -849 			this.getRoot().appendChild(blockToMove);
      -850 			this.correctEmptyElement(blockToMove);
      -851 		}
      -852 		
      -853 		return blockToMove;
      -854 	},
      -855 	
      -856 	/**
      -857 	 * Removes trailing whitespaces of given block
      -858 	 *
      -859 	 * @param {Element} block Target block
      -860 	 */
      -861 	removeTrailingWhitespace: function(block) {throw "Not implemented"},
      -862 	
      -863 	/**
      -864 	 * Extract given list item out and change its container's tag
      -865 	 *
      -866 	 * @param {Element} element LI or P which is a child of LI
      -867 	 * @param {String} type "OL", "UL", or "CODE"
      -868 	 *
      -869 	 * @returns {Element} changed element
      -870 	 */
      -871 	changeListTypeTo: function(element, type) {
      -872 		type = type.toUpperCase();
      -873 		
      -874 		var li = this.getParentElementOf(element, ["LI"]);
      -875 		if(!li) throw "IllegalArgumentException";
      -876 		
      -877 		var container = li.parentNode;
      -878 
      -879 		this.splitContainerOf(li);
      -880 		
      -881 		var newContainer = this.insertNodeAt(this.createElement(type == "UL" ? "UL" : "OL"), container, "before");
      -882 		if(type == "CODE") newContainer.className = "code";
      -883 		
      -884 		this.insertNodeAt(li, newContainer, "start");
      -885 		this.deleteNode(container);
      -886 		
      -887 		this.mergeAdjustLists(newContainer);
      -888 		
      -889 		return element;
      -890 	},
      -891 	
      -892 	/**
      -893 	 * Split container of element into (maxium) three pieces.
      -894 	 */
      -895 	splitContainerOf: function(element, preserveElementItself, dir) {
      -896 		if([element, element.parentNode].include(this.getRoot())) return element;
      -897 
      -898 		var container = element.parentNode;
      -899 		if(element.previousSibling && (!dir || dir.toLowerCase() == "prev")) {
      -900 			var prev = this.createElement(container.nodeName);
      -901 			this.copyAttributes(container, prev);
      -902 			while(container.firstChild != element) {
      -903 				prev.appendChild(container.firstChild);
      -904 			}
      -905 			this.insertNodeAt(prev, container, "before");
      -906 			this.unwrapUnnecessaryParagraph(prev);
      -907 		}
      -908 		
      -909 		if(element.nextSibling && (!dir || dir.toLowerCase() == "next")) {
      -910 			var next = this.createElement(container.nodeName);
      -911 			this.copyAttributes(container, next);
      -912 			while(container.lastChild != element) {
      -913 				this.insertNodeAt(container.lastChild, next, "start");
      -914 			}
      -915 			this.insertNodeAt(next, container, "after");
      -916 			this.unwrapUnnecessaryParagraph(next);
      -917 		}
      -918 		
      -919 		if(!preserveElementItself) element = this.unwrapUnnecessaryParagraph(container) ? container : element;
      -920 		return element;
      -921 	},
      -922 
      -923 	/**
      -924 	 * TODO: Add specs
      -925 	 */
      -926 	splitParentElement: function(seperator) {
      -927 		var parent = seperator.parentNode;
      -928 		if(["HTML", "HEAD", "BODY"].include(parent.nodeName)) throw "Illegal argument. Cannot seperate element[" + parent.nodeName + "]";
      -929 
      -930 		var previousSibling = seperator.previousSibling;
      -931 		var nextSibling = seperator.nextSibling;
      -932 		
      -933 		var newElement = this.insertNodeAt(this.createElement(parent.nodeName), parent, "after");
      -934 		
      -935 		var next;
      -936 		while(next = seperator.nextSibling) newElement.appendChild(next);
      -937 		
      -938 		this.insertNodeAt(seperator, newElement, "start");
      -939 		this.copyAttributes(parent, newElement);
      -940 		
      -941 		return newElement;
      -942 	},
      -943 	
      -944 	/**
      -945 	 * TODO: Add specs
      -946 	 */
      -947 	splitElementUpto: function(seperator, element, excludeElement) {
      -948 		while(seperator.previousSibling != element) {
      -949 			if(excludeElement && seperator.parentNode == element) break;
      -950 			seperator = this.splitParentElement(seperator);
      -951 		}
      -952 		return seperator;
      -953 	},
      -954 	
      -955 	/**
      -956 	 * Merges two adjust elements
      -957 	 *
      -958 	 * @param {Element} element base element
      -959 	 * @param {boolean} withNext merge base element with next sibling
      -960 	 * @param {boolean} skip skip merge steps
      -961 	 */
      -962 	mergeElement: function(element, withNext, skip) {
      -963 		this.wrapAllInlineOrTextNodesAs("P", element.parentNode, true);
      -964 		
      -965 		// find two block
      -966 		if(withNext) {
      -967 			var prev = element;
      -968 			var next = this.tree.findForward(
      -969 				element,
      -970 				function(node) {return this.tree.isBlock(node) && !this.tree.isListContainer(node) && node != element.parentNode}.bind(this)
      -971 			);
      -972 		} else {
      -973 			var next = element;
      -974 			var prev = this.tree.findBackward(
      -975 				element,
      -976 				function(node) {return this.tree.isBlock(node) && !this.tree.isListContainer(node) && node != element.parentNode}.bind(this)
      -977 			);
      -978 		}
      -979 		
      -980 		// normalize next block
      -981 		if(next && this.tree.isDescendantOf(this.getRoot(), next)) {
      -982 			var nextContainer = next.parentNode;
      -983 			if(this.tree.isBlockContainer(next)) {
      -984 				nextContainer = next;
      -985 				this.wrapAllInlineOrTextNodesAs("P", nextContainer, true);
      -986 				next = nextContainer.firstChild;
      -987 			}
      -988 		} else {
      -989 			next = null;
      -990 		}
      -991 		
      -992 		// normalize prev block
      -993 		if(prev && this.tree.isDescendantOf(this.getRoot(), prev)) {
      -994 			var prevContainer = prev.parentNode;
      -995 			if(this.tree.isBlockContainer(prev)) {
      -996 				prevContainer = prev;
      -997 				this.wrapAllInlineOrTextNodesAs("P", prevContainer, true);
      -998 				prev = prevContainer.lastChild;
      -999 			}
      -1000 		} else {
      -1001 			prev = null;
      -1002 		}
      -1003 		
      -1004 		try {
      -1005 			var containersAreTableCell =
      -1006 				prevContainer && (this.tree.isTableCell(prevContainer) || ['TR', 'THEAD', 'TBODY'].include(prevContainer.nodeName)) &&
      -1007 				nextContainer && (this.tree.isTableCell(nextContainer) || ['TR', 'THEAD', 'TBODY'].include(nextContainer.nodeName));
      -1008 			
      -1009 			if(containersAreTableCell && prevContainer != nextContainer) return null;
      -1010 			
      -1011 			// if next has margin, perform outdent
      -1012 			if((!skip || !prev) && next && this.outdentElement(next)) return element;
      -1013 
      -1014 			// nextContainer is first li and next of it is list container
      -1015 			if(nextContainer && nextContainer.nodeName == 'LI' && this.tree.isListContainer(next.nextSibling)) {
      -1016 				this.extractOutElementFromParent(nextContainer);
      -1017 				return prev;
      -1018 			}
      -1019 			
      -1020 			// merge two list containers
      -1021 			if(nextContainer && nextContainer.nodeName == 'LI' && this.tree.isListContainer(nextContainer.parentNode.previousSibling)) {
      -1022 				this.mergeAdjustLists(nextContainer.parentNode.previousSibling, true, "next");
      -1023 				return prev;
      -1024 			}
      -1025 
      -1026 			if(next && !containersAreTableCell && prevContainer && prevContainer.nodeName == 'LI' && nextContainer && nextContainer.nodeName == 'LI' && prevContainer.parentNode.nextSibling == nextContainer.parentNode) {
      -1027 				var nextContainerContainer = nextContainer.parentNode;
      -1028 				this.moveChildNodes(nextContainer.parentNode, prevContainer.parentNode);
      -1029 				this.deleteNode(nextContainerContainer);
      -1030 				return prev;
      -1031 			}
      -1032 			
      -1033 			// merge two containers
      -1034 			if(next && !containersAreTableCell && prevContainer && prevContainer.nextSibling == nextContainer && ((skip && prevContainer.nodeName != "LI") || (!skip && prevContainer.nodeName == "LI"))) {
      -1035 				this.moveChildNodes(nextContainer, prevContainer);
      -1036 				return prev;
      -1037 			}
      -1038 
      -1039 			// unwrap container
      -1040 			if(nextContainer && nextContainer.nodeName != "LI" && !this.getParentElementOf(nextContainer, ["TABLE"]) && !this.tree.isListContainer(nextContainer) && nextContainer != this.getRoot() && !next.previousSibling) {
      -1041 				return this.unwrapElement(nextContainer, true);
      -1042 			}
      -1043 			
      -1044 			// delete table
      -1045 			if(withNext && nextContainer && nextContainer.nodeName == "TABLE") {
      -1046 				this.deleteNode(nextContainer, true);
      -1047 				return prev;
      -1048 			} else if(!withNext && prevContainer && this.tree.isTableCell(prevContainer) && !this.tree.isTableCell(nextContainer)) {
      -1049 				this.deleteNode(this.getParentElementOf(prevContainer, ["TABLE"]), true);
      -1050 				return next;
      -1051 			}
      -1052 			
      -1053 			// if prev is same with next, do nothing
      -1054 			if(prev == next) return null;
      -1055 
      -1056 			// if there is a null block, do nothing
      -1057 			if(!prev || !next || !prevContainer || !nextContainer) return null;
      -1058 			
      -1059 			// if two blocks are not in the same table cell, do nothing
      -1060 			if(this.getParentElementOf(prev, ["TD", "TH"]) != this.getParentElementOf(next, ["TD", "TH"])) return null;
      -1061 			
      -1062 			var prevIsEmpty = false;
      -1063 			
      -1064 			// cleanup empty block before merge
      -1065 
      -1066 			// 1. cleanup prev node which ends with marker +  
      -1067 			if(
      -1068 				xq.Browser.isTrident &&
      -1069 				prev.childNodes.length >= 2 &&
      -1070 				this.isMarker(prev.lastChild.previousSibling) &&
      -1071 				prev.lastChild.nodeType == 3 &&
      -1072 				prev.lastChild.nodeValue.length == 1 &&
      -1073 				prev.lastChild.nodeValue.charCodeAt(0) == 160
      -1074 			) {
      -1075 				this.deleteNode(prev.lastChild);
      -1076 			}
      -1077 
      -1078 			// 2. cleanup prev node (if prev is empty, then replace prev's tag with next's)
      -1079 			this.removePlaceHoldersAndEmptyNodes(prev);
      -1080 			if(this.isEmptyBlock(prev)) {
      -1081 				// replace atomic block with normal block so that following code don't need to care about atomic block
      -1082 				if(this.tree.isAtomic(prev)) prev = this.replaceTag("P", prev);
      -1083 				
      -1084 				prev = this.replaceTag(next.nodeName, prev) || prev;
      -1085 				prev.innerHTML = "";
      -1086 			} else if(prev.firstChild == prev.lastChild && this.isMarker(prev.firstChild)) {
      -1087 				prev = this.replaceTag(next.nodeName, prev) || prev;
      -1088 			}
      -1089 			
      -1090 			// 3. cleanup next node
      -1091 			if(this.isEmptyBlock(next)) {
      -1092 				// replace atomic block with normal block so that following code don't need to care about atomic block
      -1093 				if(this.tree.isAtomic(next)) next = this.replaceTag("P", next);
      -1094 				
      -1095 				next.innerHTML = "";
      -1096 			}
      -1097 			
      -1098 			// perform merge
      -1099 			this.moveChildNodes(next, prev);
      -1100 			this.deleteNode(next);
      -1101 			return prev;
      -1102 		} finally {
      -1103 			// cleanup
      -1104 			if(prevContainer && this.isEmptyBlock(prevContainer)) this.deleteNode(prevContainer, true);
      -1105 			if(nextContainer && this.isEmptyBlock(nextContainer)) this.deleteNode(nextContainer, true);
      -1106 			
      -1107 			if(prevContainer) this.unwrapUnnecessaryParagraph(prevContainer);
      -1108 			if(nextContainer) this.unwrapUnnecessaryParagraph(nextContainer);
      -1109 		}
      -1110 	},
      -1111 	
      -1112 	/**
      -1113 	 * Merges adjust list containers which has same tag name
      -1114 	 *
      -1115 	 * @param {Element} container target list container
      -1116 	 * @param {boolean} force force adjust list container even if they have different list type
      -1117 	 * @param {String} dir Specify merge direction: PREV or NEXT. If not supplied it will be merged with both direction.
      -1118 	 */
      -1119 	mergeAdjustLists: function(container, force, dir) {
      -1120 		var prev = container.previousSibling;
      -1121 		var isPrevSame = prev && (prev.nodeName == container.nodeName && prev.className == container.className);
      -1122 		if((!dir || dir.toLowerCase() == 'prev') && (isPrevSame || (force && this.tree.isListContainer(prev)))) {
      -1123 			while(prev.lastChild) {
      -1124 				this.insertNodeAt(prev.lastChild, container, "start");
      -1125 			}
      -1126 			this.deleteNode(prev);
      -1127 		}
      -1128 		
      -1129 		var next = container.nextSibling;
      -1130 		var isNextSame = next && (next.nodeName == container.nodeName && next.className == container.className);
      -1131 		if((!dir || dir.toLowerCase() == 'next') && (isNextSame || (force && this.tree.isListContainer(next)))) {
      -1132 			while(next.firstChild) {
      -1133 				this.insertNodeAt(next.firstChild, container, "end");
      -1134 			}
      -1135 			this.deleteNode(next);
      -1136 		}
      -1137 	},
      -1138 	
      -1139 	/**
      -1140 	 * Moves child nodes from one element into another.
      -1141 	 *
      -1142 	 * @param {Elemet} from source element
      -1143 	 * @param {Elemet} to target element
      -1144 	 */
      -1145 	moveChildNodes: function(from, to) {
      -1146 		if(this.tree.isDescendantOf(from, to) || ["HTML", "HEAD"].include(to.nodeName))
      -1147 			throw "Illegal argument. Cannot move children of element[" + from.nodeName + "] to element[" + to.nodeName + "]";
      -1148 		
      -1149 		if(from == to) return;
      -1150 		
      -1151 		while(from.firstChild) to.appendChild(from.firstChild);
      -1152 	},
      -1153 	
      -1154 	/**
      -1155 	 * Copies attributes from one element into another.
      -1156 	 *
      -1157 	 * @param {Element} from source element
      -1158 	 * @param {Element} to target element
      -1159 	 * @param {boolean} copyId copy ID attribute of source element
      -1160 	 */
      -1161 	copyAttributes: function(from, to, copyId) {
      -1162 		// IE overrides this
      -1163 		
      -1164 		var attrs = from.attributes;
      -1165 		if(!attrs) return;
      -1166 		
      -1167 		for(var i = 0; i < attrs.length; i++) {
      -1168 			if(attrs[i].nodeName == "class" && attrs[i].nodeValue) {
      -1169 				to.className = attrs[i].nodeValue;
      -1170 			} else if((copyId || !["id"].include(attrs[i].nodeName)) && attrs[i].nodeValue) {
      -1171 				to.setAttribute(attrs[i].nodeName, attrs[i].nodeValue);
      -1172 			}
      -1173 		}
      -1174 	},
      -1175 
      -1176 	_indentElements: function(node, blocks, affect) {
      -1177 		for (var i=0; i < affect.length; i++) {
      -1178 			if (affect[i] == node || this.tree.isDescendantOf(affect[i], node))
      -1179 				return;
      -1180 		}
      -1181 		leaves = this.tree.getLeavesAtEdge(node);
      -1182 		
      -1183 		if (blocks.include(leaves[0])) {
      -1184 			var affected = this.indentElement(node, true);
      -1185 			if (affected) {
      -1186 				affect.push(affected);
      -1187 				return;
      -1188 			}
      -1189 		}
      -1190 		
      -1191 		if (blocks.include(node)) {
      -1192 			var affected = this.indentElement(node, true);
      -1193 			if (affected) {
      -1194 				affect.push(affected);
      -1195 				return;
      -1196 			}
      -1197 		}
      -1198 
      -1199 		var children=$A(node.childNodes);
      -1200 		for (var i=0; i < children.length; i++)
      -1201 			this._indentElements(children[i], blocks, affect);
      -1202 		return;
      -1203 	},
      -1204 
      -1205 	indentElements: function(from, to) {
      -1206 		var blocks = this.getBlockElementsBetween(from, to);
      -1207 		var top = this.tree.findCommonAncestorAndImmediateChildrenOf(from, to);
      -1208 		
      -1209 		var affect = [];
      -1210 		
      -1211 		leaves = this.tree.getLeavesAtEdge(top.parent);
      -1212 		if (blocks.include(leaves[0])) {
      -1213 			var affected = this.indentElement(top.parent);
      -1214 			if (affected)
      -1215 				return [affected];
      -1216 		}
      -1217 		
      -1218 		var children = $A(top.parent.childNodes);
      -1219 		for (var i=0; i < children.length; i++) {
      -1220 			this._indentElements(children[i], blocks, affect);
      -1221 		}
      -1222 		
      -1223 		affect = affect.flatten()
      -1224 		return affect.length > 0 ? affect : blocks;
      -1225 	},
      -1226 	
      -1227 	outdentElementsCode: function(node) {
      -1228 		if (node.tagName == 'LI')
      -1229 			node = node.parentNode;
      -1230 		if (node.tagName == 'OL' && node.className == 'code')
      -1231 			return true;
      -1232 		return false;
      -1233 	},
      -1234 	
      -1235 	_outdentElements: function(node, blocks, affect) {
      -1236 		for (var i=0; i < affect.length; i++) {
      -1237 			if (affect[i] == node || this.tree.isDescendantOf(affect[i], node))
      -1238 				return;
      -1239 		}
      -1240 		leaves = this.tree.getLeavesAtEdge(node);
      -1241 		
      -1242 		if (blocks.include(leaves[0]) && !this.outdentElementsCode(leaves[0])) {
      -1243 			var affected = this.outdentElement(node, true);
      -1244 			if (affected) {
      -1245 				affect.push(affected);
      -1246 				return;
      -1247 			}
      -1248 		}
      -1249 		
      -1250 		if (blocks.include(node)) {
      -1251 			var children = $A(node.parentNode.childNodes);
      -1252 			var isCode = this.outdentElementsCode(node);
      -1253 			var affected = this.outdentElement(node, true, isCode);
      -1254 			if (affected) {
      -1255 				if (children.include(affected) && this.tree.isListContainer(node.parentNode) && !isCode) {
      -1256 					for (var i=0; i < children.length; i++) {
      -1257 						if (blocks.include(children[i]) && !affect.include(children[i]))
      -1258 							affect.push(children[i]);
      -1259 					}
      -1260 				}else
      -1261 					affect.push(affected);
      -1262 				return;
      -1263 			}
      -1264 		}
      -1265 
      -1266 		var children=$A(node.childNodes);
      -1267 		for (var i=0; i < children.length; i++)
      -1268 			this._outdentElements(children[i], blocks, affect);
      -1269 		return;
      -1270 	},
      -1271 
      -1272 	outdentElements: function(from, to) {
      -1273 		var start, end;
      -1274 		
      -1275 		if (from.parentNode.tagName == 'LI') start=from.parentNode;
      -1276 		if (to.parentNode.tagName == 'LI') end=to.parentNode;
      -1277 		
      -1278 		var blocks = this.getBlockElementsBetween(from, to);
      -1279 		var top = this.tree.findCommonAncestorAndImmediateChildrenOf(from, to);
      -1280 		
      -1281 		var affect = [];
      -1282 		
      -1283 		leaves = this.tree.getLeavesAtEdge(top.parent);
      -1284 		if (blocks.include(leaves[0]) && !this.outdentElementsCode(top.parent)) {
      -1285 			var affected = this.outdentElement(top.parent);
      -1286 			if (affected)
      -1287 				return [affected];
      -1288 		}
      -1289 		
      -1290 		var children = $A(top.parent.childNodes);
      -1291 		for (var i=0; i < children.length; i++) {
      -1292 			this._outdentElements(children[i], blocks, affect);
      -1293 		}
      -1294 
      -1295 		if (from.offsetParent && to.offsetParent) {
      -1296 			start = from;
      -1297 			end = to;
      -1298 		}else if (blocks.first().offsetParent && blocks.last().offsetParent) {
      -1299 			start = blocks.first();
      -1300 			end = blocks.last();
      -1301 		}
      -1302 		
      -1303 		affect = affect.flatten()
      -1304 		if (!start || !start.offsetParent)
      -1305 			start = affect.first();
      -1306 		if (!end || !end.offsetParent)
      -1307 			end = affect.last();
      -1308 		
      -1309 		return this.getBlockElementsBetween(start, end);
      -1310 	},
      -1311 	
      -1312 	/**
      -1313 	 * Performs indent by increasing element's margin-left
      -1314 	 */	
      -1315 	indentElement: function(element, noParent, forceMargin) {
      -1316 		if(
      -1317 			!forceMargin &&
      -1318 			(element.nodeName == "LI" || (!this.tree.isListContainer(element) && !element.previousSibling && element.parentNode.nodeName == "LI"))
      -1319 		) return this.indentListItem(element, noParent);
      -1320 		
      -1321 		var root = this.getRoot();
      -1322 		if(!element || element == root) return null;
      -1323 		
      -1324 		if (element.parentNode != root && !element.previousSibling && !noParent) element=element.parentNode;
      -1325 		
      -1326 		var margin = element.style.marginLeft;
      -1327 		var cssValue = margin ? this._getCssValue(margin, "px") : {value:0, unit:"em"};
      -1328 		
      -1329 		cssValue.value += 2;
      -1330 		element.style.marginLeft = cssValue.value + cssValue.unit;
      -1331 		
      -1332 		return element;
      -1333 	},
      -1334 	
      -1335 	/**
      -1336 	 * Performs outdent by decreasing element's margin-left
      -1337 	 */	
      -1338 	outdentElement: function(element, noParent, forceMargin) {
      -1339 		if(!forceMargin && element.nodeName == "LI") return this.outdentListItem(element, noParent);
      -1340 		
      -1341 		var root = this.getRoot();
      -1342 		if(!element || element == root) return null;
      -1343 		
      -1344 		var margin = element.style.marginLeft;
      -1345 		
      -1346 		var cssValue = margin ? this._getCssValue(margin, "px") : {value:0, unit:"em"};
      -1347 		if(cssValue.value == 0) {
      -1348 			return element.previousSibling || forceMargin ?
      -1349 				null :
      -1350 				this.outdentElement(element.parentNode, noParent);
      -1351 		}
      -1352 		
      -1353 		cssValue.value -= 2;
      -1354 		element.style.marginLeft = cssValue.value <= 0 ? "" : cssValue.value + cssValue.unit;
      -1355 		if(element.style.cssText == "") element.removeAttribute("style");
      -1356 		
      -1357 		return element;
      -1358 	},
      -1359 	
      -1360 	/**
      -1361 	 * Performs indent for list item
      -1362 	 */
      -1363 	indentListItem: function(element, treatListAsNormalBlock) {
      -1364 		var li = this.getParentElementOf(element, ["LI"]);
      -1365 		var container = li.parentNode;
      -1366 		var prev = li.previousSibling;
      -1367 		if(!li.previousSibling) return this.indentElement(container);
      -1368 		
      -1369 		if(li.parentNode.nodeName == "OL" && li.parentNode.className == "code") return this.indentElement(li, treatListAsNormalBlock, true);
      -1370 		
      -1371 		if(!prev.lastChild) prev.appendChild(this.makePlaceHolder());
      -1372 		
      -1373 		var targetContainer = 
      -1374 			this.tree.isListContainer(prev.lastChild) ?
      -1375 			// if there's existing list container, select it as target container
      -1376 			prev.lastChild :
      -1377 			// if there's nothing, create new one
      -1378 			this.insertNodeAt(this.createElement(container.nodeName), prev, "end");
      -1379 		
      -1380 		this.wrapAllInlineOrTextNodesAs("P", prev, true);
      -1381 		
      -1382 		// perform move
      -1383 		targetContainer.appendChild(li);
      -1384 		
      -1385 		// flatten nested list
      -1386 		if(!treatListAsNormalBlock && li.lastChild && this.tree.isListContainer(li.lastChild)) {
      -1387 			var childrenContainer = li.lastChild;
      -1388 			var child;
      -1389 			while(child = childrenContainer.lastChild) {
      -1390 				this.insertNodeAt(child, li, "after");
      -1391 			}
      -1392 			this.deleteNode(childrenContainer);
      -1393 		}
      -1394 		
      -1395 		this.unwrapUnnecessaryParagraph(li);
      -1396 		
      -1397 		return li;
      -1398 	},
      -1399 	
      -1400 	/**
      -1401 	 * Performs outdent for list item
      -1402 	 *
      -1403 	 * @return {Element} outdented list item or null if no outdent performed
      -1404 	 */
      -1405 	outdentListItem: function(element, treatListAsNormalBlock) {
      -1406 		var li = this.getParentElementOf(element, ["LI"]);
      -1407 		var container = li.parentNode;
      -1408 
      -1409 		if(!li.previousSibling) {
      -1410 			var performed = this.outdentElement(container);
      -1411 			if(performed) return performed;
      -1412 		}
      -1413 
      -1414 		if(li.parentNode.nodeName == "OL" && li.parentNode.className == "code") return this.outdentElement(li, treatListAsNormalBlock, true);
      -1415 		
      -1416 		var parentLi = container.parentNode;
      -1417 		if(parentLi.nodeName != "LI") return null;
      -1418 		
      -1419 		if(treatListAsNormalBlock) {
      -1420 			while(container.lastChild != li) {
      -1421 				this.insertNodeAt(container.lastChild, parentLi, "after");
      -1422 			}
      -1423 		} else {
      -1424 			// make next siblings as children
      -1425 			if(li.nextSibling) {
      -1426 				var targetContainer =
      -1427 					li.lastChild && this.tree.isListContainer(li.lastChild) ?
      -1428 						// if there's existing list container, select it as target container
      -1429 						li.lastChild :
      -1430 						// if there's nothing, create new one
      -1431 						this.insertNodeAt(this.createElement(container.nodeName), li, "end");
      -1432 				
      -1433 				this.copyAttributes(container, targetContainer);
      -1434 				
      -1435 				var sibling;
      -1436 				while(sibling = li.nextSibling) {
      -1437 					targetContainer.appendChild(sibling);
      -1438 				}
      -1439 			}
      -1440 		}
      -1441 		
      -1442 		// move current LI into parent LI's next sibling
      -1443 		li = this.insertNodeAt(li, parentLi, "after");
      -1444 		
      -1445 		// remove empty container
      -1446 		if(container.childNodes.length == 0) this.deleteNode(container);
      -1447 		
      -1448 		if(li.firstChild && this.tree.isListContainer(li.firstChild)) {
      -1449 			this.insertNodeAt(this.makePlaceHolder(), li, "start");
      -1450 		}
      -1451 		
      -1452 		this.wrapAllInlineOrTextNodesAs("P", li);
      -1453 		this.unwrapUnnecessaryParagraph(parentLi);
      -1454 		
      -1455 		return li;
      -1456 	},
      -1457 	
      -1458 	/**
      -1459 	 * Performs justification
      -1460 	 *
      -1461 	 * @param {Element} block target element
      -1462 	 * @param {String} dir one of "LEFT", "CENTER", "RIGHT", "BOTH"
      -1463 	 */
      -1464 	justifyBlock: function(block, dir) {
      -1465 		// if block is only child, select its parent as mover
      -1466 		while(block.parentNode != this.getRoot() && !block.previousSibling && !block.nextSibling && !this.tree.isListContainer(block.parentNode)) {
      -1467 			block = block.parentNode;
      -1468 		}
      -1469 		
      -1470 		var styleValue = dir.toLowerCase() == "both" ? "justify" : dir;
      -1471 		if(styleValue == "left") {
      -1472 			block.style.textAlign = "";
      -1473 			if(block.style.cssText == "") block.removeAttribute("style");
      -1474 		} else {
      -1475 			block.style.textAlign = styleValue;
      -1476 		}
      -1477 		return block;
      -1478 	},
      -1479 	
      -1480 	justifyBlocks: function(blocks, dir) {
      -1481 		blocks.each(function(block) {
      -1482 			this.justifyBlock(block, dir);
      -1483 		}.bind(this));
      -1484 		
      -1485 		return blocks;
      -1486 	},
      -1487 	
      -1488 	/**
      -1489      * Turn given element into list. If the element is a list already, it will be reversed into normal element.
      -1490 	 *
      -1491 	 * @param {Element} element target element
      -1492 	 * @param {String} type one of "UL", "OL"
      -1493 	 * @returns {Element} affected element
      -1494 	 */
      -1495 	applyList: function(element, type) {
      -1496 		type = type.toUpperCase();
      -1497 		var containerTag = type == "UL" ? "UL" : "OL";
      -1498 		
      -1499 		if(element.nodeName == "LI" || (element.parentNode.nodeName == "LI" && !element.previousSibling)) {
      -1500 			var element = this.getParentElementOf(element, ["LI"]);
      -1501 			var container = element.parentNode;
      -1502 			if(container.nodeName == containerTag) {
      -1503 				return this.extractOutElementFromParent(element);
      -1504 			} else {
      -1505 				return this.changeListTypeTo(element, type);
      -1506 			}
      -1507 		} else {
      -1508 			return this.turnElementIntoListItem(element, type);
      -1509 		}
      -1510 	},
      -1511 	
      -1512 	applyLists: function(from, to, type) {
      -1513 		type = type.toUpperCase();
      -1514 		var containerTag = type == "UL" ? "UL" : "OL";
      -1515 		var blocks = this.getBlockElementsBetween(from, to);
      -1516 		
      -1517 		// LIs or Non-containing blocks
      -1518 		var whole = blocks.findAll(function(e) {
      -1519 			return e.nodeName == "LI" || !this.tree.isBlockContainer(e);
      -1520 		}.bind(this));
      -1521 		
      -1522 		// LIs
      -1523 		var listItems = whole.findAll(function(e) {return e.nodeName == "LI"}.bind(this));
      -1524 		
      -1525 		// Non-containing blocks which is not a descendant of any LIs selected above(listItems).
      -1526 		var normalBlocks = whole.findAll(function(e) {
      -1527 			return e.nodeName != "LI" &&
      -1528 				!(e.parentNode.nodeName == "LI" && !e.previousSibling && !e.nextSibling) &&
      -1529 				!this.tree.isDescendantOf(listItems, e)
      -1530 		}.bind(this));
      -1531 		
      -1532 		var diffListItems = listItems.findAll(function(e) {
      -1533 			return e.parentNode.nodeName != containerTag;
      -1534 		}.bind(this));
      -1535 		
      -1536 		// Conditions needed to determine mode
      -1537 		var hasNormalBlocks = normalBlocks.length > 0;
      -1538 		var hasDifferentListStyle = diffListItems.length > 0;
      -1539 		
      -1540 		var blockToHandle = null;
      -1541 		
      -1542 		if(hasNormalBlocks) {
      -1543 			blockToHandle = normalBlocks;
      -1544 		} else if(hasDifferentListStyle) {
      -1545 			blockToHandle = diffListItems;
      -1546 		} else {
      -1547 			blockToHandle = listItems;
      -1548 		}
      -1549 		
      -1550 		// perform operation
      -1551 		for(var i = 0; i < blockToHandle.length; i++) {
      -1552 			var block = blockToHandle[i];
      -1553 			
      -1554 			// preserve original index to restore selection
      -1555 			var originalIndex = blocks.indexOf(block);
      -1556 			blocks[originalIndex] = this.applyList(block, type);
      -1557 		}
      -1558 		
      -1559 		return blocks;
      -1560 	},
      -1561 
      -1562 	/**
      -1563 	 * Insert place-holder for given empty element. Empty element does not displayed and causes many editing problems.
      -1564 	 *
      -1565 	 * @param {Element} element empty element
      -1566 	 */
      -1567 	correctEmptyElement: function(element) {throw "Not implemented"},
      -1568 
      -1569 	/**
      -1570 	 * Corrects current block-only-container to do not take any non-block element or node.
      -1571 	 */
      -1572 	correctParagraph: function() {throw "Not implemented"},
      -1573 	
      -1574 	/**
      -1575 	 * Makes place-holder for empty element.
      -1576 	 *
      -1577 	 * @returns {Node} Platform specific place holder
      -1578 	 */
      -1579 	makePlaceHolder: function() {throw "Not implemented"},
      -1580 	
      -1581 	/**
      -1582 	 * Makes place-holder string.
      -1583 	 *
      -1584 	 * @returns {String} Platform specific place holder string
      -1585 	 */
      -1586 	makePlaceHolderString: function() {throw "Not implemented"},
      -1587 	
      -1588 	/**
      -1589 	 * Makes empty paragraph which contains only one place-holder
      -1590 	 */
      -1591 	makeEmptyParagraph: function() {throw "Not implemented"},
      -1592 
      -1593 	/**
      -1594 	 * Applies background color to selected area
      -1595 	 *
      -1596 	 * @param {Object} color valid CSS color value
      -1597 	 */
      -1598 	applyBackgroundColor: function(color) {throw "Not implemented";},
      -1599 
      -1600 	/**
      -1601 	 * Applies foreground color to selected area
      -1602 	 *
      -1603 	 * @param {Object} color valid CSS color value
      -1604 	 */
      -1605 	applyForegroundColor: function(color) {
      -1606 		this.execCommand("forecolor", color);
      -1607 	},
      -1608 	
      -1609 	execCommand: function(commandId, param) {throw "Not implemented";},
      -1610 	
      -1611 	applyRemoveFormat: function() {throw "Not implemented";},
      -1612 	applyEmphasis: function() {throw "Not implemented";},
      -1613 	applyStrongEmphasis: function() {throw "Not implemented";},
      -1614 	applyStrike: function() {throw "Not implemented";},
      -1615 	applyUnderline: function() {throw "Not implemented";},
      -1616 	applySuperscription: function() {
      -1617 		this.execCommand("superscript");
      -1618 	},
      -1619 	applySubscription: function() {
      -1620 		this.execCommand("subscript");
      -1621 	},
      -1622 	indentBlock: function(element, treatListAsNormalBlock) {
      -1623 		return (!element.previousSibling && element.parentNode.nodeName == "LI") ?
      -1624 			this.indentListItem(element, treatListAsNormalBlock) :
      -1625 			this.indentElement(element);
      -1626 	},
      -1627 	outdentBlock: function(element, treatListAsNormalBlock) {
      -1628 		while(true) {
      -1629 			if(!element.previousSibling && element.parentNode.nodeName == "LI") {
      -1630 				element = this.outdentListItem(element, treatListAsNormalBlock);
      -1631 				return element;
      -1632 			} else {
      -1633 				var performed = this.outdentElement(element);
      -1634 				if(performed) return performed;
      -1635 				
      -1636 				// first-child can outdent container
      -1637 				if(!element.previousSibling) {
      -1638 					element = element.parentNode;
      -1639 				} else {
      -1640 					break;
      -1641 				}
      -1642 			}
      -1643 		}
      -1644 		
      -1645 		return null;
      -1646 	},
      -1647 	wrapBlock: function(tag, start, end) {
      -1648 		if(!this.tree._blockTags.include(tag)) throw "Unsuppored block container: [" + tag + "]";
      -1649 		if(!start) start = this.getCurrentBlockElement();
      -1650 		if(!end) end = start;
      -1651 		
      -1652 		// Check if the selection captures valid fragement
      -1653 		var validFragment = false;
      -1654 		
      -1655 		if(start == end) {
      -1656 			// are they same block?
      -1657 			validFragment = true;
      -1658 		} else if(start.parentNode == end.parentNode && !start.previousSibling && !end.nextSibling) {
      -1659 			// are they covering whole parent?
      -1660 			validFragment = true;
      -1661 			start = end = start.parentNode;
      -1662 		} else {
      -1663 			// are they siblings of non-LI blocks?
      -1664 			validFragment =
      -1665 				(start.parentNode == end.parentNode) &&
      -1666 				(start.nodeName != "LI");
      -1667 		}
      -1668 		
      -1669 		if(!validFragment) return null;
      -1670 		
      -1671 		var wrapper = this.createElement(tag);
      -1672 		
      -1673 		if(start == end) {
      -1674 			// They are same.
      -1675 			if(this.tree.isBlockContainer(start) && !this.tree.isListContainer(start)) {
      -1676 				// It's a block container. Wrap its contents.
      -1677 				if(this.tree.isBlockOnlyContainer(wrapper)) {
      -1678 					this.correctEmptyElement(start);
      -1679 					this.wrapAllInlineOrTextNodesAs("P", start, true);
      -1680 				}
      -1681 				this.moveChildNodes(start, wrapper);
      -1682 				start.appendChild(wrapper);
      -1683 			} else {
      -1684 				// It's not a block container. Wrap itself.
      -1685 				wrapper = this.insertNodeAt(wrapper, start, "after");
      -1686 				wrapper.appendChild(start);
      -1687 			}
      -1688 			
      -1689 			this.correctEmptyElement(wrapper);
      -1690 		} else {
      -1691 			// They are siblings. Wrap'em all.
      -1692 			wrapper = this.insertNodeAt(wrapper, start, "before");
      -1693 			var node = start;
      -1694 			
      -1695 			while(node != end) {
      -1696 				next = node.nextSibling;
      -1697 				wrapper.appendChild(node);
      -1698 				node = next;
      -1699 			}
      -1700 			wrapper.appendChild(node);
      -1701 		}
      -1702 		
      -1703 		return wrapper;
      -1704 	},
      -1705 
      -1706 
      -1707 	
      -1708 	/////////////////////////////////////////////
      -1709 	// Focus/Caret/Selection
      -1710 	
      -1711 	/**
      -1712 	 * Gives focus to root element's window
      -1713 	 */
      -1714 	focus: function() {throw "Not implemented";},
      -1715 
      -1716 	/**
      -1717 	 * Returns selection object
      -1718 	 */
      -1719 	sel: function() {throw "Not implemented";},
      -1720 	
      -1721 	/**
      -1722 	 * Returns range object
      -1723 	 */
      -1724 	rng: function() {throw "Not implemented";},
      -1725 	
      -1726 	/**
      -1727 	 * Returns true if DOM has selection
      -1728 	 */
      -1729 	hasSelection: function() {throw "Not implemented";},
      -1730 
      -1731 	/**
      -1732 	 * Returns true if root element's window has selection
      -1733 	 */
      -1734 	hasFocus: function() {
      -1735 		var cur = this.getCurrentElement();
      -1736 		return (cur && cur.ownerDocument == this.getDoc());
      -1737 	},
      -1738 	
      -1739 	/**
      -1740 	 * Adjust scrollbar to make the element visible in current viewport.
      -1741 	 *
      -1742 	 * @param {Element} element Target element
      -1743 	 * @param {boolean} toTop Align element to top of the viewport
      -1744 	 * @param {boolean} moveCaret Move caret to the element
      -1745 	 */
      -1746 	scrollIntoView: function(element, toTop, moveCaret) {
      -1747 		element.scrollIntoView(toTop);
      -1748 		if(moveCaret) this.placeCaretAtStartOf(element);
      -1749 	},
      -1750 	
      -1751 	/**
      -1752 	 * Select all document
      -1753 	 */
      -1754 	selectAll: function() {
      -1755 		return this.execCommand('selectall');
      -1756 	},
      -1757 	
      -1758 	/**
      -1759 	 * Select specified element.
      -1760 	 *
      -1761 	 * @param {Element} element element to select
      -1762 	 * @param {boolean} entireElement true to select entire element, false to select inner content of element 
      -1763 	 */
      -1764 	selectElement: function(node, entireElement) {throw "Not implemented"},
      -1765 	
      -1766 	/**
      -1767 	 * Select all elements between two blocks(inclusive).
      -1768 	 *
      -1769 	 * @param {Element} start start of selection
      -1770 	 * @param {Element} end end of selection
      -1771 	 */
      -1772 	selectBlocksBetween: function(start, end) {throw "Not implemented"},
      -1773 	
      -1774 	/**
      -1775 	 * Delete selected area
      -1776 	 */
      -1777 	deleteSelection: function() {throw "Not implemented"},
      -1778 	
      -1779 	/**
      -1780 	 * Collapses current selection.
      -1781 	 *
      -1782 	 * @param {boolean} toStart true to move caret to start of selected area.
      -1783 	 */
      -1784 	collapseSelection: function(toStart) {throw "Not implemented"},
      -1785 	
      -1786 	/**
      -1787 	 * Returns selected area as HTML string
      -1788 	 */
      -1789 	getSelectionAsHtml: function() {throw "Not implemented"},
      -1790 	
      -1791 	/**
      -1792 	 * Returns selected area as text string
      -1793 	 */
      -1794 	getSelectionAsText: function() {throw "Not implemented"},
      -1795 	
      -1796 	/**
      -1797 	 * Places caret at start of the element
      -1798 	 *
      -1799 	 * @param {Element} element Target element
      -1800 	 */
      -1801 	placeCaretAtStartOf: function(element) {throw "Not implemented"},
      -1802 	
      -1803 	/**
      -1804 	 * Checks if the node is empty-text-node or not
      -1805 	 */
      -1806 	isEmptyTextNode: function(node) {
      -1807 		return node.nodeType == 3 && node.nodeValue.length == 0;
      -1808 	},
      -1809 	
      -1810 	/**
      -1811 	 * Checks if the caret is place in empty block element
      -1812 	 */
      -1813 	isCaretAtEmptyBlock: function() {
      -1814 		return this.isEmptyBlock(this.getCurrentBlockElement());
      -1815 	},
      -1816 	
      -1817 	/**
      -1818 	 * Checks if the caret is place at start of the block
      -1819 	 */
      -1820 	isCaretAtBlockStart: function() {throw "Not implemented"},
      -1821 
      -1822 	/**
      -1823 	 * Checks if the caret is place at end of the block
      -1824 	 */
      -1825 	isCaretAtBlockEnd: function() {throw "Not implemented"},
      -1826 	
      -1827 	/**
      -1828 	 * Saves current selection info
      -1829 	 *
      -1830 	 * @returns {Object} Bookmark for selection
      -1831 	 */
      -1832 	saveSelection: function() {throw "Not implemented"},
      -1833 	
      -1834 	/**
      -1835 	 * Restores current selection info
      -1836 	 *
      -1837 	 * @param {Object} bookmark Bookmark
      -1838 	 */
      -1839 	restoreSelection: function(bookmark) {throw "Not implemented"},
      -1840 	
      -1841 	/**
      -1842 	 * Create marker
      -1843 	 */
      -1844 	createMarker: function() {
      -1845 		var marker = this.createElement("SPAN");
      -1846 		marker.id = "xquared_marker_" + (this._lastMarkerId++);
      -1847 		marker.className = "xquared_marker";
      -1848 		return marker;
      -1849 	},
      -1850 
      -1851 	/**
      -1852 	 * Create and insert marker into current caret position.
      -1853 	 * Marker is an inline element which has no child nodes. It can be used with many purposes.
      -1854 	 * For example, You can push marker to mark current caret position.
      -1855 	 *
      -1856 	 * @returns {Element} marker
      -1857 	 */
      -1858 	pushMarker: function() {
      -1859 		var marker = this.createMarker();
      -1860 		return this.insertNode(marker);
      -1861 	},
      -1862 	
      -1863 	/**
      -1864 	 * Removes last marker
      -1865 	 *
      -1866 	 * @params {boolean} moveCaret move caret into marker before delete.
      -1867 	 */
      -1868 	popMarker: function(moveCaret) {
      -1869 		var id = "xquared_marker_" + (--this._lastMarkerId);
      -1870 		var marker = this.$(id);
      -1871 		if(!marker) return;
      -1872 		
      -1873 		if(moveCaret) {
      -1874 			this.selectElement(marker, true);
      -1875 			this.collapseSelection(false);
      -1876 		}
      -1877 		
      -1878 		this.deleteNode(marker);
      -1879 	},
      -1880 	
      -1881 	
      -1882 	
      -1883 	/////////////////////////////////////////////
      -1884 	// Query methods
      -1885 	
      -1886 	isMarker: function(node) {
      -1887 		return (node.nodeType == 1 && node.nodeName == "SPAN" && node.className == "xquared_marker");
      -1888 	},
      -1889 	
      -1890 	isFirstBlockOfBody: function(block) {
      -1891 		var root = this.getRoot();
      -1892 		var found = this.tree.findBackward(
      -1893 			block,
      -1894 			function(node) {return (node == root) || node.previousSibling;}.bind(this)
      -1895 		);
      -1896 		
      -1897 		return found == root;
      -1898 	},
      -1899 	
      -1900 	/**
      -1901 	 * Returns outer HTML of given element
      -1902 	 */
      -1903 	getOuterHTML: function(element) {throw "Not implemented"},
      -1904 	
      -1905 	/**
      -1906 	 * Returns inner text of given element
      -1907 	 * 
      -1908 	 * @param {Element} element Target element
      -1909 	 * @returns {String} Text string
      -1910 	 */
      -1911 	getInnerText: function(element) {
      -1912 		return element.innerHTML.stripTags();
      -1913 	},
      -1914 
      -1915 	/**
      -1916 	 * Checks if given node is place holder or not.
      -1917 	 * 
      -1918 	 * @param {Node} node DOM node
      -1919 	 */
      -1920 	isPlaceHolder: function(node) {throw "Not implemented"},
      -1921 	
      -1922 	/**
      -1923 	 * Checks if given block is the first LI whose next sibling is a nested list.
      -1924 	 *
      -1925 	 * @param {Element} block Target block
      -1926 	 */
      -1927 	isFirstLiWithNestedList: function(block) {
      -1928 		return !block.previousSibling &&
      -1929 			block.parentNode.nodeName == "LI" &&
      -1930 			this.tree.isListContainer(block.nextSibling);
      -1931 	},
      -1932 	
      -1933 	/**
      -1934 	 * Search all links within given element
      -1935 	 *
      -1936 	 * @param {Element} [element] Container element. If not given, the root element will be used.
      -1937 	 * @param {Array} [found] if passed, links will be appended into this array.
      -1938 	 * @returns {Array} Array of anchors. It returns empty array if there's no links.
      -1939 	 */
      -1940 	searchAnchors: function(element, found) {
      -1941 		if(!element) element = this.getRoot();
      -1942 		if(!found) found = [];
      -1943 
      -1944 		var anchors = element.getElementsByTagName("A");
      -1945 		for(var i = 0; i < anchors.length; i++) {
      -1946 			found.push(anchors[i]);
      -1947 		}
      -1948 
      -1949 		return found;
      -1950 	},
      -1951 	
      -1952 	/**
      -1953 	 * Search all headings within given element
      -1954 	 *
      -1955 	 * @param {Element} [element] Container element. If not given, the root element will be used.
      -1956 	 * @param {Array} [found] if passed, headings will be appended into this array.
      -1957 	 * @returns {Array} Array of headings. It returns empty array if there's no headings.
      -1958 	 */
      -1959 	searchHeadings: function(element, found) {
      -1960 		if(!element) element = this.getRoot();
      -1961 		if(!found) found = [];
      -1962 
      -1963 		var regexp = /^h[1-6]/ig;
      -1964 
      -1965 		if (!element.childNodes) return [];
      -1966 		$A(element.childNodes).each(function(child) {
      -1967 			var isContainer = child && this.tree._blockContainerTags.include(child.nodeName);
      -1968 			var isHeading = child && child.nodeName.match(regexp);
      -1969 
      -1970 			if (isContainer) {
      -1971 				this.searchHeadings(child, found);
      -1972 			} else if (isHeading) {
      -1973 				found.push(child);
      -1974 			}
      -1975 		}.bind(this));
      -1976 
      -1977 		return found;
      -1978 	},
      -1979 	
      -1980 	/**
      -1981 	 * Collect structure and style informations of given element.
      -1982 	 *
      -1983 	 * @param {Element} element target element
      -1984 	 * @returns {Object} object that contains information: {em: true, strong: false, block: "p", list: "ol", ...}
      -1985 	 */
      -1986 	collectStructureAndStyle: function(element) {
      -1987 		if(!element || element.nodeName == "#document") return {};
      -1988 
      -1989 		var block = this.getParentBlockElementOf(element);
      -1990 		var parents = this.tree.collectParentsOf(element, true, function(node) {return block.parentNode == node});
      -1991 		var blockName = block.nodeName;
      -1992 
      -1993 		var info = {};
      -1994 		
      -1995 		var doc = this.getDoc();
      -1996 		var em = doc.queryCommandState("Italic");
      -1997 		var strong = doc.queryCommandState("Bold");
      -1998 		var strike = doc.queryCommandState("Strikethrough");
      -1999 		var underline = doc.queryCommandState("Underline") && !this.getParentElementOf(element, ["A"]);
      -2000 		var superscription = doc.queryCommandState("superscript");
      -2001 		var subscription = doc.queryCommandState("subscript");
      -2002 		
      -2003 		// if block is only child, select its parent
      -2004 		while(block.parentNode && block.parentNode != this.getRoot() && !block.previousSibling && !block.nextSibling && !this.tree.isListContainer(block.parentNode)) {
      -2005 			block = block.parentNode;
      -2006 		}
      -2007 
      -2008 		var list = false;
      -2009 		if(block.nodeName == "LI") {
      -2010 			var parent = block.parentNode;
      -2011 			var isCode = parent.nodeName == "OL" && parent.className == "code";
      -2012 			list = isCode ? "CODE" : parent.nodeName;
      -2013 		}
      -2014 		
      -2015 		var justification = block.style.textAlign || "left";
      -2016 		
      -2017 		return {
      -2018 			block:blockName,
      -2019 			em: em,
      -2020 			strong: strong,
      -2021 			strike: strike,
      -2022 			underline: underline,
      -2023 			superscription: superscription,
      -2024 			subscription: subscription,
      -2025 			list: list,
      -2026 			justification: justification
      -2027 		};
      -2028 	},
      -2029 	
      -2030 	/**
      -2031 	 * Find elements by CSS selector.
      -2032 	 *
      -2033 	 * WARNING: Use this method carefully since prototype.js doesn't work well with designMode DOM.
      -2034 	 */
      -2035 	findBySelector: function(selector) {
      -2036 		return Element.getElementsBySelector(this.root, selector);
      -2037 	},
      -2038 	
      -2039 	/**
      -2040 	 * Find elements by attribute.
      -2041 	 * 
      -2042 	 * This method will be deprecated when findBySelector get stabilized.
      -2043 	 */
      -2044 	findByAttribute: function(name, value) {
      -2045 		var nodes = [];
      -2046 		this._findByAttribute(nodes, this.root, name, value);
      -2047 		return nodes;
      -2048 	},
      -2049 	
      -2050 	/** @private */
      -2051 	_findByAttribute: function(nodes, element, name, value) {
      -2052 		if(element.getAttribute(name) == value) nodes.push(element);
      -2053 		if(!element.hasChildNodes()) return;
      -2054 		
      -2055 		var children = element.childNodes;
      -2056 		for(var i = 0; i < children.length; i++) {
      -2057 			if(children[i].nodeType == 1) this._findByAttribute(nodes, children[i], name, value);
      -2058 		}
      -2059 	},
      -2060 	
      -2061 	/**
      -2062 	 * Checks if the element has one or more important attributes: id, class, style
      -2063 	 *
      -2064 	 * @param {Element} element Target element
      -2065 	 */
      -2066 	hasImportantAttributes: function(element) {throw "Not implemented"},
      -2067 	
      -2068 	/**
      -2069 	 * Checks if the element is empty or not. Place-holder is not counted as a child.
      -2070 	 *
      -2071 	 * @param {Element} element Target element
      -2072 	 */
      -2073 	isEmptyBlock: function(element) {throw "Not implemented"},
      -2074 	
      -2075 	/**
      -2076 	 * Returns element that contains caret.
      -2077 	 */
      -2078 	getCurrentElement: function() {throw "Not implemented"},
      -2079 	
      -2080 	/**
      -2081 	 * Returns block element that contains caret.
      -2082 	 */
      -2083 	getCurrentBlockElement: function() {
      -2084 		var cur = this.getCurrentElement();
      -2085 		if(!cur) return null;
      -2086 		
      -2087 		var block = this.getParentBlockElementOf(cur);
      -2088 		if(!block) return null;
      -2089 		
      -2090 		return (block.nodeName == "BODY") ? null : block;
      -2091 	},
      -2092 	
      -2093 	/**
      -2094 	 * Returns parent block element of parameter.
      -2095 	 * If the parameter itself is a block, it will be returned.
      -2096 	 *
      -2097 	 * @param {Element} element Target element
      -2098 	 *
      -2099 	 * @returns {Element} Element or null
      -2100 	 */
      -2101 	getParentBlockElementOf: function(element) {
      -2102 		while(element) {
      -2103 			if(this.tree._blockTags.include(element.nodeName)) return element;
      -2104 			element = element.parentNode;
      -2105 		}
      -2106 		return null;
      -2107 	},
      -2108 	
      -2109 	/**
      -2110 	 * Returns parent element of parameter which has one of given tag name.
      -2111 	 * If the parameter itself has the same tag name, it will be returned.
      -2112 	 *
      -2113 	 * @param {Element} element Target element
      -2114 	 * @param {Array} tagNames Array of string which contains tag names
      -2115 	 *
      -2116 	 * @returns {Element} Element or null
      -2117 	 */
      -2118 	getParentElementOf: function(element, tagNames) {
      -2119 		while(element) {
      -2120 			if(tagNames.include(element.nodeName)) return element;
      -2121 			element = element.parentNode;
      -2122 		}
      -2123 		return null;
      -2124 	},
      -2125 	
      -2126 	/**
      -2127 	 * Collects all block elements between two elements
      -2128 	 *
      -2129 	 * @param {Element} from Start element(inclusive)
      -2130 	 * @param {Element} to End element(inclusive)
      -2131 	 */
      -2132 	getBlockElementsBetween: function(from, to) {
      -2133 		return this.tree.collectNodesBetween(from, to, function(node) {
      -2134 			return node.nodeType == 1 && this.tree.isBlock(node);
      -2135 		}.bind(this));
      -2136 	},
      -2137 	
      -2138 	/**
      -2139 	 * Returns block element that contains selection start.
      -2140 	 *
      -2141 	 * This method will return exactly same result with getCurrentBlockElement method
      -2142 	 * when there's no selection.
      -2143 	 */
      -2144 	getBlockElementAtSelectionStart: function() {throw "Not implemented"},
      -2145 	
      -2146 	/**
      -2147 	 * Returns block element that contains selection end.
      -2148 	 *
      -2149 	 * This method will return exactly same result with getCurrentBlockElement method
      -2150 	 * when there's no selection.
      -2151 	 */
      -2152 	getBlockElementAtSelectionEnd: function() {throw "Not implemented"},
      -2153 	
      -2154 	/**
      -2155 	 * Returns blocks at each edge of selection(start and end).
      -2156 	 *
      -2157 	 * TODO: implement ignoreEmptyEdges for FF
      -2158 	 *
      -2159 	 * @param {boolean} naturalOrder Mak the start element always comes before the end element
      -2160 	 * @param {boolean} ignoreEmptyEdges Prevent some browser(Gecko) from selecting one more block than expected
      -2161 	 */
      -2162 	getBlockElementsAtSelectionEdge: function(naturalOrder, ignoreEmptyEdges) {throw "Not implemented"},
      -2163 	
      -2164 	/**
      -2165 	 * Returns array of selected block elements
      -2166 	 */
      -2167 	getSelectedBlockElements: function() {
      -2168 		var selectionEdges = this.getBlockElementsAtSelectionEdge(true, true);
      -2169 		var start = selectionEdges[0];
      -2170 		var end = selectionEdges[1];
      -2171 		
      -2172 		return this.tree.collectNodesBetween(start, end, function(node) {
      -2173 			return node.nodeType == 1 && this.tree.isBlock(node);
      -2174 		}.bind(this));
      -2175 	},
      -2176 	
      -2177 	/**
      -2178 	 * Get element by ID
      -2179 	 *
      -2180 	 * @param {String} id Element's ID
      -2181 	 * @returns {Element} element or null
      -2182 	 */
      -2183 	getElementById: function(id) {return this.doc.getElementById(id)},
      -2184 	
      -2185 	/**
      -2186 	 * Shortcut for #getElementById
      -2187 	 */
      -2188 	$: function(id) {return this.getElementById(id)},
      -2189 	
      -2190 	/**
      -2191 	  * Returns first "valid" child of given element. It ignores empty textnodes.
      -2192 	  *
      -2193 	  * @param {Element} element Target element
      -2194 	  * @returns {Node} first child node or null
      -2195 	  */
      -2196 	getFirstChild: function(element) {
      -2197 		if(!element) return null;
      -2198 		
      -2199 		var nodes = $A(element.childNodes);
      -2200 		for(var i = 0; i < nodes.length; i++) {
      -2201 			if(!this.isEmptyTextNode(nodes[i])) return nodes[i];
      -2202 		}
      -2203 		return null;
      -2204 	},
      -2205 	
      -2206 	/**
      -2207 	  * Returns last "valid" child of given element. It ignores empty textnodes and place-holders.
      -2208 	  *
      -2209 	  * @param {Element} element Target element
      -2210 	  * @returns {Node} last child node or null
      -2211 	  */
      -2212 	getLastChild: function(element) {throw "Not implemented"},
      -2213 
      -2214 	getNextSibling: function(node) {
      -2215 		while(node = node.nextSibling) {
      -2216 			if(node.nodeType != 3 || node.nodeValue.strip() != "") break;
      -2217 		}
      -2218 		return node;
      -2219 	},
      -2220 
      -2221 	getBottommostFirstChild: function(node) {
      -2222 		while(node.firstChild && node.nodeType == 1) node = node.firstChild;
      -2223 		return node;
      -2224 	},
      -2225 	
      -2226 	getBottommostLastChild: function(node) {
      -2227 		while(node.lastChild && node.nodeType == 1) node = node.lastChild;
      -2228 		return node;
      -2229 	},
      -2230 
      -2231 	/** @private */
      -2232 	_getCssValue: function(str, defaultUnit) {
      -2233 		if(!str || str.length == 0) return {value:0, unit:defaultUnit};
      -2234 		
      -2235 		var tokens = str.match(/(\d+)(.*)/);
      -2236 		return {
      -2237 			value:parseInt(tokens[1]),
      -2238 			unit:tokens[2] || defaultUnit
      -2239 		};
      -2240 	}
      -2241 });
      -2242 
      -2243 /**
      -2244  * Creates and returns instance of browser specific implementation.
      -2245  */
      -2246 xq.RichDom.createInstance = function() {
      -2247 	if(xq.Browser.isTrident) {
      -2248 		return new xq.RichDomTrident();
      -2249 	} else if(xq.Browser.isWebkit) {
      -2250 		return new xq.RichDomWebkit();
      -2251 	} else {
      -2252 		return new xq.RichDomGecko();
      -2253 	}
      -2254 }
      -2255 
      \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_07.html b/modules/editor/skins/xquared/doc/api/src_07.html deleted file mode 100644 index 6b89ca0d2..000000000 --- a/modules/editor/skins/xquared/doc/api/src_07.html +++ /dev/null @@ -1,54 +0,0 @@ -
        1 /**
      -  2  * RichDom for Gecko
      -  3  */
      -  4 xq.RichDomGecko = Class.create(xq.RichDomW3, {
      -  5 	makePlaceHolder: function() {
      -  6 		var holder = this.createElement("BR");
      -  7 		holder.setAttribute("type", "_moz");
      -  8 		return holder;
      -  9 	},
      - 10 	
      - 11 	makePlaceHolderString: function() {
      - 12 		return '<br type="_moz" />';
      - 13 	},
      - 14 	
      - 15 	makeEmptyParagraph: function() {
      - 16 		return this.createElementFromHtml('<p><br type="_moz" /></p>');
      - 17 	},
      - 18 
      - 19 	isPlaceHolder: function(node) {
      - 20 		if(node.nodeType != 1) return false;
      - 21 		
      - 22 		var typeMatches = node.nodeName == "BR" && node.getAttribute("type") == "_moz";
      - 23 		if(typeMatches) return true;
      - 24 		
      - 25 		var positionMatches = node.nodeName == "BR" && !this.getNextSibling(node);
      - 26 		if(positionMatches) return true;
      - 27 		
      - 28 		return false;
      - 29 	},
      - 30 
      - 31 	selectElement: function(element, entireElement) {
      - 32 		if(!element) throw "[element] is null";
      - 33 		if(element.nodeType != 1) throw "[element] is not an element";
      - 34 
      - 35 		// required to avoid Windows FF selection bug.
      - 36 		try {
      - 37 			if(!xq.Browser.isMac) this.doc.execCommand("SelectAll", false, null);
      - 38 		} catch(ignored) {}
      - 39 		
      - 40 		if(entireElement) {
      - 41 			this.rng().selectNode(element);
      - 42 		} else {
      - 43 			this.rng().selectNodeContents(element);
      - 44 		}
      - 45 	}
      - 46 });
      - 47 
      \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_08.html b/modules/editor/skins/xquared/doc/api/src_08.html deleted file mode 100644 index ce19b8514..000000000 --- a/modules/editor/skins/xquared/doc/api/src_08.html +++ /dev/null @@ -1,369 +0,0 @@ -
        1 /**
      -  2  * RichDom for Internet Explorer 6 and 7
      -  3  */
      -  4 xq.RichDomTrident = Class.create(xq.RichDom, {
      -  5 	makePlaceHolder: function() {
      -  6 		return this.createTextNode(" ");
      -  7 	},
      -  8 	
      -  9 	makePlaceHolderString: function() {
      - 10 		return ' ';
      - 11 	},
      - 12 	
      - 13 	makeEmptyParagraph: function() {
      - 14 		return this.createElementFromHtml("<p> </p>");
      - 15 	},
      - 16 
      - 17 	isPlaceHolder: function(node) {
      - 18 		return false;
      - 19 	},
      - 20 
      - 21 	getOuterHTML: function(element) {
      - 22 		return element.outerHTML;
      - 23 	},
      - 24 	
      - 25 	insertNode: function(node) {
      - 26 		if(this.hasSelection()) this.collapseSelection(true);
      - 27 		
      - 28 		this.rng().pasteHTML('<span id="xquared_temp"></span>');
      - 29 		var marker = this.$('xquared_temp');
      - 30 		if(node.id == 'xquared_temp') return marker;
      - 31 		
      - 32 		marker.replaceNode(node);
      - 33 		return node;
      - 34 	},
      - 35 	
      - 36 	removeTrailingWhitespace: function(block) {
      - 37 		if(!block) return;
      - 38 		
      - 39 		// TODO: reimplement to handle atomic tags and so on. (use DomTree)
      - 40 		if(this.tree.isBlockContainer(block)) return;
      - 41 		if(this.isEmptyBlock(block)) return;
      - 42 		
      - 43 		var text = block.innerText;
      - 44 		var lastCharCode = text.charCodeAt(text.length - 1);
      - 45 		if(text.length <= 1 || ![32,160].include(lastCharCode)) return;
      - 46 		
      - 47 		var node = block;
      - 48 		
      - 49 		while(node && node.nodeType != 3) node = node.lastChild;
      - 50 		
      - 51 		if(!node) return;
      - 52 		
      - 53 		// DO NOT REMOVE OR MODIFY FOLLOWING CODE:
      - 54 		//
      - 55 		// Modifying following code crash IE7
      - 56 		var nodeValue = node.nodeValue;
      - 57 		if(nodeValue.length <= 1) {
      - 58 			this.deleteNode(node, true);
      - 59 		} else {
      - 60 			node.nodeValue = nodeValue.substring(0, nodeValue.length - 1);
      - 61 		}
      - 62 	},
      - 63 	
      - 64 	correctEmptyElement: function(element) {
      - 65 		if(!element || element.nodeType != 1 || this.tree.isAtomic(element)) return;
      - 66 		
      - 67 		if(element.firstChild) {
      - 68 			this.correctEmptyElement(element.firstChild);
      - 69 		} else {
      - 70 			element.innerHTML = " ";
      - 71 		}
      - 72 	},
      - 73 
      - 74 	copyAttributes: function(from, to, copyId) {
      - 75 		to.mergeAttributes(from, !copyId);
      - 76 	},
      - 77 
      - 78 	correctParagraph: function() {
      - 79 		if(!this.hasFocus()) return false;
      - 80 		if(this.hasSelection()) return false;
      - 81 		
      - 82 		var block = this.getCurrentElement();
      - 83 		
      - 84 		if(block.nodeName == "BODY") {
      - 85 			// check for atomic block element such as HR
      - 86 			block = this.insertNode(this.makeEmptyParagraph());
      - 87 			var next = block.nextSibling;
      - 88 			if(this.tree.isAtomic(next)) {
      - 89 				block = this.insertNodeAt(block, next, "after");
      - 90 				this.placeCaretAtStartOf(block);
      - 91 				
      - 92 				var nextBlock = this.tree.findForward(
      - 93 					block,
      - 94 					function(node) {return this.tree.isBlock(node) && !this.tree.isBlockOnlyContainer(node)}.bind(this)
      - 95 				);
      - 96 				if(nextBlock) {
      - 97 					this.deleteNode(block);
      - 98 					this.placeCaretAtStartOf(nextBlock);
      - 99 				}
      -100 				return true;
      -101 			} else {
      -102 				var nextBlock = this.tree.findForward(
      -103 					block,
      -104 					function(node) {return this.tree.isBlock(node) && !this.tree.isBlockOnlyContainer(node)}.bind(this)
      -105 				);
      -106 				if(nextBlock) {
      -107 					this.deleteNode(block);
      -108 					this.placeCaretAtStartOf(nextBlock);
      -109 				}
      -110 				return true;
      -111 			}
      -112 		} else {
      -113 			block = this.getCurrentBlockElement();
      -114 			if(block.nodeType == 3) block = block.parentNode;
      -115 			
      -116 			if(this.tree.hasMixedContents(block)) {
      -117 				var marker = this.pushMarker();
      -118 				this.wrapAllInlineOrTextNodesAs("P", block, true);
      -119 				this.popMarker(true);
      -120 				return true;
      -121 			} else if((this.tree.isTextOrInlineNode(block.previousSibling) || this.tree.isTextOrInlineNode(block.nextSibling)) && this.tree.hasMixedContents(block.parentNode)) {
      -122 				// IE?서??Block?Inline/Text??접??경우 getCurrentElement ?이 ?작?한??
      -123 				// ?라???재 Block 주?까? ?번???아주어???다.
      -124 				this.wrapAllInlineOrTextNodesAs("P", block.parentNode, true);
      -125 				return true;
      -126 			} else {
      -127 				return false;
      -128 			}
      -129 		}
      -130 	},
      -131 	
      -132 	
      -133 	
      -134 	//////
      -135 	// Commands
      -136 	execCommand: function(commandId, param) {
      -137 		return this.doc.execCommand(commandId, false, param);
      -138 	},
      -139 	
      -140 	applyBackgroundColor: function(color) {
      -141 		this.execCommand("BackColor", color);
      -142 	},
      -143 	
      -144 	applyEmphasis: function() {
      -145 		// Generate <i> tag. It will be replaced with <emphasis> tag during cleanup phase.
      -146 		this.execCommand("Italic");
      -147 	},
      -148 	applyStrongEmphasis: function() {
      -149 		// Generate <b> tag. It will be replaced with <strong> tag during cleanup phase.
      -150 		this.execCommand("Bold");
      -151 	},
      -152 	applyStrike: function() {
      -153 		// Generate <strike> tag. It will be replaced with <style class="strike"> tag during cleanup phase.
      -154 		this.execCommand("strikethrough");
      -155 	},
      -156 	applyUnderline: function() {
      -157 		// Generate <u> tag. It will be replaced with <em class="underline"> tag during cleanup phase.
      -158 		this.execCommand("underline");
      -159 	},
      -160 	applyRemoveFormat: function() {
      -161 		this.execCommand("RemoveFormat");
      -162 		this.execCommand("Unlink");
      -163 	},
      -164 	execHeading: function(level) {
      -165 		this.execCommand("FormatBlock", "<H" + level + ">");
      -166 	},
      -167 
      -168 
      -169 
      -170 	//////
      -171 	// Focus/Caret/Selection
      -172 	
      -173 	focus: function() {
      -174 		this.win.focus();
      -175 		
      -176 		// ?게 ?으?초기??caret??P 밖에 ?치?면??		// getCurrentElement??면 P?리턴?는 기이???상??발생.
      -177 		if(!this._focusedBefore) {
      -178 			this.correctParagraph();
      -179 			this.placeCaretAtStartOf(this.getCurrentBlockElement());
      -180 			this._focusedBefore = true;
      -181 		}
      -182 	},
      -183 
      -184 	sel: function() {
      -185 		return this.doc.selection;
      -186 	},
      -187 	
      -188 	rng: function() {
      -189 		try {
      -190 			var sel = this.sel();
      -191 			return (sel == null) ? null : sel.createRange();
      -192 		} catch(ignored) {
      -193 			// IE often fails
      -194 			return null;
      -195 		}
      -196 	},
      -197 	
      -198 	hasSelection: function() {
      -199 		var selectionType = this.sel().type.toLowerCase();
      -200 		if("none" == selectionType) return false;
      -201 		if("text" == selectionType && this.getSelectionAsHtml().length == 0) return false;
      -202 		return true;
      -203 	},
      -204 	deleteSelection: function() {
      -205 		if(this.getSelectionAsText() != "") this.sel().clear();
      -206 	},
      -207 	
      -208 	placeCaretAtStartOf: function(element) {
      -209 		// If there's no empty span, caret sometimes moves into a previous node.
      -210 		var ph = this.insertNodeAt(this.createElement("SPAN"), element, "start");
      -211 		this.selectElement(ph);
      -212 		this.collapseSelection(false);
      -213 		this.deleteNode(ph);
      -214 	},
      -215 	
      -216 	selectElement: function(element, entireElement) {
      -217 		if(!element) throw "[element] is null";
      -218 		if(element.nodeType != 1) throw "[element] is not an element";
      -219 		
      -220 		var rng = this.rng();
      -221 		rng.moveToElementText(element);
      -222 		rng.select();
      -223 	},
      -224 
      -225 	selectBlocksBetween: function(start, end) {
      -226 		var rng = this.rng();
      -227 		var rngTemp = this.rng();
      -228 
      -229 		rngTemp.moveToElementText(start);
      -230 		rng.setEndPoint("StartToStart", rngTemp);
      -231 		
      -232 		rngTemp.moveToElementText(end);
      -233 		rng.setEndPoint("EndToEnd", rngTemp);
      -234 		
      -235 		rng.select();
      -236 	},
      -237 	
      -238 	collapseSelection: function(toStart) {
      -239 		var rng = this.rng();
      -240 		rng.collapse(toStart);
      -241 		rng.select();
      -242 	},
      -243 	
      -244 	getSelectionAsHtml: function() {
      -245 		var rng = this.rng()
      -246 		return rng && rng.htmlText ? rng.htmlText : ""
      -247 	},
      -248 	
      -249 	getSelectionAsText: function() {
      -250 		var rng = this.rng();
      -251 		return rng && rng.text ? rng.text : "";
      -252 	},
      -253 	
      -254 	hasImportantAttributes: function(element) {
      -255 		return !!(element.id || element.className || element.style.cssText);
      -256 	},
      -257 
      -258 	isEmptyBlock: function(element) {
      -259 		if(!element.hasChildNodes()) return true;
      -260 		if(element.nodeType == 3 && !element.nodeValue) return true;
      -261 		if([" ", " ", ""].include(element.innerHTML)) return true;
      -262 		
      -263 		return false;
      -264 	},
      -265 	
      -266 	getLastChild: function(element) {
      -267 		if(!element || !element.hasChildNodes()) return null;
      -268 		
      -269 		var nodes = $A(element.childNodes).reverse();
      -270 		
      -271 		for(var i = 0; i < nodes.length; i++) {
      -272 			if(nodes[i].nodeType != 3 || nodes[i].nodeValue.length != 0) return nodes[i];
      -273 		}
      -274 		
      -275 		return null;
      -276 	},
      -277 	
      -278 	getCurrentElement: function() {
      -279 		if(this.sel().type.toLowerCase() == "control") return this.rng().item(0);
      -280 		return this.rng().parentElement();
      -281 	},
      -282 	
      -283 	getBlockElementAtSelectionStart: function() {
      -284 		var rng = this.rng();
      -285 		var dup = rng.duplicate();
      -286 		dup.collapse(true);
      -287 		
      -288 		var result = this.getParentBlockElementOf(dup.parentElement());
      -289 		if(result.nodeName == "BODY") result = result.firstChild;
      -290 		
      -291 		return result;
      -292 	},
      -293 	
      -294 	getBlockElementAtSelectionEnd: function() {
      -295 		var rng = this.rng();
      -296 		var dup = rng.duplicate();
      -297 		dup.collapse(false);
      -298 		
      -299 		var result = this.getParentBlockElementOf(dup.parentElement());
      -300 		if(result.nodeName == "BODY") result = result.lastChild;
      -301 
      -302 		return result;
      -303 	},
      -304 	
      -305 	getBlockElementsAtSelectionEdge: function(naturalOrder, ignoreEmptyEdges) {
      -306 		return [
      -307 			this.getBlockElementAtSelectionStart(),
      -308 			this.getBlockElementAtSelectionEnd()
      -309 		];
      -310 	},
      -311 	
      -312 	isCaretAtBlockStart: function() {
      -313 		if(this.isCaretAtEmptyBlock()) return true;
      -314 		if(this.hasSelection()) return false;
      -315 		var node = this.getCurrentBlockElement();
      -316 		var marker = this.pushMarker();
      -317 		
      -318 		var isTrue = false;
      -319 		while (node = this.getFirstChild(node)) {
      -320 			if (node == marker) {
      -321 				isTrue = true;
      -322 				break;
      -323 			}
      -324 		}
      -325 		
      -326 		this.popMarker();
      -327 		
      -328 		return isTrue;
      -329 	},
      -330 	isCaretAtBlockEnd: function() {
      -331 		if(this.isCaretAtEmptyBlock()) return true;
      -332 		if(this.hasSelection()) return false;
      -333 		var node = this.getCurrentBlockElement();
      -334 		var marker = this.pushMarker();
      -335 		var isTrue = false;
      -336 		while (node = this.getLastChild(node)) {
      -337 			var nodeValue = node.nodeValue;
      -338 			
      -339 			if (node == marker) {
      -340 				isTrue = true;
      -341 				break;
      -342 			} else if(
      -343 				node.nodeType == 3 &&
      -344 				node.previousSibling == marker &&
      -345 				(nodeValue == " " || (nodeValue.length == 1 && nodeValue.charCodeAt(0) == 160))
      -346 			) {
      -347 				isTrue = true;
      -348 				break;
      -349 			}
      -350 		}
      -351 		
      -352 		this.popMarker();
      -353 		return isTrue;
      -354 	},
      -355 	saveSelection: function() {
      -356 		return this.rng();
      -357 	},
      -358 	restoreSelection: function(bookmark) {
      -359 		bookmark.select();
      -360 	}
      -361 });
      -362 
      \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_09.html b/modules/editor/skins/xquared/doc/api/src_09.html deleted file mode 100644 index 030d7b252..000000000 --- a/modules/editor/skins/xquared/doc/api/src_09.html +++ /dev/null @@ -1,382 +0,0 @@ -
        1 /**
      -  2  * RichDom for W3C Standard Engine
      -  3  */
      -  4 xq.RichDomW3 = Class.create(xq.RichDom, {
      -  5 	insertNode: function(node) {
      -  6 		var rng = this.rng();
      -  7 		rng.insertNode(node);
      -  8 		rng.selectNode(node);
      -  9 		rng.collapse(false);
      - 10 		return node;
      - 11 	},
      - 12 
      - 13 	removeTrailingWhitespace: function(block) {
      - 14 		// TODO: do nothing
      - 15 	},
      - 16 
      - 17 	getOuterHTML: function(element) {
      - 18 		var div = element.ownerDocument.createElement("div");
      - 19 		div.appendChild(element.cloneNode(true));
      - 20 		return div.innerHTML;
      - 21 	},
      - 22 	
      - 23 	correctEmptyElement: function(element) {
      - 24 		if(!element || element.nodeType != 1 || this.tree.isAtomic(element)) return;
      - 25 		
      - 26 		if(element.firstChild)
      - 27 			this.correctEmptyElement(element.firstChild);
      - 28 		else
      - 29 			element.appendChild(this.makePlaceHolder());
      - 30 	},
      - 31 	
      - 32 	correctParagraph: function() {
      - 33 		if(this.hasSelection()) return false;
      - 34 		
      - 35 		var block = this.getCurrentElement();
      - 36 		var modified = false;
      - 37 		
      - 38 		if(this.tree.isBlockOnlyContainer(block)) {
      - 39 			this.execCommand("InsertParagraph");
      - 40 			
      - 41 			// check for atomic block element such as HR
      - 42 			var newBlock = this.getCurrentElement();
      - 43 			if(this.tree.isAtomic(newBlock.previousSibling)) {
      - 44 				var nextBlock = this.tree.findForward(
      - 45 					newBlock,
      - 46 					function(node) {return this.tree.isBlock(node) && !this.tree.isBlockOnlyContainer(node)}.bind(this)
      - 47 				);
      - 48 				if(nextBlock) {
      - 49 					this.deleteNode(newBlock);
      - 50 					this.placeCaretAtStartOf(nextBlock);
      - 51 				}
      - 52 			}
      - 53 			modified = true;
      - 54 		} else if(this.tree.hasMixedContents(block)) {
      - 55 			this.wrapAllInlineOrTextNodesAs("P", block, true);
      - 56 			modified = true;
      - 57 		}
      - 58 		
      - 59 		block = this.getCurrentElement();
      - 60 		if(this.tree.isBlock(block) && !this._hasPlaceHolderAtEnd(block)) {
      - 61 			block.appendChild(this.makePlaceHolder());
      - 62 			modified = true;
      - 63 		}
      - 64 		
      - 65 		if(this.tree.isBlock(block)) {
      - 66 			var parentsLastChild = block.parentNode.lastChild;
      - 67 			if(this.isPlaceHolder(parentsLastChild)) {
      - 68 				this.deleteNode(parentsLastChild);
      - 69 				modified = true;
      - 70 			}
      - 71 		}
      - 72 		
      - 73 		return modified;
      - 74 	},
      - 75 	
      - 76 	_hasPlaceHolderAtEnd: function(block) {
      - 77 		if(!block.hasChildNodes()) return false;
      - 78 		return this.isPlaceHolder(block.lastChild) || this._hasPlaceHolderAtEnd(block.lastChild);
      - 79 	},
      - 80 	
      - 81 	applyBackgroundColor: function(color) {
      - 82 		this.execCommand("styleWithCSS", "true");
      - 83 		this.execCommand("hilitecolor", color);
      - 84 		this.execCommand("styleWithCSS", "false");
      - 85 		
      - 86 		// 0. Save current selection
      - 87 		var bookmark = this.saveSelection();
      - 88 		
      - 89 		// 1. Get selected blocks
      - 90 		var blocks = this.getSelectedBlockElements();
      - 91 		if(blocks.length == 0) return;
      - 92 		
      - 93 		// 2. Apply background-color to all adjust inline elements
      - 94 		// 3. Remove background-color from blocks
      - 95 		for(var i = 0; i < blocks.length; i++) {
      - 96 			if((i == 0 || i == blocks.length-1) && !blocks[i].style.backgroundColor) continue;
      - 97 			
      - 98 			var spans = this.wrapAllInlineOrTextNodesAs("SPAN", blocks[i], true);
      - 99 			for(var j = 0; j < spans.length; j++) {
      -100 				spans[j].style.backgroundColor = color;
      -101 			}
      -102 			blocks[i].style.backgroundColor = "";
      -103 		}
      -104 		
      -105 		// 4. Restore selection
      -106 		this.restoreSelection(bookmark);
      -107 	},
      -108 	
      -109 	
      -110 	
      -111 	
      -112 	//////
      -113 	// Commands
      -114 	execCommand: function(commandId, param) {
      -115 		return this.doc.execCommand(commandId, false, param || null);
      -116 	},
      -117 	
      -118 	saveSelection: function() {
      -119 		var rng = this.rng();
      -120 		return [rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset];
      -121 	},
      -122 	
      -123 	restoreSelection: function(bookmark) {
      -124 		var rng = this.rng();
      -125 		rng.setStart(bookmark[0], bookmark[1]);
      -126 		rng.setEnd(bookmark[2], bookmark[3]);
      -127 	},
      -128 	
      -129 	applyRemoveFormat: function() {
      -130 		this.execCommand("RemoveFormat");
      -131 		this.execCommand("Unlink");
      -132 	},
      -133 	applyEmphasis: function() {
      -134 		// Generate <i> tag. It will be replaced with <emphasis> tag during cleanup phase.
      -135 		this.execCommand("styleWithCSS", "false");
      -136 		this.execCommand("italic");
      -137 	},
      -138 	applyStrongEmphasis: function() {
      -139 		// Generate <b> tag. It will be replaced with <strong> tag during cleanup phase.
      -140 		this.execCommand("styleWithCSS", "false");
      -141 		this.execCommand("bold");
      -142 	},
      -143 	applyStrike: function() {
      -144 		// Generate <strike> tag. It will be replaced with <style class="strike"> tag during cleanup phase.
      -145 		this.execCommand("styleWithCSS", "false");
      -146 		this.execCommand("strikethrough");
      -147 	},
      -148 	applyUnderline: function() {
      -149 		// Generate <u> tag. It will be replaced with <em class="underline"> tag during cleanup phase.
      -150 		this.execCommand("styleWithCSS", "false");
      -151 		this.execCommand("underline");
      -152 	},
      -153 	execHeading: function(level) {
      -154 		this.execCommand("Heading", "H" + level);
      -155 	},
      -156 
      -157 
      -158 
      -159 	//////
      -160 	// Focus/Caret/Selection
      -161 	
      -162 	focus: function() {
      -163 		setTimeout(this._focus.bind(this), 0);
      -164 	},
      -165 	
      -166 	/** @private */
      -167 	_focus: function() {
      -168 		this.win.focus();
      -169 		if(!this.hasSelection() && this.getCurrentElement().nodeName == "HTML") {
      -170 			this.selectElement(this.doc.body.firstChild);
      -171 			this.collapseSelection(true);
      -172 		}
      -173 	},
      -174 
      -175 	sel: function() {
      -176 		return this.win.getSelection();
      -177 	},
      -178 	
      -179 	rng: function() {
      -180 		var sel = this.sel();
      -181 		return (sel == null || sel.rangeCount == 0) ? null : sel.getRangeAt(0);
      -182 	},
      -183 
      -184 	hasSelection: function() {
      -185 		var sel = this.sel();
      -186 		return sel && !sel.isCollapsed;
      -187 	},
      -188 	
      -189 	deleteSelection: function() {
      -190 		this.rng().deleteContents();
      -191 		this.sel().collapseToStart();
      -192 	},
      -193 	
      -194 	selectElement: function(element, entireElement) {throw "Not implemented yet"},
      -195 
      -196 	selectBlocksBetween: function(start, end) {
      -197 		// required to avoid FF selection bug.
      -198 		try {
      -199 			if(!xq.Browser.isMac) this.doc.execCommand("SelectAll", false, null);
      -200 		} catch(ignored) {}
      -201 		
      -202 		var rng = this.rng();
      -203 		rng.setStart(start.firstChild, 0);
      -204 		rng.setEnd(end, end.childNodes.length);
      -205 	},
      -206 
      -207 	collapseSelection: function(toStart) {
      -208 		this.rng().collapse(toStart);
      -209 	},
      -210 	
      -211 	placeCaretAtStartOf: function(element) {
      -212 		while(this.tree.isBlock(element.firstChild)) {
      -213 			element = element.firstChild;
      -214 		}
      -215 		this.selectElement(element, false);
      -216 		this.collapseSelection(true);
      -217 	},
      -218 	
      -219 	getSelectionAsHtml: function() {
      -220 		var container = document.createElement("div");
      -221 		container.appendChild(this.rng().cloneContents());
      -222 		return container.innerHTML;
      -223 	},
      -224 	
      -225 	getSelectionAsText: function() {
      -226 		return this.rng().toString()
      -227 	},
      -228 	
      -229 	hasImportantAttributes: function(element) {
      -230 		return !!(element.id || element.className || element.style.cssText);
      -231 	},
      -232 	
      -233 	isEmptyBlock: function(element) {
      -234 		if(!element.hasChildNodes()) return true;
      -235 		var children = element.childNodes;
      -236 		for(var i = 0; i < children.length; i++) {
      -237 			if(!this.isPlaceHolder(children[i]) && !this.isEmptyTextNode(children[i])) return false;
      -238 		}
      -239 		return true;
      -240 	},
      -241 	
      -242 	getLastChild: function(element) {
      -243 		if(!element || !element.hasChildNodes()) return null;
      -244 		
      -245 		var nodes = $A(element.childNodes).reverse();
      -246 		
      -247 		for(var i = 0; i < nodes.length; i++) {
      -248 			if(!this.isPlaceHolder(nodes[i]) && !this.isEmptyTextNode(nodes[i])) return nodes[i];
      -249 		}
      -250 		return null;
      -251 	},
      -252 	
      -253 	getCurrentElement: function() {
      -254 		var rng = this.rng();
      -255 		if(!rng) return null;
      -256 		
      -257 		var container = rng.startContainer;
      -258 		return container.nodeType == 3 ? container.parentNode : container;
      -259 	},
      -260 
      -261 	getBlockElementsAtSelectionEdge: function(naturalOrder, ignoreEmptyEdges) {
      -262 		var start = this.getBlockElementAtSelectionStart();
      -263 		var end = this.getBlockElementAtSelectionEnd();
      -264 		
      -265 		var reversed = false;
      -266 		
      -267 		if(naturalOrder && start != end && this.tree.checkTargetBackward(start, end)) {
      -268 			var temp = start;
      -269 			start = end;
      -270 			end = temp;
      -271 			
      -272 			reversed = true;
      -273 		}
      -274 		
      -275 		if(ignoreEmptyEdges && start != end) {
      -276 			// TODO - Firefox sometimes selects one more block.
      -277 /*
      -278 			
      -279 			var sel = this.sel();
      -280 			if(reversed) {
      -281 				if(sel.focusNode.nodeType == 1) start = start.nextSibling;
      -282 				if(sel.anchorNode.nodeType == 3 && sel.focusOffset == 0) end = end.previousSibling;
      -283 			} else {
      -284 				if(sel.anchorNode.nodeType == 1) start = start.nextSibling;
      -285 				if(sel.focusNode.nodeType == 3 && sel.focusOffset == 0) end = end.previousSibling;
      -286 			}
      -287 */
      -288 		}
      -289 		
      -290 		return [start, end];
      -291 	},
      -292 	
      -293 	getBlockElementAtSelectionStart: function() {
      -294 		var block = this.getParentBlockElementOf(this.sel().anchorNode);
      -295 		
      -296 		// find bottom-most first block child
      -297 		while(this.tree.isBlockContainer(block) && block.firstChild && this.tree.isBlock(block.firstChild)) {
      -298 			block = block.firstChild;
      -299 		}
      -300 		
      -301 		return block;
      -302 	},
      -303 	
      -304 	getBlockElementAtSelectionEnd: function() {
      -305 		var block = this.getParentBlockElementOf(this.sel().focusNode);
      -306 		
      -307 		// find bottom-most last block child
      -308 		while(this.tree.isBlockContainer(block) && block.lastChild && this.tree.isBlock(block.lastChild)) {
      -309 			block = block.lastChild;
      -310 		}
      -311 		
      -312 		return block;
      -313 	},
      -314 
      -315 	isCaretAtBlockStart: function() {
      -316 		if(this.isCaretAtEmptyBlock()) return true;
      -317 		if(this.hasSelection()) return false;
      -318 		var rng = this.rng();
      -319 		var node = this.getCurrentBlockElement();
      -320 		var isTrue = false;
      -321 		
      -322 		if(node == rng.startContainer) {
      -323 			var marker = this.pushMarker();
      -324 			while (node = this.getFirstChild(node)) {
      -325 				if (node == marker) {
      -326 					isTrue = true;
      -327 					break;
      -328 				}
      -329 			}
      -330 			this.popMarker();
      -331 		} else {
      -332 			while (node = node.firstChild) {
      -333 				if (node == rng.startContainer && rng.startOffset == 0) {
      -334 					isTrue = true;
      -335 					break;
      -336 				}
      -337 			}
      -338 		}
      -339 		
      -340 		return isTrue;
      -341 	},
      -342 	
      -343 	isCaretAtBlockEnd: function() {
      -344 		if(this.isCaretAtEmptyBlock()) return true;
      -345 		if(this.hasSelection()) return false;
      -346 		
      -347 		var rng = this.rng();
      -348 		var node = this.getCurrentBlockElement();
      -349 		var isTrue = false;
      -350 		
      -351 		if(node == rng.startContainer) {
      -352 			var marker = this.pushMarker();
      -353 			while (node = this.getLastChild(node)) {
      -354 				if ((node == marker) || (this.isPlaceHolder(node) && node.previousSibling == marker)) {
      -355 					isTrue = true;
      -356 					break;
      -357 				}
      -358 			}
      -359 			this.popMarker();
      -360 		} else {
      -361 			while (node = this.getLastChild(node)) {
      -362 				if (node == rng.endContainer && rng.endContainer.nodeType == 1) {
      -363 					isTrue = true;
      -364 					break;
      -365 				} else if (node == rng.endContainer && rng.endOffset == node.nodeValue.length) {
      -366 					isTrue = true;
      -367 					break;
      -368 				}
      -369 			}
      -370 		}
      -371 		
      -372 		return isTrue;
      -373 	}
      -374 });
      -375 
      \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_10.html b/modules/editor/skins/xquared/doc/api/src_10.html deleted file mode 100644 index 9eb4955a5..000000000 --- a/modules/editor/skins/xquared/doc/api/src_10.html +++ /dev/null @@ -1,91 +0,0 @@ -
        1 /**
      -  2  * RichDom for Webkit
      -  3  */
      -  4 xq.RichDomWebkit = Class.create(xq.RichDomW3, {
      -  5 	makePlaceHolder: function() {
      -  6 		var holder = this.createElement("BR");
      -  7 		holder.className = "webkit-block-placeholder";
      -  8 		return holder;
      -  9 	},
      - 10 	
      - 11 	makePlaceHolderString: function() {
      - 12 		return '<br class="webkit-block-placeholder" />';
      - 13 	},
      - 14 	
      - 15 	makeEmptyParagraph: function() {
      - 16 		return this.createElementFromHtml('<p><br class="webkit-block-placeholder" /></p>');
      - 17 	},
      - 18 	
      - 19 	isPlaceHolder: function(node) {
      - 20 		return node.nodeName == "BR" && node.className == "webkit-block-placeholder";
      - 21 	},
      - 22 
      - 23 	rng: function() {
      - 24 		var sel = this.sel();
      - 25 		var rng = this.doc.createRange();
      - 26 		if (!this._rng ||
      - 27 			this._anchorNode != sel.anchorNode ||
      - 28 			this._anchorOffset != sel.anchorOffset ||
      - 29 			this._focusNode != sel.focusNode ||
      - 30 			this._focusOffset != sel.focusOffset ) {
      - 31 
      - 32 			if (sel.type != 'None') {
      - 33 				rng.setStart(sel.anchorNode, sel.anchorOffset);
      - 34 				rng.setEnd(sel.focusNode, sel.focusOffset);
      - 35 			}
      - 36 			this._anchorNode = sel.anchorNode;
      - 37 			this._anchorOffset = sel.anchorOffset;
      - 38 			this._focusNode = sel.focusNode;
      - 39 			this._focusOffset = sel.focusOffset;
      - 40 			this._rng = rng;
      - 41 		}
      - 42 		return this._rng;
      - 43 	},
      - 44 
      - 45 	selectElement: function(element, entireElement) {
      - 46 		if(!element) throw "[element] is null";
      - 47 		if(element.nodeType != 1) throw "[element] is not an element";
      - 48 		
      - 49 		var rng = this.rng();
      - 50 		if(entireElement) {
      - 51 			rng.selectNode(element);
      - 52 		} else {
      - 53 			rng.selectNodeContents(element);
      - 54 		}
      - 55 		this._setSelectionByRange(rng);
      - 56 	},
      - 57 
      - 58 	deleteSelection: function() {
      - 59 		this.rng().deleteContents();
      - 60 	},
      - 61 
      - 62 	collapseSelection: function(toStart) {
      - 63 		var rng = this.rng();
      - 64 		rng.collapse(toStart);
      - 65 		this._setSelectionByRange(rng);
      - 66 	},
      - 67 
      - 68 	getSelectionAsHtml: function() {
      - 69 		var container = this.createElement("div");
      - 70 		var rng = this.rng();
      - 71 		var contents = this.rng().cloneContents();
      - 72 		if(contents) container.appendChild(contents);
      - 73 		return container.innerHTML;
      - 74 	},
      - 75 	
      - 76 	_setSelectionByRange: function(rng) {
      - 77 		var sel = this.sel();
      - 78 		sel.setBaseAndExtent(rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset);
      - 79 		this._anchorNode = sel.anchorNode;
      - 80 		this._anchorOffset = sel.anchorOffset;
      - 81 		this._focusNode = sel.focusNode;
      - 82 		this._focusOffset = sel.focusOffset;
      - 83 	}
      - 84 });
      \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_11.html b/modules/editor/skins/xquared/doc/api/src_11.html deleted file mode 100644 index 58f5fb053..000000000 --- a/modules/editor/skins/xquared/doc/api/src_11.html +++ /dev/null @@ -1,209 +0,0 @@ -
        1 xq.RichTable = Class.create({
      -  2 	initialize: function(rdom, table) {
      -  3 		this.rdom = rdom;
      -  4 		this.table = table;
      -  5 	},
      -  6 	insertNewRowAt: function(tr, where) {
      -  7 		var row = this.rdom.createElement("TR");
      -  8 		var cells = tr.cells;
      -  9 		for(var i = 0; i < cells.length; i++) {
      - 10 			var cell = this.rdom.createElement(cells[i].nodeName);
      - 11 			this.rdom.correctEmptyElement(cell);
      - 12 			row.appendChild(cell);
      - 13 		}
      - 14 		return this.rdom.insertNodeAt(row, tr, where);
      - 15 	},
      - 16 	insertNewCellAt: function(cell, where) {
      - 17 		// collect cells;
      - 18 		var cells = [];
      - 19 		var x = this.getXIndexOf(cell);
      - 20 		var y = 0;
      - 21 		while(true) {
      - 22 			var cur = this.getCellAt(x, y);
      - 23 			if(!cur) break;
      - 24 			cells.push(cur);
      - 25 			y++;
      - 26 		}
      - 27 		
      - 28 		// insert new cells
      - 29 		for(var i = 0; i < cells.length; i++) {
      - 30 			var cell = this.rdom.createElement(cells[i].nodeName);
      - 31 			this.rdom.correctEmptyElement(cell);
      - 32 			this.rdom.insertNodeAt(cell, cells[i], where);
      - 33 		}
      - 34 	},
      - 35 	deleteRow: function(tr) {
      - 36 		return this.rdom.removeBlock(tr);
      - 37 	},
      - 38 	deleteCell: function(cell) {
      - 39 		if(!cell.previousSibling && !cell.nextSibling) {
      - 40 			this.rdom.deleteNode(this.table);
      - 41 			return;
      - 42 		}
      - 43 		
      - 44 		// collect cells;
      - 45 		var cells = [];
      - 46 		var x = this.getXIndexOf(cell);
      - 47 		var y = 0;
      - 48 		while(true) {
      - 49 			var cur = this.getCellAt(x, y);
      - 50 			if(!cur) break;
      - 51 			cells.push(cur);
      - 52 			y++;
      - 53 		}
      - 54 		
      - 55 		for(var i = 0; i < cells.length; i++) {
      - 56 			this.rdom.deleteNode(cells[i]);
      - 57 		}
      - 58 	},
      - 59 	getPreviousCellOf: function(cell) {
      - 60 		if(cell.previousSibling) return cell.previousSibling;
      - 61 		var adjRow = this.getPreviousRowOf(cell.parentNode);
      - 62 		if(adjRow) return adjRow.lastChild;
      - 63 		return null;
      - 64 	},
      - 65 	getNextCellOf: function(cell) {
      - 66 		if(cell.nextSibling) return cell.nextSibling;
      - 67 		var adjRow = this.getNextRowOf(cell.parentNode);
      - 68 		if(adjRow) return adjRow.firstChild;
      - 69 		return null;
      - 70 	},
      - 71 	getPreviousRowOf: function(row) {
      - 72 		if(row.previousSibling) return row.previousSibling;
      - 73 		var rowContainer = row.parentNode;
      - 74 		if(rowContainer.previousSibling && rowContainer.previousSibling.lastChild) return rowContainer.previousSibling.lastChild;
      - 75 		return null;
      - 76 	},
      - 77 	getNextRowOf: function(row) {
      - 78 		if(row.nextSibling) return row.nextSibling;
      - 79 		var rowContainer = row.parentNode;
      - 80 		if(rowContainer.nextSibling && rowContainer.nextSibling.firstChild) return rowContainer.nextSibling.firstChild;
      - 81 		return null;
      - 82 	},
      - 83 	getAboveCellOf: function(cell) {
      - 84 		var row = this.getPreviousRowOf(cell.parentNode);
      - 85 		if(!row) return null;
      - 86 		
      - 87 		var x = this.getXIndexOf(cell);
      - 88 		return row.cells[x];
      - 89 	},
      - 90 	getBelowCellOf: function(cell) {
      - 91 		var row = this.getNextRowOf(cell.parentNode);
      - 92 		if(!row) return null;
      - 93 		
      - 94 		var x = this.getXIndexOf(cell);
      - 95 		return row.cells[x];
      - 96 	},
      - 97 	getXIndexOf: function(cell) {
      - 98 		var row = cell.parentNode;
      - 99 		for(var i = 0; i < row.cells.length; i++) {
      -100 			if(row.cells[i] == cell) return i;
      -101 		}
      -102 		
      -103 		return -1;
      -104 	},
      -105 	getYIndexOf: function(cell) {
      -106 		var y = -1;
      -107 		
      -108 		// find y
      -109 		var group = row.parentNode;
      -110 		for(var i = 0; i <group.rows.length; i++) {
      -111 			if(group.rows[i] == row) {
      -112 				y = i;
      -113 				break;
      -114 			}
      -115 		}
      -116 		if(this.hasHeadingAtTop() && group.nodeName == "TBODY") y = y + 1;
      -117 		
      -118 		return y;
      -119 	},
      -120 	/**
      -121 	 * TODO: Not used. Delete or not?
      -122 	 */
      -123 	getLocationOf: function(cell) {
      -124 		var x = this.getXIndexOf(cell);
      -125 		var y = this.getYIndexOf(cell);
      -126 		return {x:x, y:y};
      -127 	},
      -128 	getCellAt: function(col, row) {
      -129 		var row = this.getRowAt(row);
      -130 		return (row && row.cells.length > col) ? row.cells[col] : null;
      -131 	},
      -132 	getRowAt: function(index) {
      -133 		if(this.hasHeadingAtTop()) {
      -134 			return index == 0 ? this.table.tHead.rows[0] : this.table.tBodies[0].rows[index - 1];
      -135 		} else {
      -136 			var rows = this.table.tBodies[0].rows;
      -137 			return (rows.length > index) ? rows[index] : null;
      -138 		}
      -139 	},
      -140 	getDom: function() {
      -141 		return this.table;
      -142 	},
      -143 	hasHeadingAtTop: function() {
      -144 		return !!(this.table.tHead && this.table.tHead.rows[0]);
      -145 	},
      -146 	hasHeadingAtLeft: function() {
      -147 		return this.table.tBodies[0].rows[0].cells[0].nodeName == "TH";
      -148 	},
      -149 	correctEmptyCells: function() {
      -150 		var cells = $A(this.table.getElementsByTagName("TH"));
      -151 		cells.push($A(this.table.getElementsByTagName("TD")));
      -152 		cells = cells.flatten();
      -153 		
      -154 		for(var i = 0; i < cells.length; i++) {
      -155 			if(this.rdom.isEmptyBlock(cells[i])) this.rdom.correctEmptyElement(cells[i])
      -156 		}
      -157 	}
      -158 });
      -159 
      -160 xq.RichTable.create = function(rdom, cols, rows, headerPositions) {
      -161 	if(["t", "tl", "lt"].include(headerPositions)) var headingAtTop = true
      -162 	if(["l", "tl", "lt"].include(headerPositions)) var headingAtLeft = true
      -163 
      -164 	var sb = []
      -165 	sb.push('<table class="datatable">')
      -166 	
      -167 	// thead
      -168 	if(headingAtTop) {
      -169 		sb.push('<thead><tr>')
      -170 		for(var i = 0; i < cols; i++) sb.push('<th></th>')
      -171 		sb.push('</tr></thead>')
      -172 		rows -= 1
      -173 	}
      -174 		
      -175 	// tbody
      -176 	sb.push('<tbody>')
      -177 	for(var i = 0; i < rows; i++) {
      -178 		sb.push('<tr>')
      -179 		
      -180 		for(var j = 0; j < cols; j++) {
      -181 			if(headingAtLeft && j == 0) {
      -182 				sb.push('<th></th>')
      -183 			} else {
      -184 				sb.push('<td></td>')
      -185 			}
      -186 		}
      -187 		
      -188 		sb.push('</tr>')
      -189 	}
      -190 	sb.push('</tbody>')
      -191 	
      -192 	sb.push('</table>')
      -193 	
      -194 	// create DOM element
      -195 	var container = rdom.createElement("div");
      -196 	container.innerHTML = sb.join("");
      -197 	
      -198 	// correct empty cells and return
      -199 	var rtable = new xq.RichTable(rdom, container.firstChild);
      -200 	rtable.correctEmptyCells();
      -201 	return rtable;
      -202 }
      \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_12.html b/modules/editor/skins/xquared/doc/api/src_12.html deleted file mode 100644 index 72b700cd4..000000000 --- a/modules/editor/skins/xquared/doc/api/src_12.html +++ /dev/null @@ -1,135 +0,0 @@ -
        1 xq.Shortcut = Class.create({
      -  2 	initialize: function(keymapOrExpression) {
      -  3 		this.keymap = (typeof keymapOrExpression == "string") ?
      -  4 			xq.Shortcut.interprete(keymapOrExpression).keymap :
      -  5 			keymapOrExpression;
      -  6 	},
      -  7 	matches: function(e) {
      -  8 		var which = xq.Browser.isGecko && xq.Browser.isMac ? (e.keyCode + "_" + e.charCode) : e.keyCode;
      -  9 		
      - 10 		var keyMatches =
      - 11 			(this.keymap.which == which) ||
      - 12 			(this.keymap.which == 32 && which == 25); // 25 is SPACE in Type-3 keyboard.
      - 13 		
      - 14 		if(typeof e.metaKey == "undefined") e.metaKey = false;
      - 15 		
      - 16 		var modifierMatches = 
      - 17 			(typeof this.keymap.shiftKey == "undefined" || this.keymap.shiftKey == e.shiftKey) &&
      - 18 			(typeof this.keymap.altKey == "undefined" || this.keymap.altKey == e.altKey) &&
      - 19 			(typeof this.keymap.ctrlKey == "undefined" || this.keymap.ctrlKey == e.ctrlKey) &&
      - 20 			(typeof this.keymap.metaKey == "undefined" || this.keymap.metaKey == e.metaKey)
      - 21 		
      - 22 		return modifierMatches && keyMatches;
      - 23 	}
      - 24 });
      - 25 
      - 26 xq.Shortcut.interprete = function(expression) {
      - 27 	expression = expression.toUpperCase();
      - 28 	
      - 29 	var which = xq.Shortcut._interpreteWhich(expression.split("+").pop());
      - 30 	var ctrlKey = xq.Shortcut._interpreteModifier(expression, "CTRL");
      - 31 	var altKey = xq.Shortcut._interpreteModifier(expression, "ALT");
      - 32 	var shiftKey = xq.Shortcut._interpreteModifier(expression, "SHIFT");
      - 33 	var metaKey = xq.Shortcut._interpreteModifier(expression, "META");
      - 34 	
      - 35 	var keymap = {};
      - 36 	
      - 37 	keymap.which = which;
      - 38 	if(typeof ctrlKey != "undefined") keymap.ctrlKey = ctrlKey;
      - 39 	if(typeof altKey != "undefined") keymap.altKey = altKey;
      - 40 	if(typeof shiftKey != "undefined") keymap.shiftKey = shiftKey;
      - 41 	if(typeof metaKey != "undefined") keymap.metaKey = metaKey;
      - 42 	
      - 43 	return new xq.Shortcut(keymap);
      - 44 }
      - 45 
      - 46 xq.Shortcut._interpreteModifier = function(expression, modifierName) {
      - 47 	return expression.match("\\(" + modifierName + "\\)") ?
      - 48 		undefined :
      - 49 			expression.match(modifierName) ?
      - 50 			true : false;
      - 51 }
      - 52 xq.Shortcut._interpreteWhich = function(keyName) {
      - 53 	var which = keyName.length == 1 ?
      - 54 		((xq.Browser.isMac && xq.Browser.isGecko) ? "0_" + keyName.toLowerCase().charCodeAt(0) : keyName.charCodeAt(0)) :
      - 55 		xq.Shortcut._keyNames[keyName];
      - 56 	
      - 57 	if(typeof which == "undefined") throw "Unknown special key name: [" + keyName + "]"
      - 58 	
      - 59 	return which;
      - 60 }
      - 61 xq.Shortcut._keyNames =
      - 62 	xq.Browser.isMac && xq.Browser.isGecko ?
      - 63 	{
      - 64 		BACKSPACE: "8_0",
      - 65 		TAB: "9_0",
      - 66 		RETURN: "13_0",
      - 67 		ENTER: "13_0",
      - 68 		ESC: "27_0",
      - 69 		SPACE: "0_32",
      - 70 		LEFT: "37_0",
      - 71 		UP: "38_0",
      - 72 		RIGHT: "39_0",
      - 73 		DOWN: "40_0",
      - 74 		DELETE: "46_0",
      - 75 		HOME: "36_0",
      - 76 		END: "35_0",
      - 77 		PAGEUP: "33_0",
      - 78 		PAGEDOWN: "34_0",
      - 79 		COMMA: "0_44",
      - 80 		HYPHEN: "0_45",
      - 81 		EQUAL: "0_61",
      - 82 		PERIOD: "0_46",
      - 83 		SLASH: "0_47",
      - 84 		F1: "112_0",
      - 85 		F2: "113_0",
      - 86 		F3: "114_0",
      - 87 		F4: "115_0",
      - 88 		F5: "116_0",
      - 89 		F6: "117_0",
      - 90 		F7: "118_0",
      - 91 		F8: "119_0"
      - 92 	}
      - 93 	:
      - 94 	{
      - 95 		BACKSPACE: 8,
      - 96 		TAB: 9,
      - 97 		RETURN: 13,
      - 98 		ENTER: 13,
      - 99 		ESC: 27,
      -100 		SPACE: 32,
      -101 		LEFT: 37,
      -102 		UP: 38,
      -103 		RIGHT: 39,
      -104 		DOWN: 40,
      -105 		DELETE: 46,
      -106 		HOME: 36,
      -107 		END: 35,
      -108 		PAGEUP: 33,
      -109 		PAGEDOWN: 34,
      -110 		COMMA: 188,
      -111 		HYPHEN: xq.Browser.isTrident ? 189 : 109,
      -112 		EQUAL: xq.Browser.isTrident ? 187 : 61,
      -113 		PERIOD: 190,
      -114 		SLASH: 191,
      -115 		F1:112,
      -116 		F2:113,
      -117 		F3:114,
      -118 		F4:115,
      -119 		F5:116,
      -120 		F6:117,
      -121 		F7:118,
      -122 		F8:119,
      -123 		F9:120,
      -124 		F10:121,
      -125 		F11:122,
      -126 		F12:123
      -127 	}
      -128 
      \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_13.html b/modules/editor/skins/xquared/doc/api/src_13.html deleted file mode 100644 index e2311e8a9..000000000 --- a/modules/editor/skins/xquared/doc/api/src_13.html +++ /dev/null @@ -1,235 +0,0 @@ -
        1 /**
      -  2  * Validates and invalidates designmode contents
      -  3  */
      -  4 xq.Validator = Class.create({
      -  5 	initialize: function(curUrl, urlValidationMode, allowedTags, allowedAttrs) {
      -  6 		this.allowedTags = (allowedTags || ['a', 'abbr', 'acronym', 'address', 'blockquote', 'br', 'caption', 'cite', 'code', 'dd', 'dfn', 'div', 'dl', 'dt', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'img', 'kbd', 'li', 'ol', 'p', 'pre', 'q', 'samp', 'span', 'sup', 'sub', 'strong', 'table', 'thead', 'tbody', 'td', 'th', 'tr', 'ul', 'var']).join(' ') + ' ';
      -  7 		this.allowedAttrs = (allowedAttrs || ['alt', 'cite', 'class', 'datetime', 'height', 'href', 'id', 'rel', 'rev', 'src', 'style', 'title', 'width']).join(' ') + ' ';
      -  8 		
      -  9 		this.curUrl = curUrl;
      - 10 		this.curUrlParts = curUrl ? curUrl.parseURL() : null;
      - 11 		this.urlValidationMode = urlValidationMode;
      - 12 	},
      - 13 	
      - 14 	/**
      - 15 	 * Perform validation on given element
      - 16 	 *
      - 17 	 * @param {Element} element Target element. It is not affected by validation.
      - 18 	 * @param {boolean} fullValidation Perform full validation. If you just want to use the result to assign innerHTML, set it false
      - 19 	 *
      - 20 	 * @returns {String} Validated HTML string
      - 21 	 */
      - 22 	validate: function(element, fullValidation) {throw "Not implemented"},
      - 23 	
      - 24 	/**
      - 25 	 * Perform invalidation on given element to make the designmode works well.
      - 26 	 *
      - 27 	 * @param {Element} element Target element.
      - 28 	 * @returns {String} Invalidated HTML string
      - 29 	 */
      - 30 	invalidate: function(element) {throw "Not implemented"},
      - 31 	
      - 32 	validateStrike: function(content) {
      - 33 		content = content.replace(/<strike(>|\s+[^>]*>)/ig, "<span class=\"strike\"$1");
      - 34 		content = content.replace(/<\/strike>/ig, "</span>");
      - 35 		return content;
      - 36 	},
      - 37 	
      - 38 	validateUnderline: function(content) {
      - 39 		content = content.replace(/<u(>|\s+[^>]*>)/ig, "<em class=\"underline\"$1");
      - 40 		content = content.replace(/<\/u>/ig, "</em>");
      - 41 		return content;
      - 42 	},
      - 43 	
      - 44 	replaceTag: function(content, from, to) {
      - 45 		return content.replace(new RegExp("(</?)" + from + "(>|\\s+[^>]*>)", "ig"), "$1" + to + "$2");
      - 46 	},
      - 47 	
      - 48 	validateSelfClosingTags: function(content) {
      - 49 		return content.replace(/<(br|hr|img)([^>]*?)>/img, function(str, tag, attrs) {
      - 50 			return "<" + tag + attrs + " />"
      - 51 		});
      - 52 	},
      - 53 	
      - 54 	removeComments: function(content) {
      - 55 		return content.replace(/<!--.*?-->/img, '');
      - 56 	},
      - 57 	
      - 58 	removeDangerousElements: function(element) {
      - 59 		var scripts = $A(element.getElementsByTagName('SCRIPT')).reverse();
      - 60 		for(var i = 0; i < scripts.length; i++) {
      - 61 			scripts[i].parentNode.removeChild(scripts[i]);
      - 62 		}
      - 63 	},
      - 64 
      - 65 	// TODO: very slow
      - 66 	applyWhitelist: function(content) {
      - 67 		var allowedTags = this.allowedTags;
      - 68 		var allowedAttrs = this.allowedAttrs;
      - 69 		
      - 70 		return content.replace(new RegExp("(</?)([^>]+?)(>|\\s+([^>]*?)(\\s?/?)>)", "g"), function(str, head, tag, tail, attrs, selfClosing) {
      - 71 			if(allowedTags.indexOf(tag) == -1) return '';
      - 72 			
      - 73 			if(attrs) {
      - 74 				attrs = attrs.replace(/(^|\s")([^"=]+)(\s|$)/g, '$1$2="$2"$3'); // for IE
      - 75 				
      - 76 				var sb = [];
      - 77 				var m = attrs.match(/([^=]+)="[^"]*?"/g);
      - 78 				for(var i = 0; i < m.length; i++) {
      - 79 					m[i] = m[i].strip();
      - 80 					var name = m[i].split('=')[0];
      - 81 					if(allowedAttrs.indexOf(name) != -1) sb.push(m[i]);
      - 82 				}
      - 83 				attrs = sb.join(' ');
      - 84 				if(attrs != '') attrs = ' ' + attrs;
      - 85 				return head + tag + attrs + selfClosing + '>';
      - 86 			} else {
      - 87 				return str;
      - 88 			}
      - 89 		});
      - 90 	},
      - 91 	
      - 92 	makeUrlsRelative: function(content) {
      - 93 		var curUrl = this.curUrl;
      - 94 		var urlParts = this.curUrlParts;
      - 95 		
      - 96 		// 1. find attributes and...
      - 97 		return content.replace(/(<\w+\s+)(\/|([^>]+?)(\/?))>/g, function(str, head, ignored, attrs, tail) {
      - 98 			if(attrs) {
      - 99 				// 2. validate URL part
      -100 				attrs = attrs.replace(/(href|src)="([^"]+)"/g, function(str, name, url) {
      -101 					// 3. first, make it absolute
      -102 					var abs = null;
      -103 					if(url.charAt(0) == '#') {
      -104 						abs = urlParts.includeQuery + url;
      -105 					} else if(url.charAt(0) == '?') {
      -106 						abs = urlParts.includePath + url;
      -107 					} else if(url.charAt(0) == '/') {
      -108 						abs = urlParts.includeHost + url;
      -109 					} else if(url.match(/^\w+:\/\//)) {
      -110 						abs = url;
      -111 					} else {
      -112 						abs = urlParts.includeBase + url;
      -113 					}
      -114 					
      -115 					// 4. make it relative by removing same part
      -116 					var rel = abs;
      -117 					
      -118 					if(abs.indexOf(urlParts.includeQuery) == 0) {
      -119 						rel = abs.substring(urlParts.includeQuery.length);
      -120 					} else if(abs.indexOf(urlParts.includePath) == 0) {
      -121 						rel = abs.substring(urlParts.includePath.length);
      -122 					} else if(abs.indexOf(urlParts.includeBase) == 0) {
      -123 						rel = abs.substring(urlParts.includeBase.length);
      -124 					} else if(abs.indexOf(urlParts.includeHost) == 0) {
      -125 						rel = abs.substring(urlParts.includeHost.length);
      -126 					}
      -127 					if(rel == '') rel = '#';
      -128 					
      -129 					return name + '="' + rel + '"';
      -130 				});
      -131 				
      -132 				return head + attrs + tail + '>';
      -133 			} else {
      -134 				return str;
      -135 			}
      -136 		});
      -137 		
      -138 		return content;
      -139 	},
      -140 	
      -141 	makeUrlsHostRelative: function(content) {
      -142 		var curUrl = this.curUrl;
      -143 		var urlParts = this.curUrlParts;
      -144 		
      -145 		// 1. find attributes and...
      -146 		return content.replace(/(<\w+\s+)(\/|([^>]+?)(\/?))>/g, function(str, head, ignored, attrs, tail) {
      -147 			if(attrs) {
      -148 				// 2. validate URL part
      -149 				attrs = attrs.replace(/(href|src)="([^"]+)"/g, function(str, name, url) {
      -150 					// 3. first, make it absolute
      -151 					var abs = null;
      -152 					if(url.charAt(0) == '#') {
      -153 						abs = urlParts.includeQuery + url;
      -154 					} else if(url.charAt(0) == '?') {
      -155 						abs = urlParts.includePath + url;
      -156 					} else if(url.charAt(0) == '/') {
      -157 						abs = urlParts.includeHost + url;
      -158 					} else if(url.match(/^\w+:\/\//)) {
      -159 						abs = url;
      -160 					} else {
      -161 						abs = urlParts.includeBase + url;
      -162 					}
      -163 					
      -164 					// 4. make it relative by removing same part
      -165 					var rel = abs;
      -166 					if(abs.indexOf(urlParts.includeHost) == 0) {
      -167 						rel = abs.substring(urlParts.includeHost.length);
      -168 					}
      -169 					if(rel == '') rel = '#';
      -170 					
      -171 					return name + '="' + rel + '"';
      -172 				});
      -173 				
      -174 				return head + attrs + tail + '>';
      -175 			} else {
      -176 				return str;
      -177 			}
      -178 		});
      -179 		
      -180 		return content;
      -181 	},
      -182 	
      -183 	makeUrlsAbsolute: function(content) {
      -184 		var curUrl = this.curUrl;
      -185 		var urlParts = this.curUrlParts;
      -186 		
      -187 		// 1. find attributes and...
      -188 		return content.replace(/(<\w+\s+)(\/|([^>]+?)(\/?))>/g, function(str, head, ignored, attrs, tail) {
      -189 			if(attrs) {
      -190 				// 2. validate URL part
      -191 				attrs = attrs.replace(/(href|src)="([^"]+)"/g, function(str, name, url) {
      -192 					var abs = null;
      -193 					if(url.charAt(0) == '#') {
      -194 						abs = urlParts.includeQuery + url;
      -195 					} else if(url.charAt(0) == '?') {
      -196 						abs = urlParts.includePath + url;
      -197 					} else if(url.charAt(0) == '/') {
      -198 						abs = urlParts.includeHost + url;
      -199 					} else if(url.match(/^\w+:\/\//)) {
      -200 						abs = url;
      -201 					} else {
      -202 						abs = urlParts.includeBase + url;
      -203 					}
      -204 
      -205 					return name + '="' + abs + '"';
      -206 				});
      -207 				
      -208 				return head + attrs + tail + '>';
      -209 			} else {
      -210 				return str;
      -211 			}
      -212 		});
      -213 	}
      -214 });
      -215 
      -216 /**
      -217  * Creates and returns instance of browser specific implementation.
      -218  */
      -219 xq.Validator.createInstance = function(curUrl, urlValidationMode, allowedTags, allowedAttrs) {
      -220 	if(xq.Browser.isTrident) {
      -221 		return new xq.ValidatorTrident(curUrl, urlValidationMode, allowedTags, allowedAttrs);
      -222 	} else if(xq.Browser.isWebkit) {
      -223 		return new xq.ValidatorWebkit(curUrl, urlValidationMode, allowedTags, allowedAttrs);
      -224 	} else {
      -225 		return new xq.ValidatorGecko(curUrl, urlValidationMode, allowedTags, allowedAttrs);
      -226 	}
      -227 }
      -228 
      \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_14.html b/modules/editor/skins/xquared/doc/api/src_14.html deleted file mode 100644 index 9de6a044d..000000000 --- a/modules/editor/skins/xquared/doc/api/src_14.html +++ /dev/null @@ -1,12 +0,0 @@ -
        1 /**
      -  2  * Validator for Gecko Engine
      -  3  */
      -  4 xq.ValidatorGecko = Class.create(xq.ValidatorW3, {
      -  5 });
      \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_15.html b/modules/editor/skins/xquared/doc/api/src_15.html deleted file mode 100644 index a67012aa6..000000000 --- a/modules/editor/skins/xquared/doc/api/src_15.html +++ /dev/null @@ -1,147 +0,0 @@ -
        1 /**
      -  2  * Validator for Internet Explorer 6 and 7
      -  3  */
      -  4 xq.ValidatorTrident = Class.create(xq.Validator, {
      -  5 	validate: function(element, fullValidation) {
      -  6 		element = element.cloneNode(true);
      -  7 		
      -  8 		this.removeDangerousElements(element);
      -  9 		this.validateFontColor(element);
      - 10 		this.validateBackgroundColor(element);
      - 11 		
      - 12 		var content = element.innerHTML;
      - 13 		
      - 14 		try {
      - 15 			content = this.validateStrike(content);
      - 16 			content = this.validateUnderline(content);
      - 17 			
      - 18 			if(fullValidation) content = this.performFullValidation(content);
      - 19 		} catch(ignored) {}
      - 20 		
      - 21 		return content;
      - 22 	},
      - 23 	
      - 24 	invalidate: function(element) {
      - 25 		var rdom = xq.RichDom.createInstance();
      - 26 		rdom.setRoot(element);
      - 27 		
      - 28 		this.invalidateFontColor(element);
      - 29 		this.invalidateBackgroundColor(element);
      - 30 		
      - 31 		// <span class="strike"> -> <strike>
      - 32 		var strikes = rdom.findByAttribute("className", "strike");
      - 33 		for(var i = 0; i < strikes.length; i++) {
      - 34 			if("SPAN" == strikes[i].nodeName) rdom.replaceTag("strike", strikes[i]).removeAttribute("className");
      - 35 		}
      - 36 		
      - 37 		// <em|i class="underline"> -> <u>
      - 38 		var underlines = rdom.findByAttribute("className", "underline");
      - 39 		for(var i = 0; i < underlines.length; i++) {
      - 40 			if(["EM", "I"].include(underlines[i].nodeName)) rdom.replaceTag("u", underlines[i]).removeAttribute("className");
      - 41 		}
      - 42 
      - 43 		var content = rdom.getRoot().innerHTML;
      - 44 
      - 45 		content = this.removeComments(content);
      - 46 		
      - 47 		return content;
      - 48 	},
      - 49 	
      - 50 	performFullValidation: function(content) {
      - 51 		content = this.lowerTagNamesAndUniformizeQuotation(content);
      - 52 		content = this.validateSelfClosingTags(content);
      - 53 		content = this.applyWhitelist(content);
      - 54 		
      - 55 		if(this.urlValidationMode == 'relative') {
      - 56 			content = this.makeUrlsRelative(content);
      - 57 		} else if(this.urlValidationMode == 'host_relative') {
      - 58 			content = this.makeUrlsHostRelative(content);
      - 59 		} else if(this.urlValidationMode == 'absolute') {
      - 60 			// Trident always use absolute URL so we don't need to do anything.
      - 61 			//
      - 62 			// content = this.makeUrlsAbsolute(content);
      - 63 		}
      - 64 		
      - 65 		return content;
      - 66 	},
      - 67 	
      - 68 	validateFontColor: function(element) {
      - 69 		var rdom = xq.RichDom.createInstance();
      - 70 		rdom.setRoot(element);
      - 71 		
      - 72 		// It should be reversed to deal with nested elements
      - 73 		var fonts = $A(element.getElementsByTagName('FONT')).reverse();
      - 74 		for(var i = 0; i < fonts.length; i++) {
      - 75 			var font = fonts[i];
      - 76 			var color = font.getAttribute('color');
      - 77 			
      - 78 			if(color) {
      - 79 				var span = rdom.replaceTag("span", font);
      - 80 				span.removeAttribute('color');
      - 81 				span.style.color = color;
      - 82 			}
      - 83 		}
      - 84 	},
      - 85 
      - 86 	invalidateFontColor: function(element) {
      - 87 		var rdom = xq.RichDom.createInstance();
      - 88 		rdom.setRoot(element);
      - 89 
      - 90 		var spans = $A(element.getElementsByTagName('SPAN')).reverse();
      - 91 		for(var i = 0; i < spans.length; i++) {
      - 92 			var span = spans[i];
      - 93 			var color = span.style.color;
      - 94 			
      - 95 			if(color) {
      - 96 				var font = rdom.replaceTag("font", span);
      - 97 				font.style.color = "";
      - 98 				font.setAttribute('color', color);
      - 99 			}
      -100 		}
      -101 	},
      -102 
      -103 	validateBackgroundColor: function(element) {
      -104 		var rdom = xq.RichDom.createInstance();
      -105 		rdom.setRoot(element);
      -106 
      -107 		// It should be reversed to deal with nested elements
      -108 		var fonts = $A(element.getElementsByTagName('FONT')).reverse();
      -109 		for(var i = 0; i < fonts.length; i++) {
      -110 			if(fonts[i].style.color || fonts[i].style.backgroundColor) rdom.replaceTag("span", fonts[i]);
      -111 		}
      -112 	},
      -113 
      -114 	invalidateBackgroundColor: function(element) {
      -115 		var rdom = xq.RichDom.createInstance();
      -116 		rdom.setRoot(element);
      -117 
      -118 		// It should be reversed to deal with nested elements
      -119 		var spans = $A(element.getElementsByTagName('SPAN')).reverse();
      -120 		for(var i = 0; i < spans.length; i++) {
      -121 			if(spans[i].style.color || spans[i].style.backgroundColor) rdom.replaceTag("font", spans[i]);
      -122 		}
      -123 	},
      -124 	
      -125 	lowerTagNamesAndUniformizeQuotation: function(content) {
      -126 		// Uniformize quotation, turn tag names and attribute names into lower case
      -127 		content = content.replace(/<(\/?)(\w+)([^>]*?)>/img, function(str, closingMark, tagName, attrs) {
      -128 			return "<" + closingMark + tagName.toLowerCase() + this.correctHtmlAttrQuotation(attrs) + ">";
      -129 		}.bind(this));
      -130 		
      -131 		return content;
      -132 	},
      -133 	
      -134 	correctHtmlAttrQuotation: function(html) {
      -135 		html = html.replace(/\s(\w+?)=\s+"([^"]+)"/mg,function (str, name, value) {return " " + name.toLowerCase() + '=' + '"' + value + '"'});
      -136 		html = html.replace(/\s(\w+?)=([^ "]+)/mg,function (str, name, value) {return " " + name.toLowerCase() + '=' + '"' + value + '"'});
      -137 		return html;
      -138 	}
      -139 });
      -140 
      \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_16.html b/modules/editor/skins/xquared/doc/api/src_16.html deleted file mode 100644 index eacdef1b9..000000000 --- a/modules/editor/skins/xquared/doc/api/src_16.html +++ /dev/null @@ -1,112 +0,0 @@ -
        1 /**
      -  2  * Validator for W3C Standard Engine
      -  3  */
      -  4 xq.ValidatorW3 = Class.create(xq.Validator, {
      -  5 	validate: function(element, fullValidation) {
      -  6 		element = element.cloneNode(true);
      -  7 
      -  8 		var rdom = xq.RichDom.createInstance();
      -  9 		rdom.setRoot(element);
      - 10 		rdom.removePlaceHoldersAndEmptyNodes(element);
      - 11 		this.removeDangerousElements(element);
      - 12 		this.validateFontColor(element);
      - 13 
      - 14 		var content = element.innerHTML;
      - 15 		
      - 16 		try {
      - 17 			content = this.replaceTag(content, "b", "strong");
      - 18 			content = this.replaceTag(content, "i", "em");
      - 19 			
      - 20 			content = this.validateStrike(content);
      - 21 			content = this.validateUnderline(content);
      - 22 			content = this.addNbspToEmptyBlocks(content);
      - 23 			
      - 24 			if(fullValidation) content = this.performFullValidation(content);
      - 25 		} catch(ignored) {}
      - 26 
      - 27 		// insert newline between block-tags
      - 28 		var blocks = rdom.tree.getBlockTags().join("|");
      - 29 		var regex = new RegExp("</(" + blocks + ")>([^\n])", "img");
      - 30 		content = content.replace(regex, '</$1>\n$2');
      - 31 		
      - 32 		return content;
      - 33 	},
      - 34 	invalidate: function(element) {
      - 35 		var rdom = xq.RichDom.createInstance();
      - 36 		rdom.setRoot(element);
      - 37 		
      - 38 		// <span class="strike"> -> <strike>
      - 39 		var strikes = rdom.findByAttribute("class", "strike");
      - 40 		for(var i = 0; i < strikes.length; i++) {
      - 41 			if("SPAN" == strikes[i].nodeName) rdom.replaceTag("strike", strikes[i]).removeAttribute("class");
      - 42 		}
      - 43 		
      - 44 		// <em|i class="underline"> -> <u>
      - 45 		var underlines = rdom.findByAttribute("class", "underline");
      - 46 		for(var i = 0; i < underlines.length; i++) {
      - 47 			if(["EM", "I"].include(underlines[i].nodeName)) rdom.replaceTag("u", underlines[i]).removeAttribute("class");
      - 48 		}
      - 49 		
      - 50 		var content = rdom.getRoot().innerHTML;
      - 51 		
      - 52 		content = this.replaceTag(content, "strong", "b");
      - 53 		content = this.replaceTag(content, "em", "i");
      - 54 		content = this.removeComments(content);
      - 55 		content = this.replaceNbspToBr(content);
      - 56 		
      - 57 		return content;
      - 58 	},
      - 59 	
      - 60 	performFullValidation: function(content) {
      - 61 		content = this.validateSelfClosingTags(content);
      - 62 		content = this.applyWhitelist(content);
      - 63 		
      - 64 		if(this.urlValidationMode == 'relative') {
      - 65 			content = this.makeUrlsRelative(content);
      - 66 		} else if(this.urlValidationMode == 'host_relative') {
      - 67 			content = this.makeUrlsHostRelative(content);
      - 68 		} else if(this.urlValidationMode == 'absolute') {
      - 69 			content = this.makeUrlsAbsolute(content);
      - 70 		}
      - 71 
      - 72 		return content;
      - 73 	},
      - 74 	
      - 75 	validateFontColor: function(element) {
      - 76 		var rdom = xq.RichDom.createInstance();
      - 77 		rdom.setRoot(element);
      - 78 
      - 79 		var fonts = $A(element.getElementsByTagName('FONT')).reverse();
      - 80 		for(var i = 0; i < fonts.length; i++) {
      - 81 			var font = fonts[i];
      - 82 			var color = font.getAttribute('color');
      - 83 			
      - 84 			if(color) {
      - 85 				var span = rdom.replaceTag("span", font);
      - 86 				span.removeAttribute('color');
      - 87 				span.style.color = color;
      - 88 			}
      - 89 		}
      - 90 	},
      - 91 	
      - 92 	addNbspToEmptyBlocks: function(content) {
      - 93 		var blocks = new xq.DomTree().getBlockTags().join("|");
      - 94 		var regex = new RegExp("<(" + blocks + ")>\\s*?</(" + blocks + ")>", "img");
      - 95 		return content.replace(regex, '<$1> </$2>');
      - 96 	},
      - 97 	
      - 98 	replaceNbspToBr: function(content) {
      - 99 		var blocks = new xq.DomTree().getBlockTags().join("|");
      -100 		var regex = new RegExp("<(" + blocks + ")>( )?</(" + blocks + ")>", "img");
      -101 		var rdom = xq.RichDom.createInstance();
      -102 		return content.replace(regex, '<$1>' + rdom.makePlaceHolderString() + '</$3>');
      -103 	}
      -104 });
      -105 
      \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_17.html b/modules/editor/skins/xquared/doc/api/src_17.html deleted file mode 100644 index b07ebbc67..000000000 --- a/modules/editor/skins/xquared/doc/api/src_17.html +++ /dev/null @@ -1,21 +0,0 @@ -
        1 /**
      -  2  * Validator for Webkit
      -  3  */
      -  4 xq.ValidatorWebkit = Class.create(xq.ValidatorW3, {
      -  5 });
      -  6 
      -  7 /*
      -  8 if(node.nodeName == "SPAN" && node.className == "Apple-style-span" && node.style.fontStyle == "italic") em = true;
      -  9 if(node.nodeName == "SPAN" && node.className == "Apple-style-span" && node.style.fontWeight == "bold") strong = true;
      - 10 if(node.nodeName == "SPAN" && node.className == "Apple-style-span" && node.style.textDecoration == "line-through") strike = true;
      - 11 if(node.nodeName == "SPAN" && node.className == "Apple-style-span" && node.style.textDecoration == "underline") underline = true;
      - 12 if(node.nodeName == "SPAN" && node.className == "Apple-style-span" && node.style.cssText.indexOf("vertical-align: super;") != -1) superscription = true;
      - 13 if(node.nodeName == "SPAN" && node.className == "Apple-style-span" && node.style.cssText.indexOf("vertical-align: sub;") != -1) subscription = true;
      - 14 */
      \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_18.html b/modules/editor/skins/xquared/doc/api/src_18.html deleted file mode 100644 index 5fa6b1885..000000000 --- a/modules/editor/skins/xquared/doc/api/src_18.html +++ /dev/null @@ -1,157 +0,0 @@ -
        1 /**
      -  2  * Namespace for entire Xquared classes
      -  3  */
      -  4 var xq = {
      -  5 	majorVersion: '0.1',
      -  6 	minorVersion: '2007119'
      -  7 };
      -  8 
      -  9 /**
      - 10  * Make given object as event source
      - 11  *
      - 12  * @param {Object} object target object
      - 13  * @param {String} prefix prefix for generated functions
      - 14  * @param {Array} events array of string which contains name of events
      - 15  */
      - 16 xq.asEventSource = function(object, prefix, events) {
      - 17 	object._listeners = []
      - 18 	object._registerEventFirer = function(prefix, name) {
      - 19 		this["_fireOn" + name] = function() {
      - 20 			for(var i = 0; i < this._listeners.length; i++) {
      - 21 				var listener = this._listeners[i];
      - 22 				var func = listener["on" + prefix + name];
      - 23 				if(func) func.apply(listener, $A(arguments));
      - 24 			}
      - 25 		}
      - 26 	}
      - 27 	object.addListener = function(l) {
      - 28 		this._listeners.push(l);
      - 29 	}
      - 30 	
      - 31 	for(var i = 0; i < events.length; i++) {
      - 32 		object._registerEventFirer(prefix, events[i]);
      - 33 	}
      - 34 }
      - 35 
      - 36 /**
      - 37  * Returns the index of given element
      - 38  *
      - 39  * @returns {Number} index or -1
      - 40  */
      - 41 Array.prototype.indexOf = function(n) {
      - 42 	for(var i = 0; i < this.length; i++) {
      - 43 		if(this[i] == n) return i;
      - 44 	}
      - 45 	
      - 46 	return -1;
      - 47 }
      - 48 
      - 49 Date.preset = null;
      - 50 Date.pass = function(msec) {
      - 51 	if(Date.preset == null) return;
      - 52 	Date.preset = new Date(Date.preset.getTime() + msec);
      - 53 }
      - 54 Date.get = function() {
      - 55 	return Date.preset == null ? new Date() : Date.preset;
      - 56 }
      - 57 Date.prototype.elapsed = function(msec) {
      - 58 	return Date.get().getTime() - this.getTime() >= msec;
      - 59 }
      - 60 
      - 61 String.prototype.merge = function(data) {
      - 62 	var newString = this;
      - 63 	for(k in data) {
      - 64 		newString = newString.replace("{" + k + "}", data[k]);
      - 65 	}
      - 66 	return newString;
      - 67 }
      - 68 
      - 69 String.prototype.parseURL = function() {
      - 70 	var m = this.match(/((((\w+):\/\/(((([^@:]+)(:([^@]+))?)@)?([^:\/\?#]+)?(:(\d+))?))?([^\?#]+)?)(\?([^#]+))?)(#(.+))?/);
      - 71 	
      - 72 	var includeAnchor = m[0];
      - 73 	var includeQuery = m[1] || undefined;
      - 74 	var includePath = m[2] || undefined;
      - 75 	var includeHost = m[3] || undefined;
      - 76 	var includeBase = null;
      - 77 	var protocol = m[4] || undefined;
      - 78 	var user = m[8] || undefined;
      - 79 	var password = m[10] || undefined;
      - 80 	var domain = m[11] || undefined;
      - 81 	var port = m[13] || undefined;
      - 82 	var path = m[14] || undefined;
      - 83 	var query = m[16] || undefined;
      - 84 	var anchor = m[18] || undefined;
      - 85 	
      - 86 	if(!path || path == '/') {
      - 87 		includeBase = includeHost + '/';
      - 88 	} else {
      - 89 		var index = path.lastIndexOf('/');
      - 90 		includeBase = includeHost + path.substring(0, index + 1);
      - 91 	}
      - 92 	
      - 93 	return {
      - 94 		includeAnchor: includeAnchor,
      - 95 		includeQuery: includeQuery,
      - 96 		includePath: includePath,
      - 97 		includeBase: includeBase,
      - 98 		includeHost: includeHost,
      - 99 		protocol: protocol,
      -100 		user: user,
      -101 		password: password,
      -102 		domain: domain,
      -103 		port: port,
      -104 		path: path,
      -105 		query: query,
      -106 		anchor: anchor
      -107 	};
      -108 }
      -109 
      -110 xq.findXquaredScript = function() {
      -111     return $A(document.getElementsByTagName("script")).find(function(script) {
      -112     	return script.src && script.src.match(/xquared\.js/i);
      -113     });
      -114 }
      -115 xq.shouldLoadOthers = function() {
      -116 	var script = xq.findXquaredScript();
      -117     return script && !!script.src.match(/xquared\.js\?load_others=1/i);
      -118 }
      -119 xq.loadScript = function(url) {
      -120     document.write('<script type="text/javascript" src="' + url + '"></script>');
      -121 }
      -122 xq.loadOthers = function() {
      -123 	var script = xq.findXquaredScript();
      -124 	var basePath = script.src.match(/(.*\/)xquared\.js.*/i)[1];
      -125 	var others = [
      -126 		'Editor.js',
      -127 		'Browser.js',
      -128 		'Shortcut.js',
      -129 		'DomTree.js',
      -130 		'RichDom.js',
      -131 		'RichDomW3.js',
      -132 		'RichDomGecko.js',
      -133 		'RichDomWebkit.js',
      -134 		'RichDomTrident.js',
      -135 		'RichTable.js',
      -136 		'Validator.js',
      -137 		'ValidatorW3.js',
      -138 		'ValidatorGecko.js',
      -139 		'ValidatorWebkit.js',
      -140 		'ValidatorTrident.js',
      -141 		'EditHistory.js',
      -142 		'Controls.js',
      -143 		'_ui_templates.js'
      -144 	];
      -145 	others.each(function(name) {
      -146 		xq.loadScript(basePath + name);
      -147 	});
      -148 }
      -149 
      -150 if(xq.shouldLoadOthers()) xq.loadOthers();
      \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_19.html b/modules/editor/skins/xquared/doc/api/src_19.html deleted file mode 100644 index feb2f6a4e..000000000 --- a/modules/editor/skins/xquared/doc/api/src_19.html +++ /dev/null @@ -1,16 +0,0 @@ -
        1 if(!xq) xq = {};
      -  2 if(!xq.ui_templates) xq.ui_templates = {};
      -  3 
      -  4 xq.ui_templates.basicColorPickerDialog='<form action="#" class="xqFormDialog xqBasicColorPickerDialog">\n		<div>\n			<label>\n				<input type="radio" class="initialFocus" name="color" value="black" checked="checked" />\n				<span style="color: black;">Black</span>\n			</label>\n			<label>\n				<input type="radio" name="color" value="red" />\n				<span style="color: red;">Red</span>\n			</label>\n				<input type="radio" name="color" value="yellow" />\n				<span style="color: yellow;">Yellow</span>\n			</label>\n			</label>\n				<input type="radio" name="color" value="pink" />\n				<span style="color: pink;">Pink</span>\n			</label>\n			<label>\n				<input type="radio" name="color" value="blue" />\n				<span style="color: blue;">Blue</span>\n			</label>\n			<label>\n				<input type="radio" name="color" value="green" />\n				<span style="color: green;">Green</span>\n			</label>\n			\n			<input type="submit" value="Ok" />\n			<input type="button" class="cancel" value="Cancel" />\n		</div>\n	</form>';
      -  5 if(!xq) xq = {};
      -  6 if(!xq.ui_templates) xq.ui_templates = {};
      -  7 
      -  8 xq.ui_templates.basicLinkDialog='<form action="#" class="xqFormDialog xqBasicLinkDialog">\n		<h3>Link</h3>\n		<div>\n			<input type="text" class="initialFocus" name="text" value="" />\n			<input type="text" name="url" value="http://" />\n			\n			<input type="submit" value="Ok" />\n			<input type="button" class="cancel" value="Cancel" />\n		</div>\n	</form>';
      -  9 
      \ No newline at end of file From 8752115b690bc34f563b136a870d1b933a90a7ca Mon Sep 17 00:00:00 2001 From: zero Date: Tue, 4 Dec 2007 02:01:47 +0000 Subject: [PATCH 125/265] git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3149 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/member/skins/default/find_member_account.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/member/skins/default/find_member_account.html b/modules/member/skins/default/find_member_account.html index 525dd16ad..644a7f735 100644 --- a/modules/member/skins/default/find_member_account.html +++ b/modules/member/skins/default/find_member_account.html @@ -8,7 +8,7 @@ - +
      From b396c811c791c37d01d5e68e075360e6b7cf5f37 Mon Sep 17 00:00:00 2001 From: haneul Date: Tue, 4 Dec 2007 03:09:39 +0000 Subject: [PATCH 126/265] [Xquared] added align to allowed attributes git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3150 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/editor/skins/xquared/js/xe_interface.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/modules/editor/skins/xquared/js/xe_interface.js b/modules/editor/skins/xquared/js/xe_interface.js index d70b45245..ca9f04d6c 100644 --- a/modules/editor/skins/xquared/js/xe_interface.js +++ b/modules/editor/skins/xquared/js/xe_interface.js @@ -30,11 +30,8 @@ function editorGetContent_xq(editor_sequence) { function editorStart_xq(editor, element, editor_sequence, content_key, editor_height, primary_key) { editor = new xq.Editor(element); - var additionalAttributes = ['editor_component', 'poll_srl','multimedia_src', 'auto_start', 'link_url', 'editor_sequence', 'use_folder', 'folder_opener', 'folder_closer', 'color', 'border_thickness', 'border_color', 'bg_color', 'border_style', 'margin', 'padding', 'bold', 'nx', 'ny', 'gx', 'gy', 'address', 'reg_sinpic', 'language']; - var additionalTags = ['embed', 'param', 'object']; - additionalAttributes.each( function (item, index) { - editor.config.allowedAttributes.push(item); } ); - additionalTags.each( function (item, index) { editor.config.allowedTags.push(item); } ); + editor.config.allowedAttributes.push('editor_component', 'poll_srl','multimedia_src', 'auto_start', 'link_url', 'editor_sequence', 'use_folder', 'folder_opener', 'folder_closer', 'color', 'border_thickness', 'border_color', 'bg_color', 'border_style', 'margin', 'padding', 'bold', 'nx', 'ny', 'gx', 'gy', 'address', 'reg_sinpic', 'language','align'); + editor.config.allowedTags.push('embed', 'param', 'object'); editorRelKeys[editor_sequence] = new Array(); editorRelKeys[editor_sequence]['editor'] = editor; From e882a5eff6d57265dfa9e7b2f42f3093ee99102e Mon Sep 17 00:00:00 2001 From: haneul Date: Tue, 4 Dec 2007 03:27:30 +0000 Subject: [PATCH 127/265] fixed #297 git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3151 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/guestbook/skins/default/css/guestbook.css | 2 +- modules/guestbook/skins/default/list.html | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/guestbook/skins/default/css/guestbook.css b/modules/guestbook/skins/default/css/guestbook.css index d44618ada..8ae411843 100644 --- a/modules/guestbook/skins/default/css/guestbook.css +++ b/modules/guestbook/skins/default/css/guestbook.css @@ -57,7 +57,7 @@ .documentBox { padding:.6em .6em; color:#666666; border:1px solid #e0e1db; margin-top:.5em;} .documentBox .documentItem { padding:.6em .8em .6em .6em; line-height:1.25em; clear:both; list-style:none;} .documentBox p { display:inline; margin-bottom:1em;} -.documentBox .author { float:left; padding:0 .3em 0 0; font-size:.9em; color:#3074a5; margin:0 .3em .5em 0;} +.documentBox .author { float:left; padding:0 .3em 0 0; font-size:.9em; color:#3074a5; margin:0 .3em .5em 0; cursor:pointer;} .documentBox .author a { color:#3074a5; margin-right:.3em; text-decoration:none; } .documentBox .voted { float:left; font-size:.9em; color:#AAAAAA; margin:0 .3em .5em 1em;} .documentBox .date { float:right; font:.8em Tahoma; color:#cccccc; margin:.3em 0 .5em 0;} diff --git a/modules/guestbook/skins/default/list.html b/modules/guestbook/skins/default/list.html index 6cbcb6ca4..79b4e1aa7 100644 --- a/modules/guestbook/skins/default/list.html +++ b/modules/guestbook/skins/default/list.html @@ -29,14 +29,14 @@
      - - - {$document->getNickName()} + + + {$document->getNickName()} {$document->getNickName()} -
      {$document->getNickName()}
      +
      {$document->getNickName()}
      From def289725b008163a6f7f5b8bb01735a6a2cb411 Mon Sep 17 00:00:00 2001 From: k10206 Date: Tue, 4 Dec 2007 07:09:12 +0000 Subject: [PATCH 128/265] =?UTF-8?q?=EA=B8=B0=EB=B3=B8=20=EB=AA=A8=EB=93=88?= =?UTF-8?q?=EC=9D=BC=20=EB=95=8C=20(=EA=B8=B0=EB=B3=B8)=EC=9D=B4=20=20?= =?UTF-8?q?=ED=91=9C=EC=8B=9C=EB=90=98=EB=8F=84=EB=A1=9D=20=EC=A0=95?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3152 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/springnote/tpl/header.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/springnote/tpl/header.html b/modules/springnote/tpl/header.html index 46debf38f..0e1a196d6 100644 --- a/modules/springnote/tpl/header.html +++ b/modules/springnote/tpl/header.html @@ -7,7 +7,7 @@
      -

      {$module_info->mid} ({$lang->is_default}) | View

      +

      {$module_info->mid} ({$lang->is_default}) | View

        From 6a322a17cedfbe651f514e08fc4c46d3d7b554d2 Mon Sep 17 00:00:00 2001 From: zero Date: Tue, 4 Dec 2007 08:25:54 +0000 Subject: [PATCH 129/265] =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EA=B8=80=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=B6=94=EC=B6=9C=EC=8B=9C=20=EA=B3=B5=EC=A7=80?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EC=A0=9C=EC=99=B8=20=EC=B6=94=EC=B6=9C?= =?UTF-8?q?=ED=95=A0=EB=95=8C=20php=EC=BD=94=EB=93=9C=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=A5=BC=20=EC=B2=98=EB=A6=AC=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=ED=95=98=EC=97=AC=20db=20=EC=BF=BC=EB=A6=AC=20?= =?UTF-8?q?=EC=86=8D=EB=8F=84=20=EB=B9=A0=EB=A5=B4=EA=B2=8C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3153 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/document/document.model.php | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/modules/document/document.model.php b/modules/document/document.model.php index 726381860..78e83467b 100644 --- a/modules/document/document.model.php +++ b/modules/document/document.model.php @@ -139,7 +139,7 @@ $args->page_count = $obj->page_count?$obj->page_count:10; $args->start_date = $obj->start_date?$obj->start_date:null; $args->end_date = $obj->end_date?$obj->end_date:null; - if($except_notice) $args->s_is_notice = 'N'; + //if($except_notice) $args->s_is_notice = 'N'; $query_id = 'document.getDocumentList'; @@ -241,15 +241,29 @@ // 결과가 없거나 오류 발생시 그냥 return if(!$output->toBool()||!count($output->data)) return $output; - foreach($output->data as $key => $attribute) { - $document_srl = $attribute->document_srl; + $idx = 0; + $data = $output->data; + unset($output->data); + $keys = array_keys($data); + $virtual_number = $keys[0]; + + if($except_notice) { + foreach($data as $key => $attribute) { + if($attribute->is_notice == 'Y') $virtual_number --; + } + } + + foreach($data as $key => $attribute) { + if($except_notice && $attribute->is_notice == 'Y') continue; + $document_srl = $attribute->document_srl; $oDocument = null; $oDocument = new documentItem(); $oDocument->setAttribute($attribute); if($is_admin) $oDocument->setGrant(); - $output->data[$key] = $oDocument; + $output->data[$virtual_number] = $oDocument; + $virtual_number --; } return $output; From 539c32082eecfdbff538cd790174c1ab70a8004d Mon Sep 17 00:00:00 2001 From: zero Date: Tue, 4 Dec 2007 08:26:15 +0000 Subject: [PATCH 130/265] =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=95=EC=9D=84=20?= =?UTF-8?q?=ED=95=A0=20=EA=B2=BD=EC=9A=B0=20DB=20class=EC=97=90=EC=84=9C?= =?UTF-8?q?=20navigation=EC=9D=84=20=EC=B2=98=EB=A6=AC=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3154 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- classes/db/DB.class.php | 20 ++++++++++++++++ classes/db/DBCubrid.class.php | 36 +++++++++++++++++++++++++---- classes/db/DBMysql.class.php | 31 ++++++++++++++++--------- classes/db/DBMysql_innodb.class.php | 33 ++++++++++++++++---------- classes/db/DBSqlite2.class.php | 31 ++++++++++++++++--------- classes/db/DBSqlite3_pdo.class.php | 31 ++++++++++++++++--------- 6 files changed, 133 insertions(+), 49 deletions(-) diff --git a/classes/db/DB.class.php b/classes/db/DB.class.php index ca186a6e1..6191596d1 100644 --- a/classes/db/DB.class.php +++ b/classes/db/DB.class.php @@ -246,6 +246,7 @@ if( (is_a($output, 'Object')||is_subclass_of($output,'Object'))&&!$output->toBool()) return $output; + // action값에 따라서 쿼리 생성으로 돌입 switch($output->action) { case 'insert' : @@ -395,5 +396,24 @@ break; } } + + /** + * @brief condition key를 return + **/ + function getConditionList($output) { + $conditions = array(); + if(count($output->conditions)) { + foreach($output->conditions as $key => $val) { + if($val['condition']) { + foreach($val['condition'] as $k => $v) { + $conditions[] = $v['column']; + } + } + } + } + + return $conditions; + + } } ?> diff --git a/classes/db/DBCubrid.class.php b/classes/db/DBCubrid.class.php index e44bb8ee7..8943d9299 100644 --- a/classes/db/DBCubrid.class.php +++ b/classes/db/DBCubrid.class.php @@ -556,17 +556,45 @@ $condition = $this->getCondition($output); - if($output->list_count) return $this->_getNavigationData($table_list, $columns, $condition, $output); + if($output->list_count && $output->page) return $this->_getNavigationData($table_list, $columns, $condition, $output); $query = sprintf("select %s from %s %s", $columns, implode(',',$table_list), $condition); if(count($output->groups)) $query .= sprintf(' group by %s', implode(',',$output->groups)); - if($output->order) { - foreach($output->order as $key => $val) { + // list_count를 사용할 경우 적용 + if($output->list_count['value']) { + + $start_count = 0; + $list_count = $output->list_count['value']; + + if ($output->order) { + foreach($output->order as $key => $val) { $index_list[] = sprintf('%s %s', $val[0], $val[1]); + } + if(count($index_list)) $query .= ' order by '.implode(',',$index_list); + $query = sprintf('%s for orderby_num() between %d and %d', $query, $start_count, $list_count); } - if(count($index_list)) $query .= ' order by '.implode(',',$index_list); + else { + if (count($output->groups)) + $query = sprintf('%s having groupby_num() between %d and %d', $query, $start_count, $list_count); + else { + if ($condition) + $query = sprintf('%s and inst_num() between %d and %d', $query, $start_count, $list_count); + else + $query = sprintf('%s where inst_num() between %d and %d', $query, $start_count, $list_count); + } + } + + } else { + + if($output->order) { + foreach($output->order as $key => $val) { + $index_list[] = sprintf('%s %s', $val[0], $val[1]); + } + if(count($index_list)) $query .= ' order by '.implode(',',$index_list); + } + } $result = $this->_query($query); diff --git a/classes/db/DBMysql.class.php b/classes/db/DBMysql.class.php index 51dcc8c3c..15a357ed8 100644 --- a/classes/db/DBMysql.class.php +++ b/classes/db/DBMysql.class.php @@ -499,15 +499,18 @@ $condition = $this->getCondition($output); - if($output->list_count) return $this->_getNavigationData($table_list, $columns, $condition, $output); + if($output->list_count && $output->page) return $this->_getNavigationData($table_list, $columns, $condition, $output); // list_order, update_order 로 정렬시에 인덱스 사용을 위해 condition에 쿼리 추가 if($output->order) { - foreach($output->order as $key => $val) { - $col = $val[0]; - if(!in_array($col, array('list_order','update_order'))) continue; - if($condition) $condition .= sprintf(' and %s < 2100000000 ', $col); - else $condition = sprintf(' where %s < 2100000000 ', $col); + $conditions = $this->getConditionList($output); + if(!in_array('list_order', $conditions) && !in_array('update_order', $conditions)) { + foreach($output->order as $key => $val) { + $col = $val[0]; + if(!in_array($col, array('list_order','update_order'))) continue; + if($condition) $condition .= sprintf(' and %s < 2100000000 ', $col); + else $condition = sprintf(' where %s < 2100000000 ', $col); + } } } @@ -522,6 +525,9 @@ if(count($index_list)) $query .= ' order by '.implode(',',$index_list); } + // list_count를 사용할 경우 적용 + if($output->list_count['value']) $query = sprintf('%s limit %d', $query, $output->list_count['value']); + $result = $this->_query($query); if($this->isError()) return; $data = $this->_fetch($result); @@ -562,11 +568,14 @@ // list_order, update_order 로 정렬시에 인덱스 사용을 위해 condition에 쿼리 추가 if($output->order) { - foreach($output->order as $key => $val) { - $col = $val[0]; - if(!in_array($col, array('list_order','update_order'))) continue; - if($condition) $condition .= sprintf(' and %s < 2100000000 ', $col); - else $condition = sprintf(' where %s < 2100000000 ', $col); + $conditions = $this->getConditionList($output); + if(!in_array('list_order', $conditions) && !in_array('update_order', $conditions)) { + foreach($output->order as $key => $val) { + $col = $val[0]; + if(!in_array($col, array('list_order','update_order'))) continue; + if($condition) $condition .= sprintf(' and %s < 2100000000 ', $col); + else $condition = sprintf(' where %s < 2100000000 ', $col); + } } } diff --git a/classes/db/DBMysql_innodb.class.php b/classes/db/DBMysql_innodb.class.php index 4fc9c5a83..a653cc420 100644 --- a/classes/db/DBMysql_innodb.class.php +++ b/classes/db/DBMysql_innodb.class.php @@ -508,15 +508,18 @@ $condition = $this->getCondition($output); - if($output->list_count) return $this->_getNavigationData($table_list, $columns, $condition, $output); + if($output->list_count && $output->page) return $this->_getNavigationData($table_list, $columns, $condition, $output); // list_order, update_order 로 정렬시에 인덱스 사용을 위해 condition에 쿼리 추가 if($output->order) { - foreach($output->order as $key => $val) { - $col = $val[0]; - if(!in_array($col, array('list_order','update_order'))) continue; - if($condition) $condition .= sprintf(' and %s < 2100000000 ', $col); - else $condition = sprintf(' where %s < 2100000000 ', $col); + $conditions = $this->getConditionList($output); + if(!in_array('list_order', $conditions) && !in_array('update_order', $conditions)) { + foreach($output->order as $key => $val) { + $col = $val[0]; + if(!in_array($col, array('list_order','update_order'))) continue; + if($condition) $condition .= sprintf(' and %s < 2100000000 ', $col); + else $condition = sprintf(' where %s < 2100000000 ', $col); + } } } @@ -531,6 +534,9 @@ if(count($index_list)) $query .= ' order by '.implode(',',$index_list); } + // list_count를 사용할 경우 적용 + if($output->list_count['value']) $query = sprintf('%s limit %d', $query, $output->list_count['value']); + $result = $this->_query($query); if($this->isError()) return; $data = $this->_fetch($result); @@ -571,11 +577,14 @@ // list_order, update_order 로 정렬시에 인덱스 사용을 위해 condition에 쿼리 추가 if($output->order) { - foreach($output->order as $key => $val) { - $col = $val[0]; - if(!in_array($col, array('list_order','update_order'))) continue; - if($condition) $condition .= sprintf(' and %s < 2100000000 ', $col); - else $condition = sprintf(' where %s < 2100000000 ', $col); + $conditions = $this->getConditionList($output); + if(!in_array('list_order', $conditions) && !in_array('update_order', $conditions)) { + foreach($output->order as $key => $val) { + $col = $val[0]; + if(!in_array($col, array('list_order','update_order'))) continue; + if($condition) $condition .= sprintf(' and %s < 2100000000 ', $col); + else $condition = sprintf(' where %s < 2100000000 ', $col); + } } } @@ -590,7 +599,7 @@ } $query = sprintf('%s limit %d, %d', $query, $start_count, $list_count); - + $result = $this->_query($query); if($this->isError()) { $buff = new Object(); diff --git a/classes/db/DBSqlite2.class.php b/classes/db/DBSqlite2.class.php index fb31f28f9..d10a75672 100644 --- a/classes/db/DBSqlite2.class.php +++ b/classes/db/DBSqlite2.class.php @@ -520,15 +520,18 @@ $condition = $this->getCondition($output); - if($output->list_count) return $this->_getNavigationData($table_list, $columns, $condition, $output); + if($output->list_count && $output->page) return $this->_getNavigationData($table_list, $columns, $condition, $output); // list_order, update_order 로 정렬시에 인덱스 사용을 위해 condition에 쿼리 추가 if($output->order) { - foreach($output->order as $key => $val) { - $col = $val[0]; - if(!in_array($col, array('list_order','update_order'))) continue; - if($condition) $condition .= sprintf(' and %s < 2100000000 ', $col); - else $condition = sprintf(' where %s < 2100000000 ', $col); + $conditions = $this->getConditionList($output); + if(!in_array('list_order', $conditions) && !in_array('update_order', $conditions)) { + foreach($output->order as $key => $val) { + $col = $val[0]; + if(!in_array($col, array('list_order','update_order'))) continue; + if($condition) $condition .= sprintf(' and %s < 2100000000 ', $col); + else $condition = sprintf(' where %s < 2100000000 ', $col); + } } } @@ -543,6 +546,9 @@ if(count($index_list)) $query .= ' order by '.implode(',',$index_list); } + // list_count를 사용할 경우 적용 + if($output->list_count['value']) $query = sprintf('%s limit %d', $query, $output->list_count['value']); + $result = $this->_query($query); if($this->isError()) return; $data = $this->_fetch($result); @@ -583,11 +589,14 @@ // list_order, update_order 로 정렬시에 인덱스 사용을 위해 condition에 쿼리 추가 if($output->order) { - foreach($output->order as $key => $val) { - $col = $val[0]; - if(!in_array($col, array('list_order','update_order'))) continue; - if($condition) $condition .= sprintf(' and %s < 2100000000 ', $col); - else $condition = sprintf(' where %s < 2100000000 ', $col); + $conditions = $this->getConditionList($output); + if(!in_array('list_order', $conditions) && !in_array('update_order', $conditions)) { + foreach($output->order as $key => $val) { + $col = $val[0]; + if(!in_array($col, array('list_order','update_order'))) continue; + if($condition) $condition .= sprintf(' and %s < 2100000000 ', $col); + else $condition = sprintf(' where %s < 2100000000 ', $col); + } } } diff --git a/classes/db/DBSqlite3_pdo.class.php b/classes/db/DBSqlite3_pdo.class.php index fcdefab69..9d001bbc4 100644 --- a/classes/db/DBSqlite3_pdo.class.php +++ b/classes/db/DBSqlite3_pdo.class.php @@ -561,15 +561,18 @@ $condition = $this->getCondition($output); - if($output->list_count) return $this->_getNavigationData($table_list, $columns, $condition, $output); + if($output->list_count && $output->page) return $this->_getNavigationData($table_list, $columns, $condition, $output); // list_order, update_order 로 정렬시에 인덱스 사용을 위해 condition에 쿼리 추가 if($output->order) { - foreach($output->order as $key => $val) { - $col = $val[0]; - if(!in_array($col, array('list_order','update_order'))) continue; - if($condition) $condition .= sprintf(' and %s < 2100000000 ', $col); - else $condition = sprintf(' where %s < 2100000000 ', $col); + $conditions = $this->getConditionList($output); + if(!in_array('list_order', $conditions) && !in_array('update_order', $conditions)) { + foreach($output->order as $key => $val) { + $col = $val[0]; + if(!in_array($col, array('list_order','update_order'))) continue; + if($condition) $condition .= sprintf(' and %s < 2100000000 ', $col); + else $condition = sprintf(' where %s < 2100000000 ', $col); + } } } @@ -584,6 +587,9 @@ if(count($index_list)) $query .= ' order by '.implode(',',$index_list); } + // list_count를 사용할 경우 적용 + if($output->list_count['value']) $query = sprintf('%s limit %d', $query, $output->list_count['value']); + $this->_prepare($query); $data = $this->_execute(); if($this->isError()) return; @@ -624,11 +630,14 @@ // list_order, update_order 로 정렬시에 인덱스 사용을 위해 condition에 쿼리 추가 if($output->order) { - foreach($output->order as $key => $val) { - $col = $val[0]; - if(!in_array($col, array('list_order','update_order'))) continue; - if($condition) $condition .= sprintf(' and %s < 2100000000 ', $col); - else $condition = sprintf(' where %s < 2100000000 ', $col); + $conditions = $this->getConditionList($output); + if(!in_array('list_order', $conditions) && !in_array('update_order', $conditions)) { + foreach($output->order as $key => $val) { + $col = $val[0]; + if(!in_array($col, array('list_order','update_order'))) continue; + if($condition) $condition .= sprintf(' and %s < 2100000000 ', $col); + else $condition = sprintf(' where %s < 2100000000 ', $col); + } } } From 1d4191e9baa3c25f044bcd99178fa56e8a0cd887 Mon Sep 17 00:00:00 2001 From: zero Date: Wed, 5 Dec 2007 03:04:31 +0000 Subject: [PATCH 131/265] =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EA=B8=80=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=EC=8B=9C=20division=EC=9D=84=20=EC=A0=81=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EC=97=AC=205000=EA=B0=9C=20=EB=8B=A8=EC=9C=84?= =?UTF-8?q?=EB=A1=9C=20=EA=B2=80=EC=83=89=ED=95=98=EA=B3=A0=20=EA=B3=84?= =?UTF-8?q?=EC=86=8D=20=EA=B2=80=EC=83=89=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=ED=95=98=EC=97=AC=20=EC=86=8D=EB=8F=84=20=EC=A6=9D=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3155 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/board/skins/cozy_board/css/common.css | 3 + modules/board/skins/cozy_board/list.html | 14 ++-- modules/board/skins/xe_board/list.html | 14 ++-- modules/document/document.model.php | 65 +++++++++++++++++- modules/document/lang/en.lang.php | 2 + modules/document/lang/es.lang.php | 2 + modules/document/lang/jp.lang.php | 2 + modules/document/lang/ko.lang.php | 2 + modules/document/lang/ru.lang.php | 2 + modules/document/lang/zh-CN.lang.php | 2 + .../document/queries/getDocumentDivision.xml | 18 +++++ .../queries/getDocumentDivisionCount.xml | 12 ++++ modules/document/queries/getDocumentList.xml | 6 +- .../queries/getDocumentListWithinComment.xml | 5 ++ .../skins/default/css/white.css | 2 + .../skins/default/images/white/h2Search.gif | Bin 756 -> 409 bytes .../skins/default/index.html | 18 +++-- 17 files changed, 148 insertions(+), 21 deletions(-) create mode 100644 modules/document/queries/getDocumentDivision.xml create mode 100644 modules/document/queries/getDocumentDivisionCount.xml diff --git a/modules/board/skins/cozy_board/css/common.css b/modules/board/skins/cozy_board/css/common.css index 0bd58477a..0875d7640 100644 --- a/modules/board/skins/cozy_board/css/common.css +++ b/modules/board/skins/cozy_board/css/common.css @@ -580,3 +580,6 @@ Jeong, Chan Myeong 070601~070630 .tags .tagTypeD a { font-weight:bold; margin:0; background-color:#EFEFEF;} .tags .tagTypeE a { font-weight:normal; margin:0;} + +.searchNextButton { border:1px solid #979797; border-left:1px solid #B1B1B1; border-top:1px solid #B1B1B1; color:#4F4F4F; height:21px; font-size:8pt; padding-left:5px; padding-right:5px; _padding-top:3px;} +*:first-child+html .searchNextButton { padding-top:3px; } diff --git a/modules/board/skins/cozy_board/list.html b/modules/board/skins/cozy_board/list.html index 5892f5ce8..8e999ec57 100644 --- a/modules/board/skins/cozy_board/list.html +++ b/modules/board/skins/cozy_board/list.html @@ -22,15 +22,15 @@ @@ -57,7 +57,13 @@ - + + + + + + + diff --git a/modules/board/skins/xe_board/list.html b/modules/board/skins/xe_board/list.html index a13f1a157..65bfa990f 100644 --- a/modules/board/skins/xe_board/list.html +++ b/modules/board/skins/xe_board/list.html @@ -37,15 +37,15 @@ @@ -61,8 +61,12 @@ - {$lang->cmd_search}{$lang->cmd_cancel} - + + + {$lang->cmd_search_next} + + {$lang->cmd_search} + {$lang->cmd_cancel}
      diff --git a/modules/document/document.model.php b/modules/document/document.model.php index 78e83467b..ddb7a4b7c 100644 --- a/modules/document/document.model.php +++ b/modules/document/document.model.php @@ -139,10 +139,13 @@ $args->page_count = $obj->page_count?$obj->page_count:10; $args->start_date = $obj->start_date?$obj->start_date:null; $args->end_date = $obj->end_date?$obj->end_date:null; - //if($except_notice) $args->s_is_notice = 'N'; + // 기본으로 사용할 query id 지정 (몇가지 검색 옵션에 따라 query id가 변경됨) $query_id = 'document.getDocumentList'; + // 내용검색일 경우 document division을 지정하여 검색하기 위한 처리 + $use_division = false; + // 검색 옵션 정리 $search_target = $obj->search_target; $search_keyword = $obj->search_keyword; @@ -151,15 +154,18 @@ case 'title' : if($search_keyword) $search_keyword = str_replace(' ','%',$search_keyword); $args->s_title = $search_keyword; + $use_division = true; break; case 'content' : if($search_keyword) $search_keyword = str_replace(' ','%',$search_keyword); $args->s_content = $search_keyword; + $use_division = true; break; case 'title_content' : if($search_keyword) $search_keyword = str_replace(' ','%',$search_keyword); $args->s_title = $search_keyword; $args->s_content = $search_keyword; + $use_division = true; break; case 'user_id' : if($search_keyword) $search_keyword = str_replace(' ','%',$search_keyword); @@ -225,16 +231,73 @@ $args->s_comment = $search_keyword; $args->sort_index = 'documents.'.$args->sort_index; $query_id = 'document.getDocumentListWithinComment'; + $use_division = true; break; default : preg_match('/^extra_vars([0-9]+)$/',$search_target,$matches); if($matches[1]) { $args->{"s_extra_vars".$matches[1]} = $search_keyword; + $use_division = true; } break; } } + /** + * 만약 use_division이 true일 경우 document division을 이용하도록 변경 + **/ + if($use_division) { + // 시작 division + $division = (int)Context::get('division'); + + // division값이 없다면 제일 상위 + if(!$division) { + $division_args->module_srl = $args->module_srl; + $division_args->list_count = 1; + $division_args->sort_index = $args->sort_index; + $division_args->order_type = $args->order_type; + $output = executeQuery("document.getDocumentList", $division_args); + if($output->data) { + $item = array_pop($output->data); + $division = $item->list_order; + } + $division_args = null; + } + + // 마지막 division + $last_division = (int)Context::get('last_division'); + + // 지정된 division에서부터 5000개 후의 division값을 구함 + if(!$last_division) { + $last_division_args->module_srl = $args->module_srl; + $last_division_args->list_count = 1; + $last_division_args->sort_index = $args->sort_index; + $last_division_args->order_type = $args->order_type; + $last_division_args->list_order = $division; + $last_division_args->page = 5001; + $output = executeQuery("document.getDocumentDivision", $last_division_args); + if($output->data) { + $item = array_pop($output->data); + $last_division = $item->list_order; + } + + } + + // last_division 이후로 글이 있는지 확인 + if($last_division) { + $last_division_args = null; + $last_division_args->module_srl = $args->module_srl; + $last_division_args->list_order = $last_division; + $output = executeQuery("document.getDocumentDivisionCount", $last_division_args); + if($output->data->count<1) $last_division = null; + } + + $args->division = $division; + $args->last_division = $last_division; + Context::set('division', $division); + Context::set('last_division', $last_division); + } + // document.getDocumentList 쿼리 실행 $output = executeQueryArray($query_id, $args); diff --git a/modules/document/lang/en.lang.php b/modules/document/lang/en.lang.php index c9a2ee5d5..fa0cea306 100644 --- a/modules/document/lang/en.lang.php +++ b/modules/document/lang/en.lang.php @@ -14,6 +14,8 @@ $lang->title_bold = 'Bold'; $lang->title_color = 'Color'; + $lang->cmd_search_next = '계속 검색'; + $lang->cmd_temp_save = 'Temporary Save'; $lang->cmd_toggle_checked_document = 'Reverse selected items'; diff --git a/modules/document/lang/es.lang.php b/modules/document/lang/es.lang.php index 0f4a8a929..113cc2a4c 100644 --- a/modules/document/lang/es.lang.php +++ b/modules/document/lang/es.lang.php @@ -14,6 +14,8 @@ $lang->title_bold = '제목 굵게'; $lang->title_color = '제목 색깔'; + $lang->cmd_search_next = '계속 검색'; + $lang->cmd_temp_save = '임시 저장'; $lang->cmd_toggle_checked_document = '선택항목 반전'; diff --git a/modules/document/lang/jp.lang.php b/modules/document/lang/jp.lang.php index 99856f143..acccd3ffb 100644 --- a/modules/document/lang/jp.lang.php +++ b/modules/document/lang/jp.lang.php @@ -13,6 +13,8 @@ $lang->move_target_module = "移動対象モジュール"; $lang->title_bold = 'タイトル太字'; $lang->title_color = 'タイトル文字色'; + + $lang->cmd_search_next = '계속 검색'; $lang->cmd_temp_save = '臨時保存'; diff --git a/modules/document/lang/ko.lang.php b/modules/document/lang/ko.lang.php index b45387f14..be3eceecc 100644 --- a/modules/document/lang/ko.lang.php +++ b/modules/document/lang/ko.lang.php @@ -13,6 +13,8 @@ $lang->title_bold = '제목 굵게'; $lang->title_color = '제목 색깔'; + $lang->cmd_search_next = '계속 검색'; + $lang->cmd_temp_save = '임시 저장'; $lang->cmd_toggle_checked_document = '선택항목 반전'; diff --git a/modules/document/lang/ru.lang.php b/modules/document/lang/ru.lang.php index ba46cdd90..5667abd50 100644 --- a/modules/document/lang/ru.lang.php +++ b/modules/document/lang/ru.lang.php @@ -14,6 +14,8 @@ $lang->title_bold = 'Жирное Название'; $lang->title_color = 'Цвет Названия'; + $lang->cmd_search_next = '계속 검색'; + $lang->cmd_temp_save = 'Сохранить временно'; $lang->cmd_toggle_checked_document = 'Перевернуть выбранные объекты'; diff --git a/modules/document/lang/zh-CN.lang.php b/modules/document/lang/zh-CN.lang.php index e7bc224f3..f0ddd908c 100644 --- a/modules/document/lang/zh-CN.lang.php +++ b/modules/document/lang/zh-CN.lang.php @@ -14,6 +14,8 @@ $lang->title_bold = '粗标题'; $lang->title_color = '标题颜色'; + $lang->cmd_search_next = '계속 검색'; + $lang->cmd_temp_save = '临时保存'; $lang->cmd_toggle_checked_document = '反选'; diff --git a/modules/document/queries/getDocumentDivision.xml b/modules/document/queries/getDocumentDivision.xml new file mode 100644 index 000000000..ebe094a5c --- /dev/null +++ b/modules/document/queries/getDocumentDivision.xml @@ -0,0 +1,18 @@ + + +
      + + + + + + + + + + + + + + + diff --git a/modules/document/queries/getDocumentDivisionCount.xml b/modules/document/queries/getDocumentDivisionCount.xml new file mode 100644 index 000000000..92bdce812 --- /dev/null +++ b/modules/document/queries/getDocumentDivisionCount.xml @@ -0,0 +1,12 @@ + + +
      + + + + + + + + + diff --git a/modules/document/queries/getDocumentList.xml b/modules/document/queries/getDocumentList.xml index f4c36d756..179afd594 100644 --- a/modules/document/queries/getDocumentList.xml +++ b/modules/document/queries/getDocumentList.xml @@ -8,6 +8,11 @@ + + + + + @@ -48,7 +53,6 @@ - diff --git a/modules/document/queries/getDocumentListWithinComment.xml b/modules/document/queries/getDocumentListWithinComment.xml index e3941ed1a..bb39eb0f3 100644 --- a/modules/document/queries/getDocumentListWithinComment.xml +++ b/modules/document/queries/getDocumentListWithinComment.xml @@ -8,7 +8,12 @@ + + + + + diff --git a/modules/integration_search/skins/default/css/white.css b/modules/integration_search/skins/default/css/white.css index 0206005c7..b50689f96 100644 --- a/modules/integration_search/skins/default/css/white.css +++ b/modules/integration_search/skins/default/css/white.css @@ -47,3 +47,5 @@ .pageNavigation a.goToLast img { display:inline-block; padding:2px 0; position:relative; top:2px; _top:1px;} .pageNavigation .current { position:relative; margin-left:-4px; font:bold 1em Tahoma; color:#ff6600; display:inline-block; padding:1px 7px 1px 6px; border-left:1px solid #dedfde; border-right:1px solid #CCCCCC; text-decoration:none; line-height:1em; } + +.searchNext { text-align:center; margin-top:10px;} diff --git a/modules/integration_search/skins/default/images/white/h2Search.gif b/modules/integration_search/skins/default/images/white/h2Search.gif index fba3fb0f59470d30f861b1426ef80f97d8e5b4f1..147eed4cff144fb688a55c02524e2a48e8076817 100644 GIT binary patch delta 207 zcmV;=05Jdb1(^d3M@dFFIbl)&5dhTykqp#-w!oUOHj+RJ8Ac>!Yua+qsB}uLTCdpb zuy#RADj8U$;e2M#=(KuU{1g@pjHj%w+wa>BLi1)g$WC{HgI8M?UT+FxbcBtKh7uYp z3o#ggO^%s@TO^1JiY|wun0%d4%6J-%|j>P6`vR^)aH)6A}?!Yua+qsB}sN+yd0< zEi1ikxlwCiSi2x5l?*J>a6Z8~t9L$t&T!ux4M&UOW;u6I05gR%27Wkjc6ek(9|a2x z7#?nmcQ~1uh=F)fdwo!UolrNLe2JwrtE^vlH)I_M8j%bRZBB~@ta~_hop}_fqJV;b zaG6lOr=hQ87H5$PY?g~rrU?UH1fEda2Yv!G0=~Swh{!qFbK9KFLlzPmD+@6gxJ}hi z0qn}$1DOJ_#Jg z6Gr)$Ac{L77E~MoA?@B9FacfWaS1Rz5XE#5j({#34Y?o!QU(RLu4Z{)K;V>J0|GqA z10ZGD91n0%7&NYq%6-Eck|ANFzy`c6^kx}QuH3IIDC2DD*>Gu7#XRK-F{7b>!iGs9 zG*dBUP*a}Tr*a5;$}y#)9FPh4mHZA`5*d|pEixtYq{$K^txaa-mWf78_=<5nevklys6w-eo}_94Ep7SP%d^$<^XJ diff --git a/modules/integration_search/skins/default/index.html b/modules/integration_search/skins/default/index.html index 8d7649e09..6e54af24a 100644 --- a/modules/integration_search/skins/default/index.html +++ b/modules/integration_search/skins/default/index.html @@ -34,13 +34,6 @@

      {$result_text}

      - -
    • {$val}
    • - - - -->
      • @@ -58,17 +51,22 @@
      + +
      + +
      + From 6a14bbe50fdb1bfabae27a95d0308c471bf73d8c Mon Sep 17 00:00:00 2001 From: zero Date: Wed, 5 Dec 2007 03:23:49 +0000 Subject: [PATCH 132/265] =?UTF-8?q?=C3=AA=C2=B8=C2=B0=C3=AB=C2=B3=C2=B8=20?= =?UTF-8?q?=C3=AB=C2=B8=C2=94=C3=AB=C2=A1=C2=9C=C3=AA=C2=B7=C2=B8=20=C3=AB?= =?UTF-8?q?=C2=A0=C2=88=C3=AC=C2=9D=C2=B4=C3=AC=C2=95=C2=84=C3=AC=C2=9B?= =?UTF-8?q?=C2=83=C3=AC=C2=97=C2=90=C3=AC=C2=84=C2=9C=20=C3=AC=C2=9C=C2=84?= =?UTF-8?q?=C3=AC=C2=A0=C2=AF=C3=AC=C2=9D=C2=98=20=C3=AA=C2=B8=C2=80=C3=AC?= =?UTF-8?q?=C2=82=C2=AC=C3=AC=C2=9D=C2=B4=20=C3=AA=C2=B0=C2=84=C3=AA=C2=B2?= =?UTF-8?q?=C2=A9=C3=AC=C2=9D=C2=84=20=C3=AB=C2=84=C2=93=C3=AD=C2=9E=C2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3156 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/blog/skins/xe_blog/css/common.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/blog/skins/xe_blog/css/common.css b/modules/blog/skins/xe_blog/css/common.css index a7e57ed0c..d1d225514 100644 --- a/modules/blog/skins/xe_blog/css/common.css +++ b/modules/blog/skins/xe_blog/css/common.css @@ -289,5 +289,5 @@ Jeong, Chan Myeong 070601~070630 /* widget common css */ .blog_widget_ h2 { border-left:1px solid #ffffff; border-right:1px solid #ffffff; padding:7px 0 0 12px; height:21px; _height:20px; font-size:1em; color:#54564b; } .blog_widget_ .items { padding:10px; overflow:hidden;} -.blog_widget_ .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; line-height:150%; overflow:hidden; white-space:nowrap; list-style:none; width:100%;} +.blog_widget_ .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; line-height:150%; overflow:hidden; white-space:nowrap; list-style:none; width:100%; padding:3px 0 3px 0;} .blog_widget_ .items li a { color:#a4a4a4; margin-right:1em; } From a70192c8e7a67f569d8b2d744df3b0d87903abbd Mon Sep 17 00:00:00 2001 From: zero Date: Wed, 5 Dec 2007 03:27:01 +0000 Subject: [PATCH 133/265] =?UTF-8?q?=C3=AC=C2=B5=C2=9C=C3=AA=C2=B7=C2=BC?= =?UTF-8?q?=C3=AA=C2=B8=C2=80/=C3=AC=C2=B5=C2=9C=C3=AA=C2=B7=C2=BC=C3=AB?= =?UTF-8?q?=C2=8C=C2=93=C3=AA=C2=B8=C2=80/=C3=AC=C2=B5=C2=9C=C3=AA=C2=B7?= =?UTF-8?q?=C2=BC=C3=AC=C2=97=C2=AE=C3=AC=C2=9D=C2=B8=C3=AA=C2=B8=C2=80/?= =?UTF-8?q?=C3=AD=C2=83=C2=9C=C3=AA=C2=B7=C2=B8/=C3=AA=C2=B8=C2=80=C3=AB?= =?UTF-8?q?=C2=B3=C2=B4=C3=AA=C2=B4=C2=80=C3=AD=C2=95=C2=A8=20=C3=AC=C2=9C?= =?UTF-8?q?=C2=84=C3=AC=C2=A0=C2=AF=C3=AC=C2=A4=C2=91=20blog=20=C3=AC?= =?UTF-8?q?=C2=8A=C2=A4=C3=AD=C2=82=C2=A8=C3=AC=C2=9D=C2=98=20=C3=AA=C2=B8?= =?UTF-8?q?=C2=80=20=C3=AC=C2=A4=C2=84=C3=AA=C2=B0=C2=84=C3=AA=C2=B2=C2=A9?= =?UTF-8?q?=C3=AC=C2=9D=C2=84=20=C3=AB=C2=84=C2=93=C3=AD=C2=9E=C2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3157 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- widgets/archive_list/skins/blog_archive_list/css/cyan.css | 2 +- widgets/archive_list/skins/blog_archive_list/css/green.css | 2 +- widgets/archive_list/skins/blog_archive_list/css/normal.css | 2 +- widgets/archive_list/skins/blog_archive_list/css/purple.css | 2 +- widgets/archive_list/skins/blog_archive_list/css/red.css | 2 +- widgets/newest_comment/skins/blog_newest_comment/css/cyan.css | 2 +- widgets/newest_comment/skins/blog_newest_comment/css/green.css | 2 +- widgets/newest_comment/skins/blog_newest_comment/css/normal.css | 2 +- widgets/newest_comment/skins/blog_newest_comment/css/purple.css | 2 +- widgets/newest_comment/skins/blog_newest_comment/css/red.css | 2 +- widgets/newest_document/skins/blog_newest_document/css/cyan.css | 2 +- .../newest_document/skins/blog_newest_document/css/green.css | 2 +- .../newest_document/skins/blog_newest_document/css/normal.css | 2 +- .../newest_document/skins/blog_newest_document/css/purple.css | 2 +- widgets/newest_document/skins/blog_newest_document/css/red.css | 2 +- .../newest_trackback/skins/blog_newest_trackback/css/cyan.css | 2 +- .../newest_trackback/skins/blog_newest_trackback/css/green.css | 2 +- .../newest_trackback/skins/blog_newest_trackback/css/normal.css | 2 +- .../newest_trackback/skins/blog_newest_trackback/css/purple.css | 2 +- .../newest_trackback/skins/blog_newest_trackback/css/red.css | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/widgets/archive_list/skins/blog_archive_list/css/cyan.css b/widgets/archive_list/skins/blog_archive_list/css/cyan.css index 6ea760d23..cb9215921 100644 --- a/widgets/archive_list/skins/blog_archive_list/css/cyan.css +++ b/widgets/archive_list/skins/blog_archive_list/css/cyan.css @@ -1,5 +1,5 @@ .blog_widget_cyan .archive { position:relative; border:1px solid #e0e1db; background:url(../images/cyan/bgBoxTypeB.gif) repeat-x left top; margin-bottom:.7em; } .blog_widget_cyan .archive h2 { position:relative; border-left:1px solid #ffffff; border-right:1px solid #ffffff; padding:7px 0 0 12px; height:21px; _height:20px; font-size:1em; color:#54564b; font-family:Tahoma;} .blog_widget_cyan .archive .items { padding:.4em 1.2em .4em 1.2em; overflow:hidden;} -.blog_widget_cyan .archive .items li { font-size:.75em; display:block; color:#a4a4a4; margin-right:.1em; line-height:1.5em; font-family:tahoma; } +.blog_widget_cyan .archive .items li { font-size:.75em; display:block; color:#a4a4a4; margin-right:.1em; line-height:1.5em; font-family:tahoma; padding:3px 0 3px 0;} .blog_widget_cyan .archive .items li a { color:#a4a4a4; font-weight:bold; margin-right:1em; font-family:tahoma;} diff --git a/widgets/archive_list/skins/blog_archive_list/css/green.css b/widgets/archive_list/skins/blog_archive_list/css/green.css index ba171178f..631d118ff 100644 --- a/widgets/archive_list/skins/blog_archive_list/css/green.css +++ b/widgets/archive_list/skins/blog_archive_list/css/green.css @@ -1,5 +1,5 @@ .blog_widget_green .archive { position:relative; border:1px solid #e0e1db; background:url(../images/green/bgBoxTypeB.gif) repeat-x left top; margin-bottom:.7em; } .blog_widget_green .archive h2 { position:relative; border-left:1px solid #ffffff; border-right:1px solid #ffffff; padding:7px 0 0 12px; height:21px; _height:20px; font-size:1em; color:#54564b; font-family:Tahoma;} .blog_widget_green .archive .items { padding:.4em 1.2em .4em 1.2em; overflow:hidden;} -.blog_widget_green .archive .items li { font-size:.75em; display:block; color:#a4a4a4; margin-right:.1em; line-height:1.5em; font-family:tahoma; } +.blog_widget_green .archive .items li { font-size:.75em; display:block; color:#a4a4a4; margin-right:.1em; line-height:1.5em; font-family:tahoma; padding:3px 0 3px 0;} .blog_widget_green .archive .items li a { color:#a4a4a4; font-weight:bold; margin-right:1em; font-family:tahoma;} diff --git a/widgets/archive_list/skins/blog_archive_list/css/normal.css b/widgets/archive_list/skins/blog_archive_list/css/normal.css index 4fe653669..a60468fbd 100644 --- a/widgets/archive_list/skins/blog_archive_list/css/normal.css +++ b/widgets/archive_list/skins/blog_archive_list/css/normal.css @@ -1,5 +1,5 @@ .blog_widget_normal .archive { position:relative; border:1px solid #e0e1db; background:url(../images/normal/bgBoxTypeB.gif) repeat-x left top; margin-bottom:.7em; } .blog_widget_normal .archive h2 { position:relative; border-left:1px solid #ffffff; border-right:1px solid #ffffff; padding:7px 0 0 12px; height:21px; _height:20px; font-size:1em; color:#54564b; font-family:Tahoma;} .blog_widget_normal .archive .items { padding:.4em 1.2em .4em 1.2em; overflow:hidden;} -.blog_widget_normal .archive .items li { font-size:.75em; display:block; color:#a4a4a4; margin-right:.1em; line-height:1.5em; font-family:tahoma; } +.blog_widget_normal .archive .items li { font-size:.75em; display:block; color:#a4a4a4; margin-right:.1em; line-height:1.5em; font-family:tahoma; padding:3px 0 3px 0;} .blog_widget_normal .archive .items li a { color:#a4a4a4; font-weight:bold; margin-right:1em; font-family:tahoma;} diff --git a/widgets/archive_list/skins/blog_archive_list/css/purple.css b/widgets/archive_list/skins/blog_archive_list/css/purple.css index 66ce15e3c..b15ae2fb6 100644 --- a/widgets/archive_list/skins/blog_archive_list/css/purple.css +++ b/widgets/archive_list/skins/blog_archive_list/css/purple.css @@ -1,5 +1,5 @@ .blog_widget_purple .archive { position:relative; border:1px solid #e0e1db; background:url(../images/purple/bgBoxTypeB.gif) repeat-x left top; margin-bottom:.7em; } .blog_widget_purple .archive h2 { position:relative; border-left:1px solid #ffffff; border-right:1px solid #ffffff; padding:7px 0 0 12px; height:21px; _height:20px; font-size:1em; color:#54564b; font-family:Tahoma;} .blog_widget_purple .archive .items { padding:.4em 1.2em .4em 1.2em; overflow:hidden;} -.blog_widget_purple .archive .items li { font-size:.75em; display:block; color:#a4a4a4; margin-right:.1em; line-height:1.5em; font-family:tahoma; } +.blog_widget_purple .archive .items li { font-size:.75em; display:block; color:#a4a4a4; margin-right:.1em; line-height:1.5em; font-family:tahoma; padding:3px 0 3px 0;} .blog_widget_purple .archive .items li a { color:#a4a4a4; font-weight:bold; margin-right:1em; font-family:tahoma;} diff --git a/widgets/archive_list/skins/blog_archive_list/css/red.css b/widgets/archive_list/skins/blog_archive_list/css/red.css index 517f5a67b..3c93e6d30 100644 --- a/widgets/archive_list/skins/blog_archive_list/css/red.css +++ b/widgets/archive_list/skins/blog_archive_list/css/red.css @@ -1,5 +1,5 @@ .blog_widget_red .archive { position:relative; border:1px solid #e0e1db; background:url(../images/red/bgBoxTypeB.gif) repeat-x left top; margin-bottom:.7em; } .blog_widget_red .archive h2 { position:relative; border-left:1px solid #ffffff; border-right:1px solid #ffffff; padding:7px 0 0 12px; height:21px; _height:20px; font-size:1em; color:#54564b; font-family:Tahoma;} .blog_widget_red .archive .items { padding:.4em 1.2em .4em 1.2em; overflow:hidden;} -.blog_widget_red .archive .items li { font-size:.75em; display:block; color:#a4a4a4; margin-right:.1em; line-height:1.5em; font-family:tahoma; } +.blog_widget_red .archive .items li { font-size:.75em; display:block; color:#a4a4a4; margin-right:.1em; line-height:1.5em; font-family:tahoma; padding:3px 0 3px 0;} .blog_widget_red .archive .items li a { color:#a4a4a4; font-weight:bold; margin-right:1em; font-family:tahoma;} diff --git a/widgets/newest_comment/skins/blog_newest_comment/css/cyan.css b/widgets/newest_comment/skins/blog_newest_comment/css/cyan.css index de76199bd..d70671b17 100644 --- a/widgets/newest_comment/skins/blog_newest_comment/css/cyan.css +++ b/widgets/newest_comment/skins/blog_newest_comment/css/cyan.css @@ -1,5 +1,5 @@ .blog_widget_cyan .newest_comment { border:1px solid #e0e1db; background:url(../images/cyan/bgBoxTypeB.gif) repeat-x left top; margin-bottom:.7em; } .blog_widget_cyan .newest_comment h2 { border-left:1px solid #ffffff; border-right:1px solid #ffffff; padding:7px 0 0 12px; height:21px; _height:20px; font-size:1em; color:#54564b; } .blog_widget_cyan .newest_comment .items { padding:10px; overflow:hidden;} -.blog_widget_cyan .newest_comment .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%;} +.blog_widget_cyan .newest_comment .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%; padding:3px 0 3px 0;} .blog_widget_cyan .newest_comment .items li a { color:#a4a4a4; line-height:1.5em; text-decoration:none; } diff --git a/widgets/newest_comment/skins/blog_newest_comment/css/green.css b/widgets/newest_comment/skins/blog_newest_comment/css/green.css index 14369e067..49b59133b 100644 --- a/widgets/newest_comment/skins/blog_newest_comment/css/green.css +++ b/widgets/newest_comment/skins/blog_newest_comment/css/green.css @@ -1,5 +1,5 @@ .blog_widget_green .newest_comment { border:1px solid #e0e1db; background:url(../images/green/bgBoxTypeB.gif) repeat-x left top; margin-bottom:.7em; } .blog_widget_green .newest_comment h2 { border-left:1px solid #ffffff; border-right:1px solid #ffffff; padding:7px 0 0 12px; height:21px; _height:20px; font-size:1em; color:#54564b; } .blog_widget_green .newest_comment .items { padding:10px; overflow:hidden;} -.blog_widget_green .newest_comment .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%;} +.blog_widget_green .newest_comment .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%; padding:3px 0 3px 0;} .blog_widget_green .newest_comment .items li a { color:#a4a4a4; line-height:1.5em; text-decoration:none; } diff --git a/widgets/newest_comment/skins/blog_newest_comment/css/normal.css b/widgets/newest_comment/skins/blog_newest_comment/css/normal.css index 735840b5d..5883222f5 100644 --- a/widgets/newest_comment/skins/blog_newest_comment/css/normal.css +++ b/widgets/newest_comment/skins/blog_newest_comment/css/normal.css @@ -1,5 +1,5 @@ .blog_widget_normal .newest_comment { border:1px solid #e0e1db; background:url(../images/normal/bgBoxTypeB.gif) repeat-x left top; margin-bottom:.7em; } .blog_widget_normal .newest_comment h2 { border-left:1px solid #ffffff; border-right:1px solid #ffffff; padding:7px 0 0 12px; height:21px; _height:20px; font-size:1em; color:#54564b; } .blog_widget_normal .newest_comment .items { padding:10px; overflow:hidden;} -.blog_widget_normal .newest_comment .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%;} +.blog_widget_normal .newest_comment .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%; padding:3px 0 3px 0;} .blog_widget_normal .newest_comment .items li a { color:#a4a4a4; line-height:1.5em; text-decoration:none; text-decoration:none; } diff --git a/widgets/newest_comment/skins/blog_newest_comment/css/purple.css b/widgets/newest_comment/skins/blog_newest_comment/css/purple.css index 56868477e..6acf820d3 100644 --- a/widgets/newest_comment/skins/blog_newest_comment/css/purple.css +++ b/widgets/newest_comment/skins/blog_newest_comment/css/purple.css @@ -1,5 +1,5 @@ .blog_widget_purple .newest_comment { border:1px solid #e0e1db; background:url(../images/purple/bgBoxTypeB.gif) repeat-x left top; margin-bottom:.7em; } .blog_widget_purple .newest_comment h2 { border-left:1px solid #ffffff; border-right:1px solid #ffffff; padding:7px 0 0 12px; height:21px; _height:20px; font-size:1em; color:#54564b; } .blog_widget_purple .newest_comment .items { padding:10px; overflow:hidden;} -.blog_widget_purple .newest_comment .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%;} +.blog_widget_purple .newest_comment .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%; padding:3px 0 3px 0;} .blog_widget_purple .newest_comment .items li a { color:#a4a4a4; line-height:1.5em; text-decoration:none; } diff --git a/widgets/newest_comment/skins/blog_newest_comment/css/red.css b/widgets/newest_comment/skins/blog_newest_comment/css/red.css index c439a0626..39bebe2b7 100644 --- a/widgets/newest_comment/skins/blog_newest_comment/css/red.css +++ b/widgets/newest_comment/skins/blog_newest_comment/css/red.css @@ -1,5 +1,5 @@ .blog_widget_red .newest_comment { border:1px solid #e0e1db; background:url(../images/red/bgBoxTypeB.gif) repeat-x left top; margin-bottom:.7em; } .blog_widget_red .newest_comment h2 { border-left:1px solid #ffffff; border-right:1px solid #ffffff; padding:7px 0 0 12px; height:21px; _height:20px; font-size:1em; color:#54564b; } .blog_widget_red .newest_comment .items { padding:10px; overflow:hidden;} -.blog_widget_red .newest_comment .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%;} +.blog_widget_red .newest_comment .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%; padding:3px 0 3px 0;} .blog_widget_red .newest_comment .items li a { color:#a4a4a4; line-height:1.5em; text-decoration:none; } diff --git a/widgets/newest_document/skins/blog_newest_document/css/cyan.css b/widgets/newest_document/skins/blog_newest_document/css/cyan.css index f41271320..6de34c94b 100644 --- a/widgets/newest_document/skins/blog_newest_document/css/cyan.css +++ b/widgets/newest_document/skins/blog_newest_document/css/cyan.css @@ -1,5 +1,5 @@ .blog_widget_cyan .newest_document { border:1px solid #e0e1db; background:url(../images/cyan/bgBoxTypeB.gif) repeat-x left top; margin-bottom:.7em; } .blog_widget_cyan .newest_document h2 { border-left:1px solid #ffffff; border-right:1px solid #ffffff; padding:7px 0 0 12px; height:21px; _height:20px; font-size:1em; color:#54564b; } .blog_widget_cyan .newest_document .items { padding:10px; overflow:hidden;} -.blog_widget_cyan .newest_document .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%;} +.blog_widget_cyan .newest_document .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%; padding:3px 0 3px 0;} .blog_widget_cyan .newest_document .items li a { color:#a4a4a4; line-height:1.5em; text-decoration:none; } diff --git a/widgets/newest_document/skins/blog_newest_document/css/green.css b/widgets/newest_document/skins/blog_newest_document/css/green.css index 90dd6476e..7bf0dbebc 100644 --- a/widgets/newest_document/skins/blog_newest_document/css/green.css +++ b/widgets/newest_document/skins/blog_newest_document/css/green.css @@ -1,5 +1,5 @@ .blog_widget_green .newest_document { border:1px solid #e0e1db; background:url(../images/green/bgBoxTypeB.gif) repeat-x left top; margin-bottom:.7em; } .blog_widget_green .newest_document h2 { border-left:1px solid #ffffff; border-right:1px solid #ffffff; padding:7px 0 0 12px; height:21px; _height:20px; font-size:1em; color:#54564b; } .blog_widget_green .newest_document .items { padding:10px; overflow:hidden;} -.blog_widget_green .newest_document .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%;} +.blog_widget_green .newest_document .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%; padding:3px 0 3px 0;} .blog_widget_green .newest_document .items li a { color:#a4a4a4; line-height:1.5em; text-decoration:none; } diff --git a/widgets/newest_document/skins/blog_newest_document/css/normal.css b/widgets/newest_document/skins/blog_newest_document/css/normal.css index d70d6dbf1..870107d28 100644 --- a/widgets/newest_document/skins/blog_newest_document/css/normal.css +++ b/widgets/newest_document/skins/blog_newest_document/css/normal.css @@ -1,5 +1,5 @@ .blog_widget_normal .newest_document { border:1px solid #e0e1db; background:url(../images/normal/bgBoxTypeB.gif) repeat-x left top; margin-bottom:.7em; } .blog_widget_normal .newest_document h2 { border-left:1px solid #ffffff; border-right:1px solid #ffffff; padding:7px 0 0 12px; height:21px; _height:20px; font-size:1em; color:#54564b; } .blog_widget_normal .newest_document .items { padding:10px; overflow:hidden;} -.blog_widget_normal .newest_document .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%;} +.blog_widget_normal .newest_document .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%; padding:3px 0 3px 0;} .blog_widget_normal .newest_document .items li a { color:#a4a4a4; line-height:1.5em; text-decoration:none; text-decoration:none; } diff --git a/widgets/newest_document/skins/blog_newest_document/css/purple.css b/widgets/newest_document/skins/blog_newest_document/css/purple.css index 75c4af686..f3550a339 100644 --- a/widgets/newest_document/skins/blog_newest_document/css/purple.css +++ b/widgets/newest_document/skins/blog_newest_document/css/purple.css @@ -1,5 +1,5 @@ .blog_widget_purple .newest_document { border:1px solid #e0e1db; background:url(../images/purple/bgBoxTypeB.gif) repeat-x left top; margin-bottom:.7em; } .blog_widget_purple .newest_document h2 { border-left:1px solid #ffffff; border-right:1px solid #ffffff; padding:7px 0 0 12px; height:21px; _height:20px; font-size:1em; color:#54564b; } .blog_widget_purple .newest_document .items { padding:10px; overflow:hidden;} -.blog_widget_purple .newest_document .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%;} +.blog_widget_purple .newest_document .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%; padding:3px 0 3px 0;} .blog_widget_purple .newest_document .items li a { color:#a4a4a4; line-height:1.5em; text-decoration:none; } diff --git a/widgets/newest_document/skins/blog_newest_document/css/red.css b/widgets/newest_document/skins/blog_newest_document/css/red.css index bb8084fdc..154cbc636 100644 --- a/widgets/newest_document/skins/blog_newest_document/css/red.css +++ b/widgets/newest_document/skins/blog_newest_document/css/red.css @@ -1,5 +1,5 @@ .blog_widget_red .newest_document { border:1px solid #e0e1db; background:url(../images/red/bgBoxTypeB.gif) repeat-x left top; margin-bottom:.7em; } .blog_widget_red .newest_document h2 { border-left:1px solid #ffffff; border-right:1px solid #ffffff; padding:7px 0 0 12px; height:21px; _height:20px; font-size:1em; color:#54564b; } .blog_widget_red .newest_document .items { padding:10px; overflow:hidden;} -.blog_widget_red .newest_document .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%;} +.blog_widget_red .newest_document .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%; padding:3px 0 3px 0;} .blog_widget_red .newest_document .items li a { color:#a4a4a4; line-height:1.5em; text-decoration:none; } diff --git a/widgets/newest_trackback/skins/blog_newest_trackback/css/cyan.css b/widgets/newest_trackback/skins/blog_newest_trackback/css/cyan.css index 5f94930cb..c2ab6f163 100644 --- a/widgets/newest_trackback/skins/blog_newest_trackback/css/cyan.css +++ b/widgets/newest_trackback/skins/blog_newest_trackback/css/cyan.css @@ -1,5 +1,5 @@ .blog_widget_cyan .newest_trackback { border:1px solid #e0e1db; background:url(../images/cyan/bgBoxTypeB.gif) repeat-x left top; margin-bottom:.7em; } .blog_widget_cyan .newest_trackback h2 { border-left:1px solid #ffffff; border-right:1px solid #ffffff; padding:7px 0 0 12px; height:21px; _height:20px; font-size:1em; color:#54564b; } .blog_widget_cyan .newest_trackback .items { padding:10px; overflow:hidden;} -.blog_widget_cyan .newest_trackback .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%;} +.blog_widget_cyan .newest_trackback .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%; padding:3px 0 3px 0;} .blog_widget_cyan .newest_trackback .items li a { color:#a4a4a4; line-height:1.5em; text-decoration:none; } diff --git a/widgets/newest_trackback/skins/blog_newest_trackback/css/green.css b/widgets/newest_trackback/skins/blog_newest_trackback/css/green.css index 4b3367c7b..ee21c6ba8 100644 --- a/widgets/newest_trackback/skins/blog_newest_trackback/css/green.css +++ b/widgets/newest_trackback/skins/blog_newest_trackback/css/green.css @@ -1,5 +1,5 @@ .blog_widget_green .newest_trackback { border:1px solid #e0e1db; background:url(../images/green/bgBoxTypeB.gif) repeat-x left top; margin-bottom:.7em; } .blog_widget_green .newest_trackback h2 { border-left:1px solid #ffffff; border-right:1px solid #ffffff; padding:7px 0 0 12px; height:21px; _height:20px; font-size:1em; color:#54564b; } .blog_widget_green .newest_trackback .items { padding:10px; overflow:hidden;} -.blog_widget_green .newest_trackback .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%;} +.blog_widget_green .newest_trackback .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%; padding:3px 0 3px 0;} .blog_widget_green .newest_trackback .items li a { color:#a4a4a4; line-height:1.5em; text-decoration:none; } diff --git a/widgets/newest_trackback/skins/blog_newest_trackback/css/normal.css b/widgets/newest_trackback/skins/blog_newest_trackback/css/normal.css index 980712b2f..425be87ff 100644 --- a/widgets/newest_trackback/skins/blog_newest_trackback/css/normal.css +++ b/widgets/newest_trackback/skins/blog_newest_trackback/css/normal.css @@ -1,5 +1,5 @@ .blog_widget_normal .newest_trackback { border:1px solid #e0e1db; background:url(../images/normal/bgBoxTypeB.gif) repeat-x left top; margin-bottom:.7em; } .blog_widget_normal .newest_trackback h2 { border-left:1px solid #ffffff; border-right:1px solid #ffffff; padding:7px 0 0 12px; height:21px; _height:20px; font-size:1em; color:#54564b; } .blog_widget_normal .newest_trackback .items { padding:10px; overflow:hidden;} -.blog_widget_normal .newest_trackback .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%;} +.blog_widget_normal .newest_trackback .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%; padding:3px 0 3px 0;} .blog_widget_normal .newest_trackback .items li a { color:#a4a4a4; line-height:1.5em; text-decoration:none; text-decoration:none; } diff --git a/widgets/newest_trackback/skins/blog_newest_trackback/css/purple.css b/widgets/newest_trackback/skins/blog_newest_trackback/css/purple.css index 3976d6be6..3360e7e00 100644 --- a/widgets/newest_trackback/skins/blog_newest_trackback/css/purple.css +++ b/widgets/newest_trackback/skins/blog_newest_trackback/css/purple.css @@ -1,5 +1,5 @@ .blog_widget_purple .newest_trackback { border:1px solid #e0e1db; background:url(../images/purple/bgBoxTypeB.gif) repeat-x left top; margin-bottom:.7em; } .blog_widget_purple .newest_trackback h2 { border-left:1px solid #ffffff; border-right:1px solid #ffffff; padding:7px 0 0 12px; height:21px; _height:20px; font-size:1em; color:#54564b; } .blog_widget_purple .newest_trackback .items { padding:10px; overflow:hidden;} -.blog_widget_purple .newest_trackback .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%;} +.blog_widget_purple .newest_trackback .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%; padding:3px 0 3px 0;} .blog_widget_purple .newest_trackback .items li a { color:#a4a4a4; line-height:1.5em; text-decoration:none; } diff --git a/widgets/newest_trackback/skins/blog_newest_trackback/css/red.css b/widgets/newest_trackback/skins/blog_newest_trackback/css/red.css index 253d4f315..4966e2300 100644 --- a/widgets/newest_trackback/skins/blog_newest_trackback/css/red.css +++ b/widgets/newest_trackback/skins/blog_newest_trackback/css/red.css @@ -1,5 +1,5 @@ .blog_widget_red .newest_trackback { border:1px solid #e0e1db; background:url(../images/red/bgBoxTypeB.gif) repeat-x left top; margin-bottom:.7em; } .blog_widget_red .newest_trackback h2 { border-left:1px solid #ffffff; border-right:1px solid #ffffff; padding:7px 0 0 12px; height:21px; _height:20px; font-size:1em; color:#54564b; } .blog_widget_red .newest_trackback .items { padding:10px; overflow:hidden;} -.blog_widget_red .newest_trackback .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%;} +.blog_widget_red .newest_trackback .items li { font-size:.9em; display:block; color:#a4a4a4; margin-right:.1em; overflow:hidden; white-space:nowrap; list-style:none; width:100%; padding:3px 0 3px 0;} .blog_widget_red .newest_trackback .items li a { color:#a4a4a4; line-height:1.5em; text-decoration:none; } From ed1122447689e9a2812ff305710679e028e2a6f8 Mon Sep 17 00:00:00 2001 From: zero Date: Wed, 5 Dec 2007 07:17:45 +0000 Subject: [PATCH 134/265] fix blog module using dispBoardMessage to dispBlogMessage git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3158 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/blog/blog.view.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/blog/blog.view.php b/modules/blog/blog.view.php index 8b1326af8..79df829a9 100644 --- a/modules/blog/blog.view.php +++ b/modules/blog/blog.view.php @@ -266,7 +266,7 @@ $oSourceComment = $oCommentModel->getComment($parent_srl, $this->grant->manager); // 댓글이 없다면 오류 - if(!$oSourceComment->isExists()) return $this->dispBoardMessage('msg_invalid_request'); + if(!$oSourceComment->isExists()) return $this->dispBlogMessage('msg_invalid_request'); // 대상 댓글을 생성 $oComment = $oCommentModel->getComment(); @@ -302,7 +302,7 @@ $oComment = $oCommentModel->getComment($comment_srl, $this->grant->manager); // 댓글이 없다면 오류 - if(!$oComment->isExists()) return $this->dispBoardMessage('msg_invalid_request'); + if(!$oComment->isExists()) return $this->dispBlogMessage('msg_invalid_request'); // 글을 수정하려고 할 경우 권한이 없는 경우 비밀번호 입력화면으로 if(!$oComment->isGranted()) return $this->setTemplateFile('input_password_form'); From 2f0d39d05228744c264889ae79d0a261cb129aa0 Mon Sep 17 00:00:00 2001 From: haneul Date: Thu, 6 Dec 2007 01:48:00 +0000 Subject: [PATCH 135/265] remove editings of xquared main source for setting imageToolbar path git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3159 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/editor/skins/xquared/js/xe_interface.js | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/editor/skins/xquared/js/xe_interface.js b/modules/editor/skins/xquared/js/xe_interface.js index ca9f04d6c..47bd8b972 100644 --- a/modules/editor/skins/xquared/js/xe_interface.js +++ b/modules/editor/skins/xquared/js/xe_interface.js @@ -30,6 +30,7 @@ function editorGetContent_xq(editor_sequence) { function editorStart_xq(editor, element, editor_sequence, content_key, editor_height, primary_key) { editor = new xq.Editor(element); + editor.config.imagePathForDefaultToolbar = request_uri+editor_path.substring(1)+'examples/img/toolbar/'; editor.config.allowedAttributes.push('editor_component', 'poll_srl','multimedia_src', 'auto_start', 'link_url', 'editor_sequence', 'use_folder', 'folder_opener', 'folder_closer', 'color', 'border_thickness', 'border_color', 'bg_color', 'border_style', 'margin', 'padding', 'bold', 'nx', 'ny', 'gx', 'gy', 'address', 'reg_sinpic', 'language','align'); editor.config.allowedTags.push('embed', 'param', 'object'); From b5a09b8fe1956fd3ba4ac8e32b5a86c1b5ad4d9b Mon Sep 17 00:00:00 2001 From: haneul Date: Thu, 6 Dec 2007 02:35:24 +0000 Subject: [PATCH 136/265] upgrade xquared to v20071205, remove prototype.js, remove prototype dependencies in editor.html, fix bugs in xquared.js, xquared-min.js, replace xquared.js into xquared-min.js in editor.html git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3160 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/editor/skins/xquared/editor.html | 7 +- .../skins/xquared/examples/default.html | 3 +- .../xquared/examples/extensionpoint.html | 10 +- .../xquared/examples/form_and_textarea.html | 3 +- .../xquared/examples/toolbar_customized1.html | 3 +- .../xquared/examples/toolbar_customized2.html | 3 +- .../xquared/examples/toolbar_disabled.html | 3 +- modules/editor/skins/xquared/js/prototype.js | 4184 ----------------- .../editor/skins/xquared/js/xe_interface.js | 5 +- .../editor/skins/xquared/js/xquared-min.js | 803 ++-- modules/editor/skins/xquared/js/xquared.js | 887 ++-- 11 files changed, 1127 insertions(+), 4784 deletions(-) delete mode 100644 modules/editor/skins/xquared/js/prototype.js diff --git a/modules/editor/skins/xquared/editor.html b/modules/editor/skins/xquared/editor.html index b2fc7718b..833d7d85a 100644 --- a/modules/editor/skins/xquared/editor.html +++ b/modules/editor/skins/xquared/editor.html @@ -7,8 +7,7 @@ - - + @@ -16,8 +15,8 @@ var auto_saved_msg = "{$lang->msg_auto_saved}"; var xed_{$editor_sequence}; xAddEventListener(window, 'load', function() { - if($("comment_{$editor_sequence}") == null || $("comment_{$editor_sequence}").style.display != 'none'){ - editorStart_xq(xed_{$editor_sequence}, $("xqEditor_{$editor_sequence}"), {$editor_sequence}, "{$editor_content_key_name}", "{$editor_height}px", "{$editor_primary_key_name}"); + if(document.getElementById("comment_{$editor_sequence}") == null || document.getElementById("comment_{$editor_sequence}").style.display != 'none'){ + editorStart_xq(xed_{$editor_sequence}, document.getElementById("xqEditor_{$editor_sequence}"), {$editor_sequence}, "{$editor_content_key_name}", "{$editor_height}px", "{$editor_primary_key_name}"); }}); //]]> diff --git a/modules/editor/skins/xquared/examples/default.html b/modules/editor/skins/xquared/examples/default.html index b91d29415..29debfdc1 100644 --- a/modules/editor/skins/xquared/examples/default.html +++ b/modules/editor/skins/xquared/examples/default.html @@ -4,13 +4,12 @@ Xquared example - Default - ") }; xq.loadOthers=function(){var A=xq.findXquaredScript(); -var C=A.src.match(/(.*\/)xquared\.js.*/i)[1]; -var B=["Editor.js","Browser.js","Shortcut.js","DomTree.js","RichDom.js","RichDomW3.js","RichDomGecko.js","RichDomWebkit.js","RichDomTrident.js","RichTable.js","Validator.js","ValidatorW3.js","ValidatorGecko.js","ValidatorWebkit.js","ValidatorTrident.js","EditHistory.js","Controls.js","_ui_templates.js"]; -B.each(function(D){xq.loadScript(C+D) -}) -}; +var D=A.src.match(/(.*\/)xquared\.js.*/i)[1]; +var C=["Editor.js","Browser.js","Shortcut.js","DomTree.js","RichDom.js","RichDomW3.js","RichDomGecko.js","RichDomWebkit.js","RichDomTrident.js","RichTable.js","Validator.js","ValidatorW3.js","ValidatorGecko.js","ValidatorWebkit.js","ValidatorTrident.js","EditHistory.js","Controls.js","_ui_templates.js"]; +for(var B=0; +B0?G[0]:null; -if(E){this.toolbarButtons.set(F,E) -}}.bind(this)) -}var B=this.toolbarButtons; -var C=this.rdom.collectStructureAndStyle(A); -this._updateToolbarButtonStatus("emphasis",C.em); -this._updateToolbarButtonStatus("strongEmphasis",C.strong); -this._updateToolbarButtonStatus("underline",C.underline); -this._updateToolbarButtonStatus("strike",C.strike); -this._updateToolbarButtonStatus("superscription",C.superscription); -this._updateToolbarButtonStatus("subscription",C.subscription); -this._updateToolbarButtonStatus("justifyLeft",C.justification=="left"); -this._updateToolbarButtonStatus("justifyCenter",C.justification=="center"); -this._updateToolbarButtonStatus("justifyRight",C.justification=="right"); -this._updateToolbarButtonStatus("justifyBoth",C.justification=="justify"); -this._updateToolbarButtonStatus("orderedList",C.list=="OL"); -this._updateToolbarButtonStatus("unorderedList",C.list=="UL"); -this._updateToolbarButtonStatus("code",C.list=="CODE"); -this._updateToolbarButtonStatus("paragraph",C.block=="P"); -this._updateToolbarButtonStatus("heading1",C.block=="H1"); -this._updateToolbarButtonStatus("heading2",C.block=="H2"); -this._updateToolbarButtonStatus("heading3",C.block=="H3"); -this._updateToolbarButtonStatus("heading4",C.block=="H4"); -this._updateToolbarButtonStatus("heading5",C.block=="H5"); -this._updateToolbarButtonStatus("heading6",C.block=="H6") +}},updateAllToolbarButtonsStatus:function(C){if(!this.toolbarContainer){return +}if(!this.toolbarButtons){var G=["emphasis","strongEmphasis","underline","strike","superscription","subscription","justifyLeft","justifyCenter","justifyRight","justifyBoth","unorderedList","orderedList","code","paragraph","heading1","heading2","heading3","heading4","heading5","heading6"]; +this.toolbarButtons={}; +for(var B=0; +B0?E[0]:null; +if(A){this.toolbarButtons[G[B]]=A +}}}var D=this.toolbarButtons; +var F=this.rdom.collectStructureAndStyle(C); +this._updateToolbarButtonStatus("emphasis",F.em); +this._updateToolbarButtonStatus("strongEmphasis",F.strong); +this._updateToolbarButtonStatus("underline",F.underline); +this._updateToolbarButtonStatus("strike",F.strike); +this._updateToolbarButtonStatus("superscription",F.superscription); +this._updateToolbarButtonStatus("subscription",F.subscription); +this._updateToolbarButtonStatus("justifyLeft",F.justification=="left"); +this._updateToolbarButtonStatus("justifyCenter",F.justification=="center"); +this._updateToolbarButtonStatus("justifyRight",F.justification=="right"); +this._updateToolbarButtonStatus("justifyBoth",F.justification=="justify"); +this._updateToolbarButtonStatus("orderedList",F.list=="OL"); +this._updateToolbarButtonStatus("unorderedList",F.list=="UL"); +this._updateToolbarButtonStatus("code",F.list=="CODE"); +this._updateToolbarButtonStatus("paragraph",F.block=="P"); +this._updateToolbarButtonStatus("heading1",F.block=="H1"); +this._updateToolbarButtonStatus("heading2",F.block=="H2"); +this._updateToolbarButtonStatus("heading3",F.block=="H3"); +this._updateToolbarButtonStatus("heading4",F.block=="H4"); +this._updateToolbarButtonStatus("heading5",F.block=="H5"); +this._updateToolbarButtonStatus("heading6",F.block=="H6") },removeUnnecessarySpaces:function(A){var C=this.rdom.tree.getBlockTags().join("|"); var B=new RegExp("\\s*<(/?)("+C+")>\\s*","img"); return A.replace(B,"<$1$2>") @@ -331,6 +499,7 @@ this.editorBody=this.editorDoc.body; this.editorBody.className="xed"; if(xq.Browser.isIE6){this.editorDoc.documentElement.style.overflowY="auto"; this.editorDoc.documentElement.style.overflowX="hidden" +}if(this.config.generateDefaultToolbar){this._addStyleRules([{selector:".xquared div.toolbar",rule:"background-image: url("+this.config.imagePathForDefaultToobar+"toolbarBg.gif)"},{selector:".xquared ul.buttons li",rule:"background-image: url("+this.config.imagePathForDefaultToobar+"toolbarButtonBg.gif)"},{selector:".xquared ul.buttons li.xq_separator",rule:"background-image: url("+this.config.imagePathForDefaultToobar+"toolbarSeparator.gif)"}]) }this.rdom.setWin(this.editorWin); this.rdom.setRoot(this.editorBody); this.validator=xq.Validator.createInstance(this.doc.location.href,this.config.urlValidationMode,this.config.allowedTags,this.config.allowedAttributes); @@ -339,67 +508,68 @@ this.contentElement.form.onsubmit=function(){this.contentElement.value=this.getC if(A){return A() }else{return true }}.bind(this) -}},_addStyleRule:function(A,C){if(!this.dynamicStyle){if(xq.Browser.isTrident){this.dynamicStyle=this.doc.createStyleSheet() +}},_addStyleRules:function(D){if(!this.dynamicStyle){if(xq.Browser.isTrident){this.dynamicStyle=this.doc.createStyleSheet() }else{var B=this.doc.createElement("style"); this.doc.body.appendChild(B); -this.dynamicStyle=$A(this.doc.styleSheets).last() -}}if(xq.Browser.isTrident){this.dynamicStyle.addRule(A,C) -}else{this.dynamicStyle.insertRule(A+" {"+C+"}",this.dynamicStyle.cssRules.length) -}},_generateDefaultToolbar:function(){this._addStyleRule(".xquared div.toolbar","background-image: url("+this.config.imagePathForDefaultToobar+"toolbarBg.gif)"); -this._addStyleRule(".xquared ul.buttons li","background-image: url("+this.config.imagePathForDefaultToobar+"toolbarButtonBg.gif)"); -this._addStyleRule(".xquared ul.buttons li.xq_separator","background-image: url("+this.config.imagePathForDefaultToobar+"toolbarSeparator.gif)"); -var container=this.doc.createElement("div"); -container.className="toolbar"; -var buttons=this.doc.createElement("ul"); -buttons.className="buttons"; -container.appendChild(buttons); -var cancelMousedown=function(e){Event.stop(e); +this.dynamicStyle=xq.$A(this.doc.styleSheets).last() +}}for(var A=0; +A0){this._contextMenuContainer.removeChild(this._contextMenuContainer.childNodes[0]) }}for(var B=0; @@ -810,8 +993,9 @@ A.className="separator" return A },_contextMenuClicked:function(e){this.hideContextMenu(); if(!this._contextMenuContainer){return -}var node=Event.findElement(e,"LI"); -if(!node||!this.rdom.tree.isDescendantOf(this._contextMenuContainer,node)){return +}var node=e.srcElement||e.target; +while(node&&node.nodeName!="LI"){node=node.parentNode +}if(!node||!this.rdom.tree.isDescendantOf(this._contextMenuContainer,node)){return }for(var i=0; i-1,isGecko:navigator.userAgent.indexOf("Gecko")>-1&&navigator.userAgent.indexOf("KHTML")==-1,isKHTML:navigator.userAgent.indexOf("KHTML")!=-1,isPresto:navigator.appName=="Opera",isMac:navigator.userAgent.indexOf("Macintosh")!=-1,isUbuntu:navigator.userAgent.indexOf("Ubuntu")!=-1,isIE:navigator.appName=="Microsoft Internet Explorer",isIE6:navigator.userAgent.indexOf("MSIE 6")!=-1,isIE7:navigator.userAgent.indexOf("MSIE 7")!=-1}; -xq.Shortcut=Class.create({initialize:function(A){this.keymap=(typeof A=="string")?xq.Shortcut.interprete(A).keymap:A +xq.Shortcut=xq.Class({initialize:function(A){xq.addToFinalizeQueue(this); +this.keymap=(typeof A=="string")?xq.Shortcut.interprete(A).keymap:A },matches:function(A){var B=xq.Browser.isGecko&&xq.Browser.isMac?(A.keyCode+"_"+A.charCode):A.keyCode; var D=(this.keymap.which==B)||(this.keymap.which==32&&B==25); if(typeof A.metaKey=="undefined"){A.metaKey=false @@ -870,7 +1054,8 @@ if(typeof B=="undefined"){throw"Unknown special key name: ["+A+"]" }return B }; xq.Shortcut._keyNames=xq.Browser.isMac&&xq.Browser.isGecko?{BACKSPACE:"8_0",TAB:"9_0",RETURN:"13_0",ENTER:"13_0",ESC:"27_0",SPACE:"0_32",LEFT:"37_0",UP:"38_0",RIGHT:"39_0",DOWN:"40_0",DELETE:"46_0",HOME:"36_0",END:"35_0",PAGEUP:"33_0",PAGEDOWN:"34_0",COMMA:"0_44",HYPHEN:"0_45",EQUAL:"0_61",PERIOD:"0_46",SLASH:"0_47",F1:"112_0",F2:"113_0",F3:"114_0",F4:"115_0",F5:"116_0",F6:"117_0",F7:"118_0",F8:"119_0"}:{BACKSPACE:8,TAB:9,RETURN:13,ENTER:13,ESC:27,SPACE:32,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46,HOME:36,END:35,PAGEUP:33,PAGEDOWN:34,COMMA:188,HYPHEN:xq.Browser.isTrident?189:109,EQUAL:xq.Browser.isTrident?187:61,PERIOD:190,SLASH:191,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123}; -xq.DomTree=Class.create({initialize:function(){this._blockTags=["DIV","DD","LI","ADDRESS","CAPTION","DT","H1","H2","H3","H4","H5","H6","HR","P","BODY","BLOCKQUOTE","PRE","PARAM","DL","OL","UL","TABLE","THEAD","TBODY","TR","TH","TD"]; +xq.DomTree=xq.Class({initialize:function(){xq.addToFinalizeQueue(this); +this._blockTags=["DIV","DD","LI","ADDRESS","CAPTION","DT","H1","H2","H3","H4","H5","H6","HR","P","BODY","BLOCKQUOTE","PRE","PARAM","DL","OL","UL","TABLE","THEAD","TBODY","TR","TH","TD"]; this._blockContainerTags=["DIV","DD","LI","BODY","BLOCKQUOTE","UL","OL","DL","TABLE","THEAD","TBODY","TR","TH","TD"]; this._listContainerTags=["OL","UL","DL"]; this._tableCellTags=["TH","TD"]; @@ -969,22 +1154,23 @@ if(!A&&this.isTextOrInlineNode(D)){A=true }}if(!A||!E){return false }return true },isBlockOnlyContainer:function(A){if(!A){return false -}return this._blockOnlyContainerTags.include(typeof A=="string"?A:A.nodeName) +}return this._blockOnlyContainerTags.indexOf(typeof A=="string"?A:A.nodeName)!=-1 },isTableCell:function(A){if(!A){return false -}return this._tableCellTags.include(typeof A=="string"?A:A.nodeName) +}return this._tableCellTags.indexOf(typeof A=="string"?A:A.nodeName)!=-1 },isBlockContainer:function(A){if(!A){return false -}return this._blockContainerTags.include(typeof A=="string"?A:A.nodeName) +}return this._blockContainerTags.indexOf(typeof A=="string"?A:A.nodeName)!=-1 },isHeading:function(A){if(!A){return false }return(typeof A=="string"?A:A.nodeName).match(/H\d/) },isBlock:function(A){if(!A){return false -}return this._blockTags.include(typeof A=="string"?A:A.nodeName) +}return this._blockTags.indexOf(typeof A=="string"?A:A.nodeName)!=-1 },isAtomic:function(A){if(!A){return false -}return this._atomicTags.include(typeof A=="string"?A:A.nodeName) +}return this._atomicTags.indexOf(typeof A=="string"?A:A.nodeName)!=-1 },isListContainer:function(A){if(!A){return false -}return this._listContainerTags.include(typeof A=="string"?A:A.nodeName) +}return this._listContainerTags.indexOf(typeof A=="string"?A:A.nodeName)!=-1 },isTextOrInlineNode:function(A){return A&&(A.nodeType==3||!this.isBlock(A)) }}); -xq.RichDom=Class.create({initialize:function(){this.tree=new xq.DomTree(); +xq.RichDom=xq.Class({initialize:function(){xq.addToFinalizeQueue(this); +this.tree=new xq.DomTree(); this._lastMarkerId=0 },setWin:function(A){if(!A){throw"[win] is null" }this.win=A @@ -1007,7 +1193,7 @@ while(true){if(!D||D==A){break D=this.tree.walkForward(D); this.deleteNode(B) }else{D=this.tree.walkForward(D) -}}},setAttributes:function(A,B){for(key in B){A.setAttribute(key,B[key]) +}}},setAttributes:function(B,C){for(var A in C){B.setAttribute(A,C[A]) }},createTextNode:function(A){return this.doc.createTextNode(A) },createElement:function(A){return this.doc.createElement(A) },createElementFromHtml:function(A){var B=this.createElement("div"); @@ -1026,7 +1212,7 @@ this.correctEmptyElement(B) }},insertNode:function(A){throw"Not implemented" },insertHtml:function(A){return this.insertNode(this.createElementFromHtml(A)) },insertText:function(A){this.insertNode(this.createTextNode(A)) -},insertNodeAt:function(B,F,E,D){if(["HTML","HEAD"].include(F.nodeName)||["BODY"].include(F.nodeName)&&["before","after"].include(E)){throw"Illegal argument. Cannot move node["+B.nodeName+"] to '"+E+"' of target["+F.nodeName+"]" +},insertNodeAt:function(B,F,E,D){if(["HTML","HEAD"].indexOf(F.nodeName)!=-1||"BODY"==F.nodeName&&["before","after"].indexOf(E)!=-1){throw"Illegal argument. Cannot move node["+B.nodeName+"] to '"+E+"' of target["+F.nodeName+"]" }var C; var I; var G; @@ -1096,8 +1282,11 @@ return E },function(T){return T.nodeType==3 }); var M=0; -var Q=B.pluck("nodeValue"); -var P=Q.join(""); +var Q=[]; +for(var L=0; +L" @@ -1889,7 +2074,7 @@ if(C){return true }}catch(A){}if(C){this.rng().selectNode(B) }else{this.rng().selectNodeContents(B) }}}); -xq.RichDomWebkit=Class.create(xq.RichDomW3,{makePlaceHolder:function(){var A=this.createElement("BR"); +xq.RichDomWebkit=xq.Class(xq.RichDomW3,{makePlaceHolder:function(){var A=this.createElement("BR"); A.className="webkit-block-placeholder"; return A },makePlaceHolderString:function(){return"
      " @@ -1927,7 +2112,7 @@ this._anchorOffset=B.anchorOffset; this._focusNode=B.focusNode; this._focusOffset=B.focusOffset }}); -xq.RichDomTrident=Class.create(xq.RichDom,{makePlaceHolder:function(){return this.createTextNode(" ") +xq.RichDomTrident=xq.Class(xq.RichDom,{makePlaceHolder:function(){return this.createTextNode(" ") },makePlaceHolderString:function(){return" " },makeEmptyParagraph:function(){return this.createElementFromHtml("

       

      ") },isPlaceHolder:function(A){return false @@ -1943,7 +2128,7 @@ return B }if(this.isEmptyBlock(E)){return }var D=E.innerText; var B=D.charCodeAt(D.length-1); -if(D.length<=1||![32,160].include(B)){return +if(D.length<=1||[32,160].indexOf(B)==-1){return }var C=E; while(C&&C.nodeType!=3){C=C.lastChild }if(!C){return @@ -1970,6 +2155,7 @@ this.placeCaretAtStartOf(C) }.bind(this)); if(C){this.deleteNode(D); this.placeCaretAtStartOf(C) +}else{this.placeCaretAtStartOf(D) }return true }}else{D=this.getCurrentBlockElement(); if(D.nodeType==3){D=D.parentNode @@ -2028,10 +2214,10 @@ return A&&A.text?A.text:"" },hasImportantAttributes:function(A){return !!(A.id||A.className||A.style.cssText) },isEmptyBlock:function(A){if(!A.hasChildNodes()){return true }if(A.nodeType==3&&!A.nodeValue){return true -}if([" "," ",""].include(A.innerHTML)){return true +}if([" "," ",""].indexOf(A.innerHTML)!=-1){return true }return false },getLastChild:function(C){if(!C||!C.hasChildNodes()){return null -}var A=$A(C.childNodes).reverse(); +}var A=xq.$A(C.childNodes).reverse(); for(var B=0; BA)?B[A]:null }},getDom:function(){return this.table },hasHeadingAtTop:function(){return !!(this.table.tHead&&this.table.tHead.rows[0]) },hasHeadingAtLeft:function(){return this.table.tBodies[0].rows[0].cells[0].nodeName=="TH" -},correctEmptyCells:function(){var A=$A(this.table.getElementsByTagName("TH")); -A.push($A(this.table.getElementsByTagName("TD"))); -A=A.flatten(); +},correctEmptyCells:function(){var A=xq.$A(this.table.getElementsByTagName("TH")); +var C=xq.$A(this.table.getElementsByTagName("TD")); for(var B=0; +B"); if(I){F.push("
      "); @@ -2192,7 +2381,8 @@ var H=new xq.RichTable(E,A.firstChild); H.correctEmptyCells(); return H }; -xq.Validator=Class.create({initialize:function(C,A,D,B){this.allowedTags=(D||["a","abbr","acronym","address","blockquote","br","caption","cite","code","dd","dfn","div","dl","dt","em","h1","h2","h3","h4","h5","h6","hr","img","kbd","li","ol","p","pre","q","samp","span","sup","sub","strong","table","thead","tbody","td","th","tr","ul","var"]).join(" ")+" "; +xq.Validator=xq.Class({initialize:function(C,A,D,B){xq.addToFinalizeQueue(this); +this.allowedTags=(D||["a","abbr","acronym","address","blockquote","br","caption","cite","code","dd","dfn","div","dl","dt","em","h1","h2","h3","h4","h5","h6","hr","img","kbd","li","ol","p","pre","q","samp","span","sup","sub","strong","table","thead","tbody","td","th","tr","ul","var"]).join(" ")+" "; this.allowedAttrs=(B||["alt","cite","class","datetime","height","href","id","rel","rev","src","style","title","width"]).join(" ")+" "; this.curUrl=C; this.curUrlParts=C?C.parseURL():null; @@ -2209,7 +2399,7 @@ return A },validateSelfClosingTags:function(A){return A.replace(/<(br|hr|img)([^>]*?)>/img,function(D,B,C){return"<"+B+C+" />" }) },removeComments:function(A){return A.replace(//img,"") -},removeDangerousElements:function(C){var A=$A(C.getElementsByTagName("SCRIPT")).reverse(); +},removeDangerousElements:function(C){var A=xq.$A(C.getElementsByTagName("SCRIPT")).reverse(); for(var B=0; B\n$2"); return E },invalidate:function(C){var F=xq.RichDom.createInstance(); F.setRoot(C); -var E=F.findByAttribute("class","strike"); +var E=xq.getElementsByClassName(F.getRoot(),"strike"); for(var B=0; B( )?","img"); var C=xq.RichDom.createInstance(); return B.replace(A,"<$1>"+C.makePlaceHolderString()+"") }}); -xq.ValidatorGecko=Class.create(xq.ValidatorW3,{}); -xq.ValidatorWebkit=Class.create(xq.ValidatorW3,{}); -xq.ValidatorTrident=Class.create(xq.Validator,{validate:function(C,B){C=C.cloneNode(true); +xq.ValidatorGecko=xq.Class(xq.ValidatorW3,{}); +xq.ValidatorWebkit=xq.Class(xq.ValidatorW3,{}); +xq.ValidatorTrident=xq.Class(xq.Validator,{validate:function(C,B){C=C.cloneNode(true); this.removeDangerousElements(C); this.validateFontColor(C); this.validateBackgroundColor(C); @@ -2356,14 +2546,14 @@ if(B){D=this.performFullValidation(D) F.setRoot(C); this.invalidateFontColor(C); this.invalidateBackgroundColor(C); -var E=F.findByAttribute("className","strike"); +var E=xq.getElementsByClassName(F.getRoot(),"strike"); for(var B=0; B0){D[0].focus() -}if(C.cancelOnEsc){Event.observe(this.form,"keydown",function(F){if(F.keyCode==27){this.onCloseHandler(); +}if(C.cancelOnEsc){xq.observe(this.form,"keydown",function(F){if(F.keyCode==27){this.onCloseHandler(); this.close() }return false }.bind(this)) }this.onLoadHandler(this) },close:function(){this.form.parentNode.removeChild(this.form) -},setPosition:function(G){var D; -if(G=="centerOfWindow"){D=document.documentElement -}else{if(G=="centerOfEditor"){D=this.xed.getDoc()[xq.Browser.isTrident?"body":"documentElement"] -}else{if(G=="nearbyCaret"){throw"Not implemented yet" -}else{throw"Invalid argument: "+G -}}}var E=D.clientWidth; -var B=D.clientHeight; -var F=this.form.clientWidth; -var C=this.form.clientHeight; -var A=parseInt((E-F)/2); -var H=parseInt((B-C)/2); -this.form.style.left=A+"px"; +},setPosition:function(E){var F=null; +var B=0; +var H=0; +if(E=="centerOfWindow"){F=document.documentElement +}else{if(E=="centerOfEditor"){F=this.xed.getFrame(); +var A=F; +do{B+=A.offsetLeft; +H+=A.offsetTop +}while(A=A.offsetParent) +}else{if(E=="nearbyCaret"){throw"Not implemented yet" +}else{throw"Invalid argument: "+E +}}}var I=F.clientWidth; +var D=F.clientHeight; +var C=this.form.clientWidth; +var G=this.form.clientHeight; +B+=parseInt((I-C)/2); +H+=parseInt((D-G)/2); +this.form.style.left=B+"px"; this.form.style.top=H+"px" }}); -xq.controls.QuickSearchDialog=Class.create({initialize:function(A,B){this.xed=A; +xq.controls.QuickSearchDialog=xq.Class({initialize:function(A,B){xq.addToFinalizeQueue(this); +this.xed=A; this.rdom=xq.RichDom.createInstance(); this.rdom.setRoot(document.body); this.param=B; @@ -2538,7 +2737,7 @@ if(!this.param.renderItem){this.param.renderItem=function(C){return this.rdom.ge }return this._getInputField().value },onSubmit:function(A){if(this.matchCount()>0){this.param.onSelect(this.xed,this.list[this._getSelectedIndex()]) }this.close(); -Event.stop(A); +xq.stopEvent(A); return false },onCancel:function(A){if(this.param.onCancel){this.param.onCancel(this.xed) }this.close() @@ -2575,18 +2774,24 @@ this.updateList(); this.focus() },close:function(){this.rdom.deleteNode(this.container) },focus:function(){this._getInputField().focus() -},setPosition:function(G){var D; -if(G=="centerOfWindow"){D=document.documentElement -}else{if(G=="centerOfEditor"){D=this.xed.getDoc().documentElement -}else{if(G=="nearbyCaret"){throw"Not implemented yet" -}else{throw"Invalid argument: "+G -}}}var E=D.clientWidth; -var B=D.clientHeight; -var F=this.container.clientWidth; -var C=this.container.clientHeight; -var A=parseInt((E-F)/2); -var H=parseInt((B-C)/2); -this.container.style.left=A+"px"; +},setPosition:function(E){var F=null; +var B=0; +var H=0; +if(E=="centerOfWindow"){F=document.documentElement +}else{if(E=="centerOfEditor"){F=this.xed.getFrame(); +var A=F; +do{B+=A.offsetLeft; +H+=A.offsetTop +}while(A=A.offsetParent) +}else{if(E=="nearbyCaret"){throw"Not implemented yet" +}else{throw"Invalid argument: "+E +}}}var I=F.clientWidth; +var D=F.clientHeight; +var C=this.container.clientWidth; +var G=this.container.clientHeight; +B+=parseInt((I-C)/2); +H+=parseInt((D-G)/2); +this.container.style.left=B+"px"; this.container.style.top=H+"px" },matchCount:function(){return this.list?this.list.length:0 },_create:function(){var A=this.rdom.createElement("DIV"); @@ -2604,11 +2809,11 @@ D.appendChild(B); C.appendChild(D); A.appendChild(C); var E=this.rdom.createElement("OL"); -Event.observe(B,"blur",this.onBlur.bindAsEventListener(this)); -Event.observe(B,"keypress",this.onKey.bindAsEventListener(this)); -Event.observe(E,"click",this.onClick.bindAsEventListener(this),true); -Event.observe(D,"submit",this.onSubmit.bindAsEventListener(this)); -Event.observe(D,"reset",this.onCancel.bindAsEventListener(this)); +xq.observe(B,"blur",this.onBlur.bindAsEventListener(this)); +xq.observe(B,"keypress",this.onKey.bindAsEventListener(this)); +xq.observe(E,"click",this.onClick.bindAsEventListener(this),true); +xq.observe(D,"submit",this.onSubmit.bindAsEventListener(this)); +xq.observe(D,"reset",this.onCancel.bindAsEventListener(this)); A.appendChild(E); return A },_getInputField:function(){return this.container.getElementsByTagName("INPUT")[0] diff --git a/modules/editor/skins/xquared/js/xquared.js b/modules/editor/skins/xquared/js/xquared.js index 1e010f684..0bcf46524 100644 --- a/modules/editor/skins/xquared/js/xquared.js +++ b/modules/editor/skins/xquared/js/xquared.js @@ -2,10 +2,258 @@ * Namespace for entire Xquared classes */ var xq = { - majorVersion: '0.1', - minorVersion: '2007119' + majorVersion: '0.2', + minorVersion: '20071205' }; + + +/** + * Add prototype.js like functions + */ +xq.Class = function() { // TODO + var parent = null, properties = xq.$A(arguments); + if (typeof properties[0] == "function") + parent = properties.shift(); + + function klass() { + this.initialize.apply(this, arguments); + } + + if(parent) { + for (var key in parent.prototype) + klass.prototype[key] = parent.prototype[key]; + } + + for (var key in properties[0]) + klass.prototype[key] = properties[0][key]; + + if (!klass.prototype.initialize) + klass.prototype.initialize = function() {}; + + klass.prototype.constructor = klass; + + return klass; +} + +xq.observe = function(element, eventName, handler) { + if (element.addEventListener) { + element.addEventListener(eventName, handler, false); + } else { + element.attachEvent('on' + eventName, handler); + } + element = null; +} + +xq.stopObserving = function(element, eventName, handler) { + if (element.removeEventListener) { + element.removeEventListener(eventName, handler, false); + } else { + element.detachEvent("on" + eventName, handler); + } + element = null; +} + +xq.cancelHandler = function(e) {xq.stopEvent(e); return false}; + +xq.stopEvent = function(event) { + if(event.preventDefault) event.preventDefault(); + if(event.stopPropagation) event.stopPropagation(); + event.returnValue = false; + event.cancelBubble = true; + event.stopped = true; +} + +xq.isButton = function(event, code) { + return event.which ? (event.which === code + 1) : (event.button === code); +} +xq.isLeftClick = function(event) {return isButton(event, 0);} +xq.isMiddleClick = function(event) {return isButton(event, 1);} +xq.isRightClick = function(event) {return isButton(event, 2);} + +xq.getEventPoint = function(event) { + return { + x: event.pageX || (event.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft)), + y: event.pageY || (event.clientY + (document.documentElement.scrollTop || document.body.scrollTop)) + }; +} + +xq.getCumulativeOffset = function(element) { + var top = 0, left = 0; + + do { + top += element.offsetTop || 0; + left += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + + return {top:top, left:left}; +} + +xq.$ = function(id) { + return document.getElementById(id); +} + +xq.isEmptyHash = function(h) { + for(var key in h) { + return false; + } + return true; +} + +xq.$A = function(arraylike) { + var len = arraylike.length, a = new Array(len); + while (len--) a[len] = arraylike[len]; + return a; +} + +xq.hasClassName = function(element, className) { + var classNames = element.className; + return (classNames.length > 0 && (classNames == className || new RegExp("(^|\\s)" + className + "(\\s|$)").test(classNames))); +} + +xq.serializeForm = function(f) { + +try{ + var options = {hash: true}; + var data = {}; + var elements = f.getElementsByTagName("*"); + for(var i = 0; i < elements.length; i++) { + var element = elements[i]; + var tagName = element.tagName.toLowerCase(); + if(element.disabled || !element.name || ['input', 'textarea', 'option', 'select'].indexOf(tagName) == -1) continue; + + var key = element.name; + var value = xq.getValueOfElement(element); + + if(value === undefined) continue; + + if(key in data) { + if(data[key].constructor == Array) data[key] = [data[key]]; + data[key].push(value); + } else { + data[key] = value; + } + } + return data; +} catch(e) {alert(e)} +} + +xq.getValueOfElement = function(e) { + var type = e.type.toLowerCase(); + if(type == 'checkbox' || type == 'radio') return e.checked ? e.value : undefined; + return e.value; +} + +xq.getElementsByClassName = function(element, className) { + if(element.getElementsByClassName) return element.getElementsByClassName(className); + + var elements = element.getElementsByTagName("*"); + var len = elements.length; + var result = []; + var p = new RegExp("(^|\\s)" + className + "($|\\s)"); + for(var i = 0; i < len; i++) { + var cur = elements[i]; + if(p.test(cur.className)) result.push(cur); + } + return result; +} + +try {Prototype.version; __prototype = true;} catch(ignored) {__prototype = false;} + +if(!__prototype) { + if(!Function.prototype.bind) { + Function.prototype.bind = function() { + var __m = this, arg = xq.$A(arguments), o = arg.shift(); + return function() { + return __m.apply(o, arg.concat(xq.$A(arguments))); + } + } + } + + if(!Function.prototype.bindAsEventListener) { + Function.prototype.bindAsEventListener = function() { + var __m = this, arg = xq.$A(arguments), o = arg.shift(); + return function(event) { + return __m.apply(o, [event || window.event].concat(arg)); + } + } + } + + Array.prototype.find = function(f) { + for(var i = 0; i < this.length; i++) { + if(f(this[i])) return this[i]; + } + } + + Array.prototype.findAll = function(f) { + var result = []; + for(var i = 0; i < this.length; i++) { + if(f(this[i])) result.push(this[i]); + } + return result; + } + + Array.prototype.first = function() {return this[0]} + + Array.prototype.last = function() {return this[this.length - 1]} + + Array.prototype.include = function(o) { + if (this.indexOf(o) != -1) return true; + + var found = false; + for(var i = 0; i < this.length; i++) { + if(this[i] == o) return true; + } + + return false; + } + + Array.prototype.flatten = function() { + var result = []; + var _flatten = function(array) { + for(var i = 0; i < array.length; i++) { + if(array[i].constructor === Array) { + _flatten(array[i]); + } else { + result.push(array[i]); + } + } + } + _flatten(this); + + return result; + } + + String.prototype.blank = function() { + return /^\s*$/.test(this); + } + String.prototype.stripTags = function() { + return this.replace(/<\/?[^>]+>/gi, ''); + } + String.prototype.escapeHTML = function() { + xq._text.data = this; + return xq._div.innerHTML; + } + xq._text = document.createTextNode(''); + xq._div = document.createElement('div'); + xq._div.appendChild(xq._text); + + String.prototype.strip = function() { + return this.replace(/^\s+/, '').replace(/\s+$/, ''); + } + + Array.prototype.indexOf = function(n) { + for(var i = 0; i < this.length; i++) { + if(this[i] == n) return i; + } + + return -1; + } +} + + + /** * Make given object as event source * @@ -20,7 +268,7 @@ xq.asEventSource = function(object, prefix, events) { for(var i = 0; i < this._listeners.length; i++) { var listener = this._listeners[i]; var func = listener["on" + prefix + name]; - if(func) func.apply(listener, $A(arguments)); + if(func) func.apply(listener, xq.$A(arguments)); } } } @@ -33,18 +281,7 @@ xq.asEventSource = function(object, prefix, events) { } } -/** - * Returns the index of given element - * - * @returns {Number} index or -1 - */ -Array.prototype.indexOf = function(n) { - for(var i = 0; i < this.length; i++) { - if(this[i] == n) return i; - } - - return -1; -} + Date.preset = null; Date.pass = function(msec) { @@ -107,8 +344,37 @@ String.prototype.parseURL = function() { }; } + + +/** + * Automatic finalizer + */ +xq.autoFinalizeQueue = []; + +xq.addToFinalizeQueue = function(obj) { + xq.autoFinalizeQueue.push(obj); +} + +xq.finalize = function(obj) { + if(typeof obj.finalize == "function") { + try {obj.finalize();} catch(ignored) {} + } + + for(key in obj) obj[key] = null; +} + +xq.observe(window, "unload", function() { + for(var i = 0; i < xq.autoFinalizeQueue.length; i++) xq.finalize(xq.autoFinalizeQueue[i]); + xq = null; +}); + + + +/** + * Script loader + */ xq.findXquaredScript = function() { - return $A(document.getElementsByTagName("script")).find(function(script) { + return xq.$A(document.getElementsByTagName("script")).find(function(script) { return script.src && script.src.match(/xquared\.js/i); }); } @@ -142,27 +408,32 @@ xq.loadOthers = function() { 'Controls.js', '_ui_templates.js' ]; - others.each(function(name) { - xq.loadScript(basePath + name); - }); + for(var i = 0; i < others.length; i++) { + xq.loadScript(basePath + others[i]); + }; } if(xq.shouldLoadOthers()) xq.loadOthers(); /** * @fileOverview xq.Editor manages configurations such as autocompletion and autocorrection, edit mode/normal mode switching, handles editing commands, keyboard shortcuts and other events. */ -xq.Editor = Class.create({ +xq.Editor = xq.Class({ /** * Initialize editor but it doesn't automatically start designMode. setEditMode should be called after initialization. * * @constructor - * @param {Element} contentElement HTML element(TEXTAREA or normal block element such as DIV) to be replaced with editable area - * @param {Element} toolbarContainer HTML element which contains toolbar icons + * @param {Object} contentElement HTML element(TEXTAREA or normal block element such as DIV) to be replaced with editable area, or DOM ID string. + * @param {Object} toolbarContainer HTML element which contains toolbar icons, or DOM ID string. */ initialize: function(contentElement, toolbarContainer) { + xq.addToFinalizeQueue(this); + + if(typeof contentElement == 'string') contentElement = xq.$(contentElement); if(!contentElement) throw "[contentElement] is null"; if(contentElement.nodeType != 1) throw "[contentElement] is not an element"; + if(typeof toolbarContainer == 'string') toolbarContainer = xq.$(toolbarContainer); + xq.asEventSource(this, "Editor", ["ElementChanged", "BeforeEvent", "AfterEvent", "CurrentContentChanged", "StaticContentChanged", "CurrentEditModeChanged"]); /** @@ -224,7 +495,8 @@ xq.Editor = Class.create({ ] ]; - this.config.imagePathForDefaultToobar = request_uri+editor_path.substring(1)+'examples/img/toolbar/'; + this.config.imagePathForDefaultToobar = 'img/toolbar/'; + this.config.imagePathForContent = 'img/content/'; // relative | host_relative | absolute | browser_default this.config.urlValidationMode = 'absolute'; @@ -335,6 +607,7 @@ xq.Editor = Class.create({ * @type Array */ this.toolbarButtons = null; + this._toolbarAnchorsCache = []; /** * Undo/redo manager @@ -369,6 +642,15 @@ xq.Editor = Class.create({ }); }, + finalize: function() { + for(var i = 0; i < this._toolbarAnchorsCache.length; i++) { + this._toolbarAnchorsCache[i].xed = null; + this._toolbarAnchorsCache[i].handler = null; + this._toolbarAnchorsCache[i] = null; + } + this._toolbarAnchorsCache = null; + }, + ///////////////////////////////////////////// @@ -475,9 +757,9 @@ xq.Editor = Class.create({ * @param {Array} list of shortcuts. each element should have following structure: {event:"keymap expression", handler:handler} */ addShortcuts: function(list) { - list.each(function(shortcut) { - this.addShortcut(shortcut.event, shortcut.handler); - }.bind(this)); + for(var i = 0; i < list.length; i++) { + this.addShortcut(list[i].event, list[i].handler); + } }, /** @@ -520,9 +802,9 @@ xq.Editor = Class.create({ * @param {Array} list of autocorrection. each element should have following structure: {id:"identifier", criteria:criteria, handler:handler} */ addAutocorrections: function(list) { - list.each(function(ac) { - this.addAutocorrection(ac.id, ac.criteria, ac.handler); - }.bind(this)); + for(var i = 0; i < list.length; i++) { + this.addAutocorrection(list[i].id, list[i].criteria, list[i].handler); + } }, /** @@ -568,9 +850,9 @@ xq.Editor = Class.create({ * @param {Array} list of autocompletion. each element should have following structure: {id:"identifier", criteria:criteria, handler:handler} */ addAutocompletions: function(list) { - list.each(function(ac) { - this.addAutocompletion(ac.id, ac.criteria, ac.handler); - }.bind(this)); + for(var i = 0; i < list.length; i++) { + this.addAutocompletion(list[i].id, list[i].criteria, list[i].handler); + } }, /** @@ -608,9 +890,9 @@ xq.Editor = Class.create({ * @param {Array} list of template processors. Each element should have following structure: {id:"identifier", handler:handler} */ addTemplateProcessors: function(list) { - list.each(function(tp) { - this.addTemplateProcessor(tp.id, tp.handler); - }.bind(this)); + for(var i = 0; i < list.length; i++) { + this.addTemplateProcessor(list[i].id, list[i].handler); + } }, /** @@ -650,9 +932,9 @@ xq.Editor = Class.create({ * @param {Array} list of handlers. Each element should have following structure: {id:"identifier", handler:handler} */ addContextMenuHandlers: function(list) { - list.each(function(mh) { - this.addContextMenuHandler(mh.id, mh.handler); - }.bind(this)); + for(var i = 0; i < list.length; i++) { + this.addContextMenuHandler(list[i].id, list[i].handler); + } }, /** @@ -849,15 +1131,16 @@ xq.Editor = Class.create({ if(!this.toolbarContainer) return; exceptions = exceptions || []; - $(this.toolbarContainer).select('li').each(function(li) { - var buttonsClassName = li.classNames().find(function(name) {return name != 'xq_separator'}); - var exception = exceptions.include(buttonsClassName); - exec(li, exception); - }); + var lis = this.toolbarContainer.getElementsByTagName('LI'); + for(var i = 0; i < lis.length; i++) { + var buttonsClassName = lis[i].className.split(" ").find(function(name) {return name != 'xq_separator'}); + var exception = exceptions.indexOf(buttonsClassName) != -1; + exec(lis[i], exception); + } }, _updateToolbarButtonStatus: function(buttonClassName, selected) { - var button = this.toolbarButtons.get(buttonClassName); + var button = this.toolbarButtons[buttonClassName]; if(button) button.firstChild.firstChild.className = selected ? 'selected' : ''; }, @@ -871,13 +1154,13 @@ xq.Editor = Class.create({ "paragraph", "heading1", "heading2", "heading3", "heading4", "heading5", "heading6" ]; - this.toolbarButtons = $H({}); + this.toolbarButtons = {}; - classNames.each(function(className) { - var found = $(this.toolbarContainer).getElementsBySelector("." + className); + for(var i = 0; i < classNames.length; i++) { + var found = xq.getElementsByClassName(this.toolbarContainer, classNames[i]); var button = found && found.length > 0 ? found[0] : null; - if(button) this.toolbarButtons.set(className, button); - }.bind(this)); + if(button) this.toolbarButtons[classNames[i]] = button; + } } var buttons = this.toolbarButtons; @@ -1128,6 +1411,15 @@ xq.Editor = Class.create({ this.editorDoc.documentElement.style.overflowX='hidden'; } + // override image path + if(this.config.generateDefaultToolbar) { + this._addStyleRules([ + {selector:".xquared div.toolbar", rule:"background-image: url(" + this.config.imagePathForDefaultToobar + "toolbarBg.gif)"}, + {selector:".xquared ul.buttons li", rule:"background-image: url(" + this.config.imagePathForDefaultToobar + "toolbarButtonBg.gif)"}, + {selector:".xquared ul.buttons li.xq_separator", rule:"background-image: url(" + this.config.imagePathForDefaultToobar + "toolbarSeparator.gif)"} + ]); + } + this.rdom.setWin(this.editorWin); this.rdom.setRoot(this.editorBody); this.validator = xq.Validator.createInstance(this.doc.location.href, this.config.urlValidationMode, this.config.allowedTags, this.config.allowedAttributes); @@ -1147,30 +1439,51 @@ xq.Editor = Class.create({ } }, - _addStyleRule: function(selector, rule) { + _addStyleRules: function(rules) { if(!this.dynamicStyle) { if(xq.Browser.isTrident) { this.dynamicStyle = this.doc.createStyleSheet(); } else { var style = this.doc.createElement('style'); this.doc.body.appendChild(style); - this.dynamicStyle = $A(this.doc.styleSheets).last(); + this.dynamicStyle = xq.$A(this.doc.styleSheets).last(); } } - if(xq.Browser.isTrident) { - this.dynamicStyle.addRule(selector, rule); + for(var i = 0; i < rules.length; i++) { + var rule = rules[i]; + if(xq.Browser.isTrident) { + this.dynamicStyle.addRule(rules[i].selector, rules[i].rule); + } else { + this.dynamicStyle.insertRule(rules[i].selector + " {" + rules[i].rule + "}", this.dynamicStyle.cssRules.length); + } + } + }, + + _defaultToolbarClickHandler: function(e) { + var src = e.target || e.srcElement; + while(src.nodeName != "A") src = src.parentNode; + + if(xq.hasClassName(src.parentNode, 'disabled') || xq.hasClassName(this.toolbarContainer, 'disabled')) { + xq.stopEvent(e); + return false; + } + + if(xq.Browser.isTrident) this.focus(); + + var handler = src.handler; + var xed = this; + var stop = (typeof handler == "function") ? handler(this) : eval(handler); + + if(stop) { + xq.stopEvent(e); + return false; } else { - this.dynamicStyle.insertRule(selector + " {" + rule + "}", this.dynamicStyle.cssRules.length); - } + return true; + } }, _generateDefaultToolbar: function() { - // override image path - this._addStyleRule(".xquared div.toolbar", "background-image: url(" + this.config.imagePathForDefaultToobar + "toolbarBg.gif)"); - this._addStyleRule(".xquared ul.buttons li", "background-image: url(" + this.config.imagePathForDefaultToobar + "toolbarButtonBg.gif)"); - this._addStyleRule(".xquared ul.buttons li.xq_separator", "background-image: url(" + this.config.imagePathForDefaultToobar + "toolbarSeparator.gif)"); - // outmost container var container = this.doc.createElement('div'); container.className = 'toolbar'; @@ -1181,7 +1494,6 @@ xq.Editor = Class.create({ container.appendChild(buttons); // Generate buttons from map and append it to button container - var cancelMousedown = function(e) {Event.stop(e); return false}; var map = this.config.defaultToolbarButtonMap; for(var i = 0; i < map.length; i++) { for(var j = 0; j < map[i].length; j++) { @@ -1199,28 +1511,12 @@ xq.Editor = Class.create({ a.href = '#'; a.title = buttonConfig.title; a.handler = buttonConfig.handler; - a.xed = this; - Event.observe(a, 'mousedown', cancelMousedown); - Event.observe(a, 'click', function(e) { - var xed = this.xed; - - if($(this.parentNode).hasClassName('disabled') || xed.toolbarContainer.hasClassName('disabled')) { - Event.stop(e); - return false; - } - - if(xq.Browser.isTrident) xed.focus(); - - var handler = this.handler; - var stop = (typeof handler == "function") ? handler(xed) : eval(handler); - if(stop) { - Event.stop(e); - return false; - } else { - return true; - } - }.bind(a)); + this._toolbarAnchorsCache.push(a); + + xq.observe(a, 'mousedown', xq.cancelHandler); + xq.observe(a, 'click', this._defaultToolbarClickHandler.bindAsEventListener(this)); + var img = this.doc.createElement('img'); a.appendChild(img); img.src = this.config.imagePathForDefaultToobar + buttonConfig.className + '.gif'; @@ -1238,13 +1534,13 @@ xq.Editor = Class.create({ // Event Management _registerEventHandlers: function() { - var events = ['keydown', 'click', 'keyup', 'mouseup', 'contextmenu', 'scroll']; + var events = ['keydown', 'click', 'keyup', 'mouseup', 'contextmenu']; if(xq.Browser.isTrident && this.config.changeCursorOnLink) events.push('mousemove'); if(xq.Browser.isMac && xq.Browser.isGecko) events.push('keypress'); for(var i = 0; i < events.length; i++) { - Event.observe(this.getDoc(), events[i], this._handleEvent.bindAsEventListener(this)); + xq.observe(this.getDoc(), events[i], this._handleEvent.bindAsEventListener(this)); } }, @@ -1258,7 +1554,11 @@ xq.Editor = Class.create({ if(e.type == 'mousemove' && this.config.changeCursorOnLink) { // Trident only var link = !!this.rdom.getParentElementOf(e.srcElement, ["A"]); - if(this.editorBody.contentEditable != link && !this.rdom.hasSelection()) this.editorBody.contentEditable = !link; + + var editable = this.editorBody.contentEditable; + editable = editable == 'inherit' ? false : editable; + + if(editable != link && !this.rdom.hasSelection()) this.editorBody.contentEditable = !link; } else if(e.type == 'click' && e.button == 0 && this.config.enableLinkClick) { var a = this.rdom.getParentElementOf(e.target || e.srcElement, ["A"]); if(a) stop = this.handleClick(e, a); @@ -1275,13 +1575,13 @@ xq.Editor = Class.create({ if(key == "undo") undoPerformed = true; } - } else if(["mouseup", "keyup"].include(e.type)) { + } else if(["mouseup", "keyup"].indexOf(e.type) != -1) { modifiedByCorrection = this.rdom.correctParagraph(); - } else if(["contextmenu"].include(e.type)) { + } else if(["contextmenu"].indexOf(e.type) != -1) { this._handleContextMenu(e); } - if(stop) Event.stop(e); + if(stop) xq.stopEvent(e); this._fireOnCurrentContentChanged(this); this._fireOnAfterEvent(this, e); @@ -1335,8 +1635,8 @@ xq.Editor = Class.create({ * TODO: remove dup with handleAutocorrection */ handleAutocompletion: function() { - var acs = $H(this.config.autocompletions); - if(acs.size() == 0) return; + var acs = this.config.autocompletions; + if(xq.isEmptyHash(acs)) return; if(this.rdom.hasSelection()) { var text = this.rdom.getSelectionAsText(); @@ -1345,41 +1645,58 @@ xq.Editor = Class.create({ wrapper.innerHTML = text; var marker = this.rdom.pushMarker(); - - var filtered = - acs.map(function(pair) { - return [pair.key, pair.value.criteria(text)]; - }.bind(this)).findAll(function(elem) { - return elem[1] != -1; - }).sortBy(function(elem) { - return elem[1]; - }); + var filtered = []; + for(var key in acs) { + filtered.push([key, acs[key].criteria(text)]); + } + filtered = filtered.findAll(function(elem) { + return elem[1] != -1; + }); + if(filtered.length == 0) { this.rdom.popMarker(true); return; } - var ac = acs.get(filtered[0][0]); + + var minIndex = 0; + var min = filtered[0][1]; + for(var i = 0; i < filtered.length; i++) { + if(filtered[i][1] < min) { + minIndex = i; + min = filtered[i][1]; + } + } + + var ac = acs[filtered[minIndex][0]]; this.editHistory.disable(); } else { var marker = this.rdom.pushMarker(); - - var filtered = - acs.map(function(pair) { - return [pair.key, this.rdom.testSmartWrap(marker, pair.value.criteria).textIndex]; - }.bind(this)).findAll(function(elem) { - return elem[1] != -1; - }).sortBy(function(elem) { - return elem[1]; - }); + + var filtered = []; + for(var key in acs) { + filtered.push([key, this.rdom.testSmartWrap(marker, acs[key].criteria).textIndex]); + } + filtered = filtered.findAll(function(elem) { + return elem[1] != -1; + }); if(filtered.length == 0) { this.rdom.popMarker(true); return; } - var ac = acs.get(filtered[0][0]); + var minIndex = 0; + var min = filtered[0][1]; + for(var i = 0; i < filtered.length; i++) { + if(filtered[i][1] < min) { + minIndex = i; + min = filtered[i][1]; + } + } + + var ac = acs[filtered[minIndex][0]]; this.editHistory.disable(); @@ -1405,7 +1722,6 @@ xq.Editor = Class.create({ try { this.rdom.unwrapElement(wrapper); } catch(ignored) {} - if(this.rdom.isEmptyBlock(block)) this.rdom.correctEmptyElement(block); @@ -1701,7 +2017,7 @@ xq.Editor = Class.create({ var rtable = new xq.RichTable(this.rdom, table); var target = null; - if(["next", "prev"].include(dir)) { + if(["next", "prev"].indexOf(dir) != -1) { var toNext = dir == "next"; target = toNext ? rtable.getNextCellOf(cell) : rtable.getPreviousCellOf(cell); } else { @@ -1710,7 +2026,7 @@ xq.Editor = Class.create({ } if(!target) { - var finder = function(node) {return !['TD', 'TH'].include(node.nodeName) && this.tree.isBlock(node) && !this.tree.hasBlocks(node);}.bind(this.rdom); + var finder = function(node) {return ['TD', 'TH'].indexOf(node.nodeName) == -1 && this.tree.isBlock(node) && !this.tree.hasBlocks(node);}.bind(this.rdom); var exitCondition = function(node) {return this.tree.isBlock(node) && !this.tree.isDescendantOf(this.getRoot(), node)}.bind(this.rdom); target = (toNext || toBelow) ? @@ -2161,24 +2477,26 @@ xq.Editor = Class.create({ _handleContextMenu: function(e) { if (xq.Browser.isWebkit) { - if (e.metaKey || Event.isLeftClick(e)) return false; + if (e.metaKey || xq.isLeftClick(e)) return false; } else if (e.shiftKey || e.ctrlKey || e.altKey) { return false; } - var x=Event.pointerX(e); - var y=Event.pointerY(e); - var pos=Position.cumulativeOffset(this.getFrame()); - x+=pos[0]; - y+=pos[1]; + var point = xq.getEventPoint(e); + var x = point.x; + var y = point.y; + + var pos = xq.getCumulativeOffset(this.getFrame()); + x += pos.left; + y += pos.top; this._contextMenuTargetElement = e.target || e.srcElement; //TODO: Safari on Windows doesn't work with context key(app key) if (!x || !y || xq.Browser.isTrident) { - var pos = Position.cumulativeOffset(this._contextMenuTargetElement); - var posFrame = Position.cumulativeOffset(this.getFrame()); - x = pos[0] + posFrame[0] - this.getDoc().documentElement.scrollLeft; - y = pos[1] + posFrame[1] - this.getDoc().documentElement.scrollTop; + var pos = xq.getCumulativeOffset(this._contextMenuTargetElement); + var posFrame = xq.getCumulativeOffset(this.getFrame()); + x = pos.left + posFrame.left - this.getDoc().documentElement.scrollLeft; + y = pos.top + posFrame.top - this.getDoc().documentElement.scrollTop; } if (!xq.Browser.isTrident) { @@ -2197,7 +2515,7 @@ xq.Editor = Class.create({ for(var cmh in this.config.contextMenuHandlers) { var stop = this.config.contextMenuHandlers[cmh].handler(this, this._contextMenuTargetElement, x, y); if(stop) { - Event.stop(e); + xq.stopEvent(e); return true; } } @@ -2213,8 +2531,8 @@ xq.Editor = Class.create({ this._contextMenuContainer.className = 'xqContextMenu'; this._contextMenuContainer.style.display='none'; - Event.observe(this.doc, 'click', this._contextMenuClicked.bindAsEventListener(this)); - Event.observe(this.rdom.getDoc(), 'click', this.hideContextMenu.bindAsEventListener(this)); + xq.observe(this.doc, 'click', this._contextMenuClicked.bindAsEventListener(this)); + xq.observe(this.rdom.getDoc(), 'click', this.hideContextMenu.bindAsEventListener(this)); this.body.appendChild(this._contextMenuContainer); } else { @@ -2267,7 +2585,10 @@ xq.Editor = Class.create({ if (!this._contextMenuContainer) return; - var node = Event.findElement(e, 'LI'); + var node = e.srcElement || e.target; + while(node && node.nodeName != "LI") { + node = node.parentNode; + } if (!node || !this.rdom.tree.isDescendantOf(this._contextMenuContainer, node)) return; for (var i=0; i < this._contextMenuItems.length; i++) { @@ -2312,9 +2633,10 @@ xq.Editor = Class.create({ _processTemplate: function(html) { // apply template processors - var tps = $H(this.getTemplateProcessors()).values(); - for(var i = 0; i < tps.length; i++) { - html = tps[i].handler(html); + var tps = this.getTemplateProcessors(); + for(var key in tps) { + var value = tps[key]; + html = value.handler(html); } // remove all whitespace characters between block tags @@ -2374,8 +2696,10 @@ xq.Browser = { isIE6: navigator.userAgent.indexOf('MSIE 6') != -1, isIE7: navigator.userAgent.indexOf('MSIE 7') != -1 }; -xq.Shortcut = Class.create({ +xq.Shortcut = xq.Class({ initialize: function(keymapOrExpression) { + xq.addToFinalizeQueue(this); + this.keymap = (typeof keymapOrExpression == "string") ? xq.Shortcut.interprete(keymapOrExpression).keymap : keymapOrExpression; @@ -2506,8 +2830,9 @@ xq.Shortcut._keyNames = * * TODO: Add specs */ -xq.DomTree = Class.create({ +xq.DomTree = xq.Class({ initialize: function() { + xq.addToFinalizeQueue(this); this._blockTags = ["DIV", "DD", "LI", "ADDRESS", "CAPTION", "DT", "H1", "H2", "H3", "H4", "H5", "H6", "HR", "P", "BODY", "BLOCKQUOTE", "PRE", "PARAM", "DL", "OL", "UL", "TABLE", "THEAD", "TBODY", "TR", "TH", "TD"]; this._blockContainerTags = ["DIV", "DD", "LI", "BODY", "BLOCKQUOTE", "UL", "OL", "DL", "TABLE", "THEAD", "TBODY", "TR", "TH", "TD"]; this._listContainerTags = ["OL", "UL", "DL"]; @@ -2590,6 +2915,7 @@ xq.DomTree = Class.create({ var left = findLeft(element); var right = findRight(element); + return [left == element ? null : left, right == element ? null : right]; }, @@ -2782,17 +3108,17 @@ xq.DomTree = Class.create({ isBlockOnlyContainer: function(element) { if(!element) return false; - return this._blockOnlyContainerTags.include(typeof element == 'string' ? element : element.nodeName); + return this._blockOnlyContainerTags.indexOf(typeof element == 'string' ? element : element.nodeName) != -1; }, isTableCell: function(element) { if(!element) return false; - return this._tableCellTags.include(typeof element == 'string' ? element : element.nodeName); + return this._tableCellTags.indexOf(typeof element == 'string' ? element : element.nodeName) != -1; }, isBlockContainer: function(element) { if(!element) return false; - return this._blockContainerTags.include(typeof element == 'string' ? element : element.nodeName); + return this._blockContainerTags.indexOf(typeof element == 'string' ? element : element.nodeName) != -1; }, isHeading: function(element) { @@ -2802,17 +3128,17 @@ xq.DomTree = Class.create({ isBlock: function(element) { if(!element) return false; - return this._blockTags.include(typeof element == 'string' ? element : element.nodeName); + return this._blockTags.indexOf(typeof element == 'string' ? element : element.nodeName) != -1; }, isAtomic: function(element) { if(!element) return false; - return this._atomicTags.include(typeof element == 'string' ? element : element.nodeName); + return this._atomicTags.indexOf(typeof element == 'string' ? element : element.nodeName) != -1; }, isListContainer: function(element) { if(!element) return false; - return this._listContainerTags.include(typeof element == 'string' ? element : element.nodeName); + return this._listContainerTags.indexOf(typeof element == 'string' ? element : element.nodeName) != -1; }, isTextOrInlineNode: function(node) { @@ -2824,13 +3150,15 @@ xq.DomTree = Class.create({ * * RichDom provides basic CRUD + Advanced DOM manipulation API, various query methods and caret/selection management API */ -xq.RichDom = Class.create({ +xq.RichDom = xq.Class({ /** * Initialize RichDom. Target window and root element should be set after initialization. See setWin and setRoot. * * @constructor */ initialize: function() { + xq.addToFinalizeQueue(this); + /** * {xq.DomTree} instance of DomTree */ @@ -2921,7 +3249,7 @@ xq.RichDom = Class.create({ * @param {Object} map key-value pairs */ setAttributes: function(element, map) { - for(key in map) element.setAttribute(key, map[key]); + for(var key in map) element.setAttribute(key, map[key]); }, /** @@ -3023,8 +3351,8 @@ xq.RichDom = Class.create({ */ insertNodeAt: function(node, target, where, performValidation) { if( - ["HTML", "HEAD"].include(target.nodeName) || - ["BODY"].include(target.nodeName) && ["before", "after"].include(where) + ["HTML", "HEAD"].indexOf(target.nodeName) != -1 || + "BODY" == target.nodeName && ["before", "after"].indexOf(where) != -1 ) throw "Illegal argument. Cannot move node[" + node.nodeName + "] to '" + where + "' of target[" + target.nodeName + "]" var object; @@ -3217,7 +3545,10 @@ xq.RichDom = Class.create({ // find textnode and break-point var nodeIndex = 0; - var nodeValues = textNodes.pluck("nodeValue"); + var nodeValues = []; + for(var i = 0; i < textNodes.length; i++) { + nodeValues.push(textNodes[i].nodeValue); + } var textToWrap = nodeValues.join(""); var textIndex = criteria(textToWrap) var breakPoint = textIndex; @@ -3531,13 +3862,16 @@ xq.RichDom = Class.create({ var elements = this.getBlockElementsBetween(from, to); for(var i = 0; i < elements.length; i++) { if(this.tree.isBlockContainer(elements[i])) { - applied.push(this.wrapAllInlineOrTextNodesAs(tagName, elements[i], true)); + var wrappers = this.wrapAllInlineOrTextNodesAs(tagName, elements[i], true); + for(var j = 0; j < wrappers.length; j++) { + applied.push(wrappers[j]); + } } else { applied.push(this.replaceTag(tagName, elements[i])); } } } - return applied.flatten(); + return applied; }, /** @@ -3564,7 +3898,7 @@ xq.RichDom = Class.create({ if(target) { var singleNodeLi = target.nodeName == 'LI' && ((target.childNodes.length == 1 && this.tree.isBlock(target.firstChild)) || !this.tree.hasBlocks(target)); - var table = ['TABLE', 'TR'].include(target.nodeName); + var table = ['TABLE', 'TR'].indexOf(target.nodeName) != -1; where = this.tree.isBlockContainer(target) && !singleNodeLi && !table ? "end" : "before"; } else if(block.parentNode != this.getRoot()) { @@ -3576,7 +3910,7 @@ xq.RichDom = Class.create({ if(target) { var singleNodeLi = target.nodeName == 'LI' && ((target.childNodes.length == 1 && this.tree.isBlock(target.firstChild)) || !this.tree.hasBlocks(target)); - var table = ['TABLE', 'TR'].include(target.nodeName); + var table = ['TABLE', 'TR'].indexOf(target.nodeName) != -1; where = this.tree.isBlockContainer(target) && !singleNodeLi && !table ? "start" : "after"; } else if(block.parentNode != this.getRoot()) { @@ -3588,7 +3922,7 @@ xq.RichDom = Class.create({ // no way to go? if(!target) return null; - if(["TBODY", "THEAD"].include(target.nodeName)) return null; + if(["TBODY", "THEAD"].indexOf(target.nodeName) != -1) return null; // normalize this.wrapAllInlineOrTextNodesAs("P", target, true); @@ -3618,6 +3952,8 @@ xq.RichDom = Class.create({ } } + this.correctEmptyElement(moved); + return moved; }, @@ -3714,7 +4050,7 @@ xq.RichDom = Class.create({ * Split container of element into (maxium) three pieces. */ splitContainerOf: function(element, preserveElementItself, dir) { - if([element, element.parentNode].include(this.getRoot())) return element; + if([element, element.parentNode].indexOf(this.getRoot()) != -1) return element; var container = element.parentNode; if(element.previousSibling && (!dir || dir.toLowerCase() == "prev")) { @@ -3746,7 +4082,7 @@ xq.RichDom = Class.create({ */ splitParentElement: function(seperator) { var parent = seperator.parentNode; - if(["HTML", "HEAD", "BODY"].include(parent.nodeName)) throw "Illegal argument. Cannot seperate element[" + parent.nodeName + "]"; + if(["HTML", "HEAD", "BODY"].indexOf(parent.nodeName) != -1) throw "Illegal argument. Cannot seperate element[" + parent.nodeName + "]"; var previousSibling = seperator.previousSibling; var nextSibling = seperator.nextSibling; @@ -3824,8 +4160,8 @@ xq.RichDom = Class.create({ try { var containersAreTableCell = - prevContainer && (this.tree.isTableCell(prevContainer) || ['TR', 'THEAD', 'TBODY'].include(prevContainer.nodeName)) && - nextContainer && (this.tree.isTableCell(nextContainer) || ['TR', 'THEAD', 'TBODY'].include(nextContainer.nodeName)); + prevContainer && (this.tree.isTableCell(prevContainer) || ['TR', 'THEAD', 'TBODY'].indexOf(prevContainer.nodeName) != -1) && + nextContainer && (this.tree.isTableCell(nextContainer) || ['TR', 'THEAD', 'TBODY'].indexOf(nextContainer.nodeName) != -1); if(containersAreTableCell && prevContainer != nextContainer) return null; @@ -3964,7 +4300,7 @@ xq.RichDom = Class.create({ * @param {Elemet} to target element */ moveChildNodes: function(from, to) { - if(this.tree.isDescendantOf(from, to) || ["HTML", "HEAD"].include(to.nodeName)) + if(this.tree.isDescendantOf(from, to) || ["HTML", "HEAD"].indexOf(to.nodeName) != -1) throw "Illegal argument. Cannot move children of element[" + from.nodeName + "] to element[" + to.nodeName + "]"; if(from == to) return; @@ -3988,7 +4324,7 @@ xq.RichDom = Class.create({ for(var i = 0; i < attrs.length; i++) { if(attrs[i].nodeName == "class" && attrs[i].nodeValue) { to.className = attrs[i].nodeValue; - } else if((copyId || !["id"].include(attrs[i].nodeName)) && attrs[i].nodeValue) { + } else if((copyId || "id" != attrs[i].nodeName) && attrs[i].nodeValue) { to.setAttribute(attrs[i].nodeName, attrs[i].nodeValue); } } @@ -4017,7 +4353,7 @@ xq.RichDom = Class.create({ } } - var children=$A(node.childNodes); + var children=xq.$A(node.childNodes); for (var i=0; i < children.length; i++) this._indentElements(children[i], blocks, affect); return; @@ -4036,7 +4372,7 @@ xq.RichDom = Class.create({ return [affected]; } - var children = $A(top.parent.childNodes); + var children = xq.$A(top.parent.childNodes); for (var i=0; i < children.length; i++) { this._indentElements(children[i], blocks, affect); } @@ -4069,7 +4405,7 @@ xq.RichDom = Class.create({ } if (blocks.include(node)) { - var children = $A(node.parentNode.childNodes); + var children = xq.$A(node.parentNode.childNodes); var isCode = this.outdentElementsCode(node); var affected = this.outdentElement(node, true, isCode); if (affected) { @@ -4084,7 +4420,7 @@ xq.RichDom = Class.create({ } } - var children=$A(node.childNodes); + var children=xq.$A(node.childNodes); for (var i=0; i < children.length; i++) this._outdentElements(children[i], blocks, affect); return; @@ -4108,7 +4444,7 @@ xq.RichDom = Class.create({ return [affected]; } - var children = $A(top.parent.childNodes); + var children = xq.$A(top.parent.childNodes); for (var i=0; i < children.length; i++) { this._outdentElements(children[i], blocks, affect); } @@ -4299,10 +4635,9 @@ xq.RichDom = Class.create({ }, justifyBlocks: function(blocks, dir) { - blocks.each(function(block) { - this.justifyBlock(block, dir); - }.bind(this)); - + for(var i = 0; i < blocks.length; i++) { + this.justifyBlock(blocks[i], dir); + } return blocks; }, @@ -4466,7 +4801,7 @@ xq.RichDom = Class.create({ return null; }, wrapBlock: function(tag, start, end) { - if(!this.tree._blockTags.include(tag)) throw "Unsuppored block container: [" + tag + "]"; + if(this.tree._blockTags.indexOf(tag) == -1) throw "Unsuppored block container: [" + tag + "]"; if(!start) start = this.getCurrentBlockElement(); if(!end) end = start; @@ -4782,18 +5117,19 @@ xq.RichDom = Class.create({ if(!found) found = []; var regexp = /^h[1-6]/ig; - - if (!element.childNodes) return []; - $A(element.childNodes).each(function(child) { - var isContainer = child && this.tree._blockContainerTags.include(child.nodeName); - var isHeading = child && child.nodeName.match(regexp); + var nodes = element.childNodes; + if (!nodes) return []; + + for(var i = 0; i < nodes.length; i++) { + var isContainer = nodes[i] && this.tree._blockContainerTags.indexOf(nodes[i].nodeName) != -1; + var isHeading = nodes[i] && nodes[i].nodeName.match(regexp); if (isContainer) { - this.searchHeadings(child, found); + this.searchHeadings(nodes[i], found); } else if (isHeading) { - found.push(child); + found.push(nodes[i]); } - }.bind(this)); + } return found; }, @@ -4808,6 +5144,10 @@ xq.RichDom = Class.create({ if(!element || element.nodeName == "#document") return {}; var block = this.getParentBlockElementOf(element); + + // IE���� ��Ȥ DOM�� �� ��: element�� ���ڷ� �Ѿ�4?��찡�? + if(block == null) return {}; + var parents = this.tree.collectParentsOf(element, true, function(node) {return block.parentNode == node}); var blockName = block.nodeName; @@ -4848,37 +5188,6 @@ xq.RichDom = Class.create({ }; }, - /** - * Find elements by CSS selector. - * - * WARNING: Use this method carefully since prototype.js doesn't work well with designMode DOM. - */ - findBySelector: function(selector) { - return Element.getElementsBySelector(this.root, selector); - }, - - /** - * Find elements by attribute. - * - * This method will be deprecated when findBySelector get stabilized. - */ - findByAttribute: function(name, value) { - var nodes = []; - this._findByAttribute(nodes, this.root, name, value); - return nodes; - }, - - /** @private */ - _findByAttribute: function(nodes, element, name, value) { - if(element.getAttribute(name) == value) nodes.push(element); - if(!element.hasChildNodes()) return; - - var children = element.childNodes; - for(var i = 0; i < children.length; i++) { - if(children[i].nodeType == 1) this._findByAttribute(nodes, children[i], name, value); - } - }, - /** * Checks if the element has one or more important attributes: id, class, style * @@ -4921,7 +5230,7 @@ xq.RichDom = Class.create({ */ getParentBlockElementOf: function(element) { while(element) { - if(this.tree._blockTags.include(element.nodeName)) return element; + if(this.tree._blockTags.indexOf(element.nodeName) != -1) return element; element = element.parentNode; } return null; @@ -4938,7 +5247,7 @@ xq.RichDom = Class.create({ */ getParentElementOf: function(element, tagNames) { while(element) { - if(tagNames.include(element.nodeName)) return element; + if(tagNames.indexOf(element.nodeName) != -1) return element; element = element.parentNode; } return null; @@ -5017,11 +5326,8 @@ xq.RichDom = Class.create({ getFirstChild: function(element) { if(!element) return null; - var nodes = $A(element.childNodes); - for(var i = 0; i < nodes.length; i++) { - if(!this.isEmptyTextNode(nodes[i])) return nodes[i]; - } - return null; + var nodes = xq.$A(element.childNodes); + return nodes.find(function(node) {return !this.isEmptyTextNode(node)}.bind(this)); }, /** @@ -5076,7 +5382,7 @@ xq.RichDom.createInstance = function() { /** * RichDom for W3C Standard Engine */ -xq.RichDomW3 = Class.create(xq.RichDom, { +xq.RichDomW3 = xq.Class(xq.RichDom, { insertNode: function(node) { var rng = this.rng(); rng.insertNode(node); @@ -5317,7 +5623,7 @@ xq.RichDomW3 = Class.create(xq.RichDom, { getLastChild: function(element) { if(!element || !element.hasChildNodes()) return null; - var nodes = $A(element.childNodes).reverse(); + var nodes = xq.$A(element.childNodes).reverse(); for(var i = 0; i < nodes.length; i++) { if(!this.isPlaceHolder(nodes[i]) && !this.isEmptyTextNode(nodes[i])) return nodes[i]; @@ -5450,7 +5756,7 @@ xq.RichDomW3 = Class.create(xq.RichDom, { /** * RichDom for Gecko */ -xq.RichDomGecko = Class.create(xq.RichDomW3, { +xq.RichDomGecko = xq.Class(xq.RichDomW3, { makePlaceHolder: function() { var holder = this.createElement("BR"); holder.setAttribute("type", "_moz"); @@ -5496,7 +5802,7 @@ xq.RichDomGecko = Class.create(xq.RichDomW3, { /** * RichDom for Webkit */ -xq.RichDomWebkit = Class.create(xq.RichDomW3, { +xq.RichDomWebkit = xq.Class(xq.RichDomW3, { makePlaceHolder: function() { var holder = this.createElement("BR"); holder.className = "webkit-block-placeholder"; @@ -5580,7 +5886,7 @@ xq.RichDomWebkit = Class.create(xq.RichDomW3, { /** * RichDom for Internet Explorer 6 and 7 */ -xq.RichDomTrident = Class.create(xq.RichDom, { +xq.RichDomTrident = xq.Class(xq.RichDom, { makePlaceHolder: function() { return this.createTextNode(" "); }, @@ -5621,7 +5927,7 @@ xq.RichDomTrident = Class.create(xq.RichDom, { var text = block.innerText; var lastCharCode = text.charCodeAt(text.length - 1); - if(text.length <= 1 || ![32,160].include(lastCharCode)) return; + if(text.length <= 1 || [32,160].indexOf(lastCharCode) == -1) return; var node = block; @@ -5682,10 +5988,14 @@ xq.RichDomTrident = Class.create(xq.RichDom, { block, function(node) {return this.tree.isBlock(node) && !this.tree.isBlockOnlyContainer(node)}.bind(this) ); + if(nextBlock) { this.deleteNode(block); this.placeCaretAtStartOf(nextBlock); + } else { + this.placeCaretAtStartOf(block); } + return true; } } else { @@ -5837,7 +6147,7 @@ xq.RichDomTrident = Class.create(xq.RichDom, { isEmptyBlock: function(element) { if(!element.hasChildNodes()) return true; if(element.nodeType == 3 && !element.nodeValue) return true; - if([" ", " ", ""].include(element.innerHTML)) return true; + if([" ", " ", ""].indexOf(element.innerHTML) != -1) return true; return false; }, @@ -5845,7 +6155,7 @@ xq.RichDomTrident = Class.create(xq.RichDom, { getLastChild: function(element) { if(!element || !element.hasChildNodes()) return null; - var nodes = $A(element.childNodes).reverse(); + var nodes = xq.$A(element.childNodes).reverse(); for(var i = 0; i < nodes.length; i++) { if(nodes[i].nodeType != 3 || nodes[i].nodeValue.length != 0) return nodes[i]; @@ -5938,8 +6248,10 @@ xq.RichDomTrident = Class.create(xq.RichDom, { bookmark.select(); } }); -xq.RichTable = Class.create({ +xq.RichTable = xq.Class({ initialize: function(rdom, table) { + xq.addToFinalizeQueue(this); + this.rdom = rdom; this.table = table; }, @@ -6087,9 +6399,11 @@ xq.RichTable = Class.create({ return this.table.tBodies[0].rows[0].cells[0].nodeName == "TH"; }, correctEmptyCells: function() { - var cells = $A(this.table.getElementsByTagName("TH")); - cells.push($A(this.table.getElementsByTagName("TD"))); - cells = cells.flatten(); + var cells = xq.$A(this.table.getElementsByTagName("TH")); + var tds = xq.$A(this.table.getElementsByTagName("TD")); + for(var i = 0; i < tds.length; i++) { + cells.push(tds[i]); + } for(var i = 0; i < cells.length; i++) { if(this.rdom.isEmptyBlock(cells[i])) this.rdom.correctEmptyElement(cells[i]) @@ -6098,8 +6412,8 @@ xq.RichTable = Class.create({ }); xq.RichTable.create = function(rdom, cols, rows, headerPositions) { - if(["t", "tl", "lt"].include(headerPositions)) var headingAtTop = true - if(["l", "tl", "lt"].include(headerPositions)) var headingAtLeft = true + if(["t", "tl", "lt"].indexOf(headerPositions) != -1) var headingAtTop = true + if(["l", "tl", "lt"].indexOf(headerPositions) != -1) var headingAtLeft = true var sb = [] sb.push('
      ') @@ -6143,8 +6457,10 @@ xq.RichTable.create = function(rdom, cols, rows, headerPositions) { /** * Validates and invalidates designmode contents */ -xq.Validator = Class.create({ +xq.Validator = xq.Class({ initialize: function(curUrl, urlValidationMode, allowedTags, allowedAttrs) { + xq.addToFinalizeQueue(this); + this.allowedTags = (allowedTags || ['a', 'abbr', 'acronym', 'address', 'blockquote', 'br', 'caption', 'cite', 'code', 'dd', 'dfn', 'div', 'dl', 'dt', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'img', 'kbd', 'li', 'ol', 'p', 'pre', 'q', 'samp', 'span', 'sup', 'sub', 'strong', 'table', 'thead', 'tbody', 'td', 'th', 'tr', 'ul', 'var']).join(' ') + ' '; this.allowedAttrs = (allowedAttrs || ['alt', 'cite', 'class', 'datetime', 'height', 'href', 'id', 'rel', 'rev', 'src', 'style', 'title', 'width']).join(' ') + ' '; @@ -6198,7 +6514,7 @@ xq.Validator = Class.create({ }, removeDangerousElements: function(element) { - var scripts = $A(element.getElementsByTagName('SCRIPT')).reverse(); + var scripts = xq.$A(element.getElementsByTagName('SCRIPT')).reverse(); for(var i = 0; i < scripts.length; i++) { scripts[i].parentNode.removeChild(scripts[i]); } @@ -6370,7 +6686,7 @@ xq.Validator.createInstance = function(curUrl, urlValidationMode, allowedTags, a /** * Validator for W3C Standard Engine */ -xq.ValidatorW3 = Class.create(xq.Validator, { +xq.ValidatorW3 = xq.Class(xq.Validator, { validate: function(element, fullValidation) { element = element.cloneNode(true); @@ -6405,15 +6721,15 @@ xq.ValidatorW3 = Class.create(xq.Validator, { rdom.setRoot(element); // -> - var strikes = rdom.findByAttribute("class", "strike"); + var strikes = xq.getElementsByClassName(rdom.getRoot(), "strike"); for(var i = 0; i < strikes.length; i++) { if("SPAN" == strikes[i].nodeName) rdom.replaceTag("strike", strikes[i]).removeAttribute("class"); } // -> - var underlines = rdom.findByAttribute("class", "underline"); + var underlines = xq.getElementsByClassName(rdom.getRoot(), "underline"); for(var i = 0; i < underlines.length; i++) { - if(["EM", "I"].include(underlines[i].nodeName)) rdom.replaceTag("u", underlines[i]).removeAttribute("class"); + if(["EM", "I"].indexOf(underlines[i].nodeName) != -1) rdom.replaceTag("u", underlines[i]).removeAttribute("class"); } var content = rdom.getRoot().innerHTML; @@ -6445,7 +6761,7 @@ xq.ValidatorW3 = Class.create(xq.Validator, { var rdom = xq.RichDom.createInstance(); rdom.setRoot(element); - var fonts = $A(element.getElementsByTagName('FONT')).reverse(); + var fonts = xq.$A(element.getElementsByTagName('FONT')).reverse(); for(var i = 0; i < fonts.length; i++) { var font = fonts[i]; var color = font.getAttribute('color'); @@ -6474,12 +6790,12 @@ xq.ValidatorW3 = Class.create(xq.Validator, { /** * Validator for Gecko Engine */ -xq.ValidatorGecko = Class.create(xq.ValidatorW3, { +xq.ValidatorGecko = xq.Class(xq.ValidatorW3, { }); /** * Validator for Webkit */ -xq.ValidatorWebkit = Class.create(xq.ValidatorW3, { +xq.ValidatorWebkit = xq.Class(xq.ValidatorW3, { }); /* @@ -6493,7 +6809,7 @@ if(node.nodeName == "SPAN" && node.className == "Apple-style-span" && node.style /** * Validator for Internet Explorer 6 and 7 */ -xq.ValidatorTrident = Class.create(xq.Validator, { +xq.ValidatorTrident = xq.Class(xq.Validator, { validate: function(element, fullValidation) { element = element.cloneNode(true); @@ -6521,15 +6837,15 @@ xq.ValidatorTrident = Class.create(xq.Validator, { this.invalidateBackgroundColor(element); // -> - var strikes = rdom.findByAttribute("className", "strike"); + var strikes = xq.getElementsByClassName(rdom.getRoot(), "strike"); for(var i = 0; i < strikes.length; i++) { if("SPAN" == strikes[i].nodeName) rdom.replaceTag("strike", strikes[i]).removeAttribute("className"); } // -> - var underlines = rdom.findByAttribute("className", "underline"); + var underlines = xq.getElementsByClassName(rdom.getRoot(), "underline"); for(var i = 0; i < underlines.length; i++) { - if(["EM", "I"].include(underlines[i].nodeName)) rdom.replaceTag("u", underlines[i]).removeAttribute("className"); + if(["EM", "I"].indexOf(underlines[i].nodeName) != -1) rdom.replaceTag("u", underlines[i]).removeAttribute("className"); } var content = rdom.getRoot().innerHTML; @@ -6562,7 +6878,7 @@ xq.ValidatorTrident = Class.create(xq.Validator, { rdom.setRoot(element); // It should be reversed to deal with nested elements - var fonts = $A(element.getElementsByTagName('FONT')).reverse(); + var fonts = xq.$A(element.getElementsByTagName('FONT')).reverse(); for(var i = 0; i < fonts.length; i++) { var font = fonts[i]; var color = font.getAttribute('color'); @@ -6579,7 +6895,7 @@ xq.ValidatorTrident = Class.create(xq.Validator, { var rdom = xq.RichDom.createInstance(); rdom.setRoot(element); - var spans = $A(element.getElementsByTagName('SPAN')).reverse(); + var spans = xq.$A(element.getElementsByTagName('SPAN')).reverse(); for(var i = 0; i < spans.length; i++) { var span = spans[i]; var color = span.style.color; @@ -6597,7 +6913,7 @@ xq.ValidatorTrident = Class.create(xq.Validator, { rdom.setRoot(element); // It should be reversed to deal with nested elements - var fonts = $A(element.getElementsByTagName('FONT')).reverse(); + var fonts = xq.$A(element.getElementsByTagName('FONT')).reverse(); for(var i = 0; i < fonts.length; i++) { if(fonts[i].style.color || fonts[i].style.backgroundColor) rdom.replaceTag("span", fonts[i]); } @@ -6608,7 +6924,7 @@ xq.ValidatorTrident = Class.create(xq.Validator, { rdom.setRoot(element); // It should be reversed to deal with nested elements - var spans = $A(element.getElementsByTagName('SPAN')).reverse(); + var spans = xq.$A(element.getElementsByTagName('SPAN')).reverse(); for(var i = 0; i < spans.length; i++) { if(spans[i].style.color || spans[i].style.backgroundColor) rdom.replaceTag("font", spans[i]); } @@ -6632,7 +6948,7 @@ xq.ValidatorTrident = Class.create(xq.Validator, { /** * @fileOverview xq.EditHistory manages editing history and performs UNDO/REDO. */ -xq.EditHistory = Class.create({ +xq.EditHistory = xq.Class({ /** * Initializer * @@ -6641,6 +6957,7 @@ xq.EditHistory = Class.create({ * @param {Number} [max] maximum UNDO buffer size(default value is 100). */ initialize: function(rdom, max) { + xq.addToFinalizeQueue(this); if (!rdom) throw "IllegalArgumentException"; this.disabled = false; @@ -6698,11 +7015,11 @@ xq.EditHistory = Class.create({ // ignore normal keys if('keydown' == event.type && !(event.ctrlKey || event.metaKey)) return false; - if(['keydown', 'keyup', 'keypress'].include(event.type) && !event.ctrlKey && !event.altKey && !event.metaKey && ![33,34,35,36,37,38,39,40].include(event.keyCode)) return false; - if(['keydown', 'keyup', 'keypress'].include(event.type) && (event.ctrlKey || event.metaKey) && [89,90].include(event.keyCode)) return false; + if(['keydown', 'keyup', 'keypress'].indexOf(event.type) != -1 && !event.ctrlKey && !event.altKey && !event.metaKey && [33,34,35,36,37,38,39,40].indexOf(event.keyCode) == -1) return false; + if(['keydown', 'keyup', 'keypress'].indexOf(event.type) != -1 && (event.ctrlKey || event.metaKey) && [89,90].indexOf(event.keyCode) != -1) return false; // ignore ctrl/shift/alt/meta keys - if([16,17,18,224].include(event.keyCode)) return false; + if([16,17,18,224].indexOf(event.keyCode) != -1) return false; return this.pushContent(); }, @@ -6791,7 +7108,7 @@ xq.controls = {}; -xq.controls.FormDialog = Class.create({ +xq.controls.FormDialog = xq.Class({ /** * @constructor * @@ -6799,6 +7116,8 @@ xq.controls.FormDialog = Class.create({ * @param {Function} [onLoadHandler] callback function to be called when the form is loaded */ initialize: function(xed, html, onLoadHandler, onCloseHandler) { + xq.addToFinalizeQueue(this); + this.xed = xed; this.html = html; this.onLoadHandler = onLoadHandler || function() {}; @@ -6819,21 +7138,21 @@ xq.controls.FormDialog = Class.create({ var self = this; // create and append container - var container = $(document.createElement('DIV')); + var container = document.createElement('DIV'); container.style.display = 'none'; document.body.appendChild(container); // initialize form container.innerHTML = this.html; - this.form = $(container.getElementsByTagName('FORM')[0]); + this.form = container.getElementsByTagName('FORM')[0]; this.form.onsubmit = function() { - self.onCloseHandler($(this).serialize(true)); + self.onCloseHandler(xq.serializeForm(this)); self.close(); return false; }; - var cancelButton = this.form.getElementsByClassName('cancel')[0]; + var cancelButton = xq.getElementsByClassName(this.form, 'cancel')[0]; cancelButton.onclick = function() { self.onCloseHandler(); self.close(); @@ -6847,12 +7166,12 @@ xq.controls.FormDialog = Class.create({ this.setPosition(options.position); // give focus - var elementToFocus = this.form.getElementsByClassName('initialFocus'); + var elementToFocus = xq.getElementsByClassName(this.form, 'initialFocus'); if(elementToFocus.length > 0) elementToFocus[0].focus(); // handle cancelOnEsc option if(options.cancelOnEsc) { - Event.observe(this.form, 'keydown', function(e) { + xq.observe(this.form, 'keydown', function(e) { if(e.keyCode == 27) { this.onCloseHandler(); this.close(); @@ -6863,24 +7182,25 @@ xq.controls.FormDialog = Class.create({ this.onLoadHandler(this); }, + close: function() { this.form.parentNode.removeChild(this.form); }, + setPosition: function(target) { - var targetElement; - var curleft = curtop = 0; + var targetElement = null; + var left = 0; + var top = 0; if(target == 'centerOfWindow') { targetElement = document.documentElement; } else if(target == 'centerOfEditor') { targetElement = this.xed.getFrame(); - var obj = targetElement; - while( obj.offsetParent ) - { - curleft += obj.offsetLeft; - curtop += obj.offsetTop; - obj = obj.offsetParent; - } + var o = targetElement; + do { + left += o.offsetLeft; + top += o.offsetTop; + } while(o = o.offsetParent) } else if(target == 'nearbyCaret') { throw "Not implemented yet"; } else { @@ -6892,21 +7212,22 @@ xq.controls.FormDialog = Class.create({ var dialogWidth = this.form.clientWidth; var dialogHeight = this.form.clientHeight; - var x = curleft + parseInt((targetWidth - dialogWidth) / 2); - var y = curtop + parseInt((targetHeight - dialogHeight) / 2); + left += parseInt((targetWidth - dialogWidth) / 2); + top += parseInt((targetHeight - dialogHeight) / 2); - this.form.style.left = x + "px"; - this.form.style.top = y + "px"; + this.form.style.left = left + "px"; + this.form.style.top = top + "px"; } }) -xq.controls.QuickSearchDialog = Class.create({ +xq.controls.QuickSearchDialog = xq.Class({ /** * @constructor */ initialize: function(xed, param) { + xq.addToFinalizeQueue(this); this.xed = xed; this.rdom = xq.RichDom.createInstance(); @@ -6931,7 +7252,7 @@ xq.controls.QuickSearchDialog = Class.create({ } this.close(); - Event.stop(e); + xq.stopEvent(e); return false; }, @@ -7018,12 +7339,19 @@ xq.controls.QuickSearchDialog = Class.create({ }, setPosition: function(target) { - var targetElement; + var targetElement = null; + var left = 0; + var top = 0; if(target == 'centerOfWindow') { targetElement = document.documentElement; } else if(target == 'centerOfEditor') { - targetElement = this.xed.getDoc().documentElement; + targetElement = this.xed.getFrame(); + var o = targetElement; + do { + left += o.offsetLeft; + top += o.offsetTop; + } while(o = o.offsetParent) } else if(target == 'nearbyCaret') { throw "Not implemented yet"; } else { @@ -7035,10 +7363,11 @@ xq.controls.QuickSearchDialog = Class.create({ var dialogWidth = this.container.clientWidth; var dialogHeight = this.container.clientHeight; - var x = parseInt((targetWidth - dialogWidth) / 2); - var y = parseInt((targetHeight - dialogHeight) / 2); - this.container.style.left = x + "px"; - this.container.style.top = y + "px"; + left += parseInt((targetWidth - dialogWidth) / 2); + top += parseInt((targetHeight - dialogHeight) / 2); + + this.container.style.left = left + "px"; + this.container.style.top = top + "px"; }, matchCount: function() { @@ -7071,11 +7400,11 @@ xq.controls.QuickSearchDialog = Class.create({ // make list var list = this.rdom.createElement("OL"); - Event.observe(input, 'blur', this.onBlur.bindAsEventListener(this)); - Event.observe(input, 'keypress', this.onKey.bindAsEventListener(this)); - Event.observe(list, 'click', this.onClick.bindAsEventListener(this), true); - Event.observe(form, 'submit', this.onSubmit.bindAsEventListener(this)); - Event.observe(form, 'reset', this.onCancel.bindAsEventListener(this)); + xq.observe(input, 'blur', this.onBlur.bindAsEventListener(this)); + xq.observe(input, 'keypress', this.onKey.bindAsEventListener(this)); + xq.observe(list, 'click', this.onClick.bindAsEventListener(this), true); + xq.observe(form, 'submit', this.onSubmit.bindAsEventListener(this)); + xq.observe(form, 'reset', this.onCancel.bindAsEventListener(this)); container.appendChild(list); return container; @@ -7122,7 +7451,7 @@ xq.controls.QuickSearchDialog = Class.create({ var index = this._getSelectedIndex(); var ol = this._getListContainer(); ol.childNodes[index].className = ""; - + index++; if(index >= count) index = 0; From ecebb4192dbcaf91708c61b6ff32dddeaa793e07 Mon Sep 17 00:00:00 2001 From: zero Date: Thu, 6 Dec 2007 05:38:30 +0000 Subject: [PATCH 137/265] =?UTF-8?q?#298.=20=EC=B5=9C=EA=B7=BC=EA=B8=80/?= =?UTF-8?q?=EC=9B=B9=EC=A7=84=ED=98=95=20=EC=9C=84=EC=A0=AF=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EB=8C=80=EC=83=81=20=EA=B8=80=EC=9D=B4=201?= =?UTF-8?q?=EA=B0=9C=EC=9D=BC=20=EA=B2=BD=EC=9A=B0=20=EC=98=A4=EB=A5=98?= =?UTF-8?q?=EA=B0=80=20=EB=82=98=EB=8A=94=20=EB=B6=80=EB=B6=84=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3161 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- .htaccess | 3 --- widgets/newest_document/newest_document.class.php | 2 +- widgets/webzine/webzine.class.php | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.htaccess b/.htaccess index 04b152121..00ca00909 100644 --- a/.htaccess +++ b/.htaccess @@ -54,6 +54,3 @@ RewriteRule ^([a-zA-Z0-9_]+)/writer/(.*)$ ./index.php?mid=$1&search_target=nick_ # module link RewriteRule ^([a-zA-Z0-9_]+)(/){0,1}$ ./index.php?mid=$1 [L] - -# css/img/js/htc등의 경로 처리 -RewriteRule ^(.+)/common/js/iePngFix.htc ./common/js/iePngFix.htc [L] diff --git a/widgets/newest_document/newest_document.class.php b/widgets/newest_document/newest_document.class.php index edcf7bbb0..13b5e7286 100644 --- a/widgets/newest_document/newest_document.class.php +++ b/widgets/newest_document/newest_document.class.php @@ -54,7 +54,7 @@ $obj->order_type = $order_type=="desc"?"asc":"desc"; $obj->list_count = $list_count; - $output = executeQuery('widgets.newest_document.getNewestDocuments', $obj); + $output = executeQueryArray('widgets.newest_document.getNewestDocuments', $obj); // document 모듈의 model 객체를 받아서 결과를 객체화 시킴 $oDocumentModel = &getModel('document'); diff --git a/widgets/webzine/webzine.class.php b/widgets/webzine/webzine.class.php index 472912903..e94797d8e 100644 --- a/widgets/webzine/webzine.class.php +++ b/widgets/webzine/webzine.class.php @@ -74,7 +74,7 @@ $obj->isvalid = 'Y'; // 정해진 모듈에서 문서별 파일 목록을 구함 - $files_output = executeQuery("file.getOneFileInDocument", $obj); + $files_output = executeQueryArray("file.getOneFileInDocument", $obj); $oDocumentModel = &getModel('document'); if(count($files_output->data)) { From c870c7a1948eb99df021e68e053001c687773eba Mon Sep 17 00:00:00 2001 From: zero Date: Thu, 6 Dec 2007 05:43:30 +0000 Subject: [PATCH 138/265] =?UTF-8?q?#295=20=EC=9D=B4=EB=AA=A8=ED=8B=B0?= =?UTF-8?q?=EC=BD=98=20=EB=AA=A9=EB=A1=9D=20=EC=B6=94=EC=B6=9C=EC=8B=9C=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=EC=9D=B4=EB=A6=84=20=EC=88=9C=20=EC=A0=95?= =?UTF-8?q?=EB=A0=AC=EC=9D=84=20=ED=95=98=EC=97=AC=20=EB=85=B8=EC=B6=9C?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3162 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/editor/components/emoticon/emoticon.class.php | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/editor/components/emoticon/emoticon.class.php b/modules/editor/components/emoticon/emoticon.class.php index ed001b225..608be572a 100644 --- a/modules/editor/components/emoticon/emoticon.class.php +++ b/modules/editor/components/emoticon/emoticon.class.php @@ -46,6 +46,7 @@ if(eregi('\.(jpg|jpeg|gif|png)$',$file)) $output[] = sprintf("%s/%s", $path, str_replace($this->emoticon_path,'',$file)); } $oDir->close(); + if(count($output)) asort($output); return $output; } From f63c58674a5ae1f740a2e7904e68da2a41822abf Mon Sep 17 00:00:00 2001 From: zero Date: Thu, 6 Dec 2007 07:06:08 +0000 Subject: [PATCH 139/265] =?UTF-8?q?#291=20=EC=9B=B9=EC=A7=84=ED=98=95=20?= =?UTF-8?q?=EC=9C=84=EC=A0=AF=EC=9D=98=20=EC=A0=95=EB=A0=AC=20=EC=88=9C?= =?UTF-8?q?=EC=84=9C=EA=B0=80=20=EC=A0=81=EC=9A=A9=EB=90=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=ED=96=88=EA=B3=A0=20=EC=9D=B4=EB=AF=B8=EC=A7=80?= =?UTF-8?q?=EA=B0=80=20=EC=97=86=EB=8D=94=EB=9D=BC=EB=8F=84=20=EB=85=B8?= =?UTF-8?q?=EC=B6=9C=EC=9D=B4=20=EB=90=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3163 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- .../webzine/skins/xe_official/css/normal.css | 2 +- widgets/webzine/skins/xe_official/list.html | 7 ++- widgets/webzine/webzine.class.php | 48 +++++++++++++------ 3 files changed, 40 insertions(+), 17 deletions(-) diff --git a/widgets/webzine/skins/xe_official/css/normal.css b/widgets/webzine/skins/xe_official/css/normal.css index 13cf54ef6..2953f356e 100644 --- a/widgets/webzine/skins/xe_official/css/normal.css +++ b/widgets/webzine/skins/xe_official/css/normal.css @@ -15,7 +15,7 @@ .nw_box .thumbnailBox .thumbnail img { padding:4px; border:1px solid #DEDEDE; } .nw_box .thumbnailBox .thumbnail img:hover { border:1px solid #54564b; } -.nw_box .thumbnailBox .desc { padding-left:5px; } +.nw_box .thumbnailBox .desc { padding-left:5px; padding-bottom:5px; } .nw_box .thumbnailBox .titleBox { margin-top:8px; margin-bottom:5px;} diff --git a/widgets/webzine/skins/xe_official/list.html b/widgets/webzine/skins/xe_official/list.html index 36ab6e583..85dd80802 100644 --- a/widgets/webzine/skins/xe_official/list.html +++ b/widgets/webzine/skins/xe_official/list.html @@ -17,14 +17,17 @@ {@ $oDocument = $widget_info->document_list[$i*$widget_info->cols_list_count + $j]} + {@ $_existsThumbnail = $oDocument->thumbnailExists($widget_info->thumbnail_width,$widget_info->thumbnail_height,$widget_info->thumbnail_type) }
      rows_list_count>1)-->class="bottomBorder"> + + - - +
      +
      diff --git a/widgets/webzine/webzine.class.php b/widgets/webzine/webzine.class.php index e94797d8e..863a15fb3 100644 --- a/widgets/webzine/webzine.class.php +++ b/widgets/webzine/webzine.class.php @@ -43,6 +43,15 @@ $widget_info->cols_list_count = (int)$args->cols_list_count; if(!$widget_info->cols_list_count) $widget_info->cols_list_count = 2; + // 정렬 대상 + $widget_info->order_target = $args->order_target; + if(!in_array($widget_info->order_target, array('list_order','update_order'))) $widget_info->order_target = 'list_order'; + + // 정렬 순서 + $widget_info->order_type = $args->order_type; + if(!in_array($widget_info->order_type, array('asc','desc'))) $widget_info->order_type = 'asc'; + + // 노출 여부 체크 if($args->display_author!='Y') $widget_info->display_author = 'N'; else $widget_info->display_author = 'Y'; @@ -62,29 +71,40 @@ // 템플릿 파일에서 사용할 변수들을 세팅 if(count($mid_list)==1) $widget_info->module_name = $mid_list[0]; - // 변수 정리 - $obj->list_count = $widget_info->rows_list_count * $widget_info->cols_list_count; - // mid에 해당하는 module_srl을 구함 $oModuleModel = &getModel('module'); $module_srl_list = $oModuleModel->getModuleSrlByMid($mid_list); - if(is_array($module_srl_list)) $obj->module_srls = implode(",",$module_srl_list); - else $obj->module_srls = $module_srl_list; - $obj->direct_download = 'Y'; - $obj->isvalid = 'Y'; + if(is_array($module_srl_list)) $obj->module_srl = implode(",",$module_srl_list); + else $obj->module_srl = $module_srl_list; + $obj->sort_index = $widget_info->order_target; + $obj->order_type = $widget_info->order_type=="desc"?"asc":"desc"; + $obj->list_count = $widget_info->rows_list_count * $widget_info->cols_list_count; - // 정해진 모듈에서 문서별 파일 목록을 구함 - $files_output = executeQueryArray("file.getOneFileInDocument", $obj); + $output = executeQueryArray('widgets.newest_document.getNewestDocuments', $obj); + // document 모듈의 model 객체를 받아서 결과를 객체화 시킴 $oDocumentModel = &getModel('document'); - if(count($files_output->data)) { - foreach($files_output->data as $key => $val) { + + // 오류가 생기면 그냥 무시 + if(!$output->toBool()) return; + + // 결과가 있으면 각 문서 객체화를 시킴 + if(count($output->data)) { + foreach($output->data as $key => $attribute) { + $document_srl = $attribute->document_srl; + $oDocument = null; - $oDocument = $oDocumentModel->getDocument(); - $oDocument->setAttribute($val); - $document_list[] = $oDocument; + $oDocument = new documentItem(); + $oDocument->setAttribute($attribute); + + $document_list[$key] = $oDocument; } + } else { + + $document_list = array(); + } + $document_count = count($document_list); $total_count = $widget_info->rows_list_count * $widget_info->cols_list_count; for($i=$document_count;$i<$total_count;$i++) $document_list[] = new DocumentItem(); From 2b093411dadf9552e47f6604788b43fa0c4445bb Mon Sep 17 00:00:00 2001 From: supershop Date: Thu, 6 Dec 2007 13:02:56 +0000 Subject: [PATCH 140/265] =?UTF-8?q?=EC=98=81=EC=96=B4=20-=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B2=88=EC=97=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3164 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- widgets/rank_count/conf/info.xml | 3 +++ widgets/rank_count/skins/sz_xe/skin.xml | 15 +++++++++++++++ widgets/rank_download/conf/info.xml | 18 ++++++++++++++++++ widgets/rank_download/skins/sz_xe/skin.xml | 15 +++++++++++++++ widgets/rank_point/conf/info.xml | 17 ++++++++++++++++- widgets/rank_point/skins/sz_xe/skin.xml | 17 ++++++++++++++++- widgets/rss_reader/conf/info.xml | 8 ++++---- widgets/rss_reader/skins/sz_select/skin.xml | 15 +++++++++++++++ widgets/rss_reader/skins/sz_xe/skin.xml | 15 +++++++++++++++ widgets/rss_reader/skins/xe_select/skin.xml | 5 +++++ 10 files changed, 122 insertions(+), 6 deletions(-) diff --git a/widgets/rank_count/conf/info.xml b/widgets/rank_count/conf/info.xml index e24498783..c1a2db1d5 100644 --- a/widgets/rank_count/conf/info.xml +++ b/widgets/rank_count/conf/info.xml @@ -1,11 +1,14 @@ 글, 댓글 랭킹 출력 + Article, Comment Ranking 输出主题, 评论排行 Simulz + Simulz Simulz 글, 댓글 작성 순위를 출력합니다. + This widget displays articles and comments ranking. 输出主题, 内容排行. diff --git a/widgets/rank_count/skins/sz_xe/skin.xml b/widgets/rank_count/skins/sz_xe/skin.xml index 37f389eec..93f4a5947 100644 --- a/widgets/rank_count/skins/sz_xe/skin.xml +++ b/widgets/rank_count/skins/sz_xe/skin.xml @@ -2,56 +2,71 @@ Simulz 랭킹 스킨 Simulz 排行皮肤 + Simulz Ranking Skin Simulz Simulz + Simulz Simulz 랭킹 스킨입니다. Simulz 排行皮肤. + + + This is Simulz ranking skin. 기본 默认 + Default 회색 灰色 + Gray 연두 淡绿 + Yellowish Green 분홍 粉红 + Pink 보라 淡青 + Purple 밝은 파랑 浅蓝 + Bright Blue 청록 青绿 + Bluish Green 초록 草绿 + Green 노랑 黄色 + Yellow 파랑 蓝色 + Blue diff --git a/widgets/rank_download/conf/info.xml b/widgets/rank_download/conf/info.xml index 91764c48c..5b28a3034 100644 --- a/widgets/rank_download/conf/info.xml +++ b/widgets/rank_download/conf/info.xml @@ -1,72 +1,90 @@ 다운로드 랭킹 출력 + Download Ranking 输出下载排行 Simulz + Simulz Simulz 자료 내려받기 순위를 출력합니다. + This widget displays download ranking. 输出下载文件顺位. 제목 + Title 主题 text 위젯의 제목으로 출력됩니다. + It will be displayed as widget's title. 输出控件的主题. 목록수 + No. of List 目录数 text 출력될 목록의 수를 정하실 수 있습니다. (기본 5개) + You may set number of list that will be displayed. (default 5) 可以指定将输出的目录数.(默认 5个) 파일 종류 + File Type 文件类型 select 순위에 포함할 파일 종류를 선택하세요. + Please select file type to include. 请选择输出目录中要包涵的文件类型. 모두 + All 全部 all 이미지 제외 + Exclude Images 图片除外 noimage 이미지만 + Images Only 只输出图片类 image 내려 받기 + Download 显示下载链接 select 바로 내려 받는 링크를 보여줍니다. + It shows direct download link. 显示直接下载链接 링크 보임 + Show Link 显示连接 Y 링크 숨김 + Hide Link 隐藏链接 N 대상 모듈 + Target Module 对象模块 mid_list 선택하신 모듈에 등록된 글을 대상으로 합니다. + Articles in selected module will be target. 被选中的模块将输出. diff --git a/widgets/rank_download/skins/sz_xe/skin.xml b/widgets/rank_download/skins/sz_xe/skin.xml index 04dc0706f..9423c0bb4 100644 --- a/widgets/rank_download/skins/sz_xe/skin.xml +++ b/widgets/rank_download/skins/sz_xe/skin.xml @@ -1,12 +1,17 @@ Simulz 랭킹 스킨 + Simulz Ranking Skin Simulz 排行皮肤 Simulz + Simulz Simulz Simulz 랭킹 스킨입니다. + + + This is Simulz Ranking Skin. Simulz 排行皮肤 @@ -15,42 +20,52 @@ 기본 + Default 默认 회색 + Gray 灰色 연두 + Yellowish Green 淡绿 분홍 + Pink 粉红 보라 + Purple 淡青 밝은 파랑 + Bright Blue 浅蓝 청록 + Bluish Green 青绿 초록 + Green 草绿 노랑 + Yellow 黄色 파랑 + Blue 蓝色 diff --git a/widgets/rank_point/conf/info.xml b/widgets/rank_point/conf/info.xml index 0b4fcf7f6..a3fe5397d 100644 --- a/widgets/rank_point/conf/info.xml +++ b/widgets/rank_point/conf/info.xml @@ -1,58 +1,73 @@ 포인트 랭킹 출력 + Display Point Ranking 输出积分排行 Simulz + Simulz Simulz 회원의 포인트 순위를 출력합니다. + This widget displays members' point ranking. 输出会员积分排行. 제목 + Title 主题 text 위젯의 제목으로 출력됩니다. + It will be displayed as widget's title. 输出控件的主题. 목록수 + No. of List 目录数 text 출력될 목록의 수를 정하실 수 있습니다. (기본 5개) + You may set number of list that will be displayed. (default 5) 可以指定要输出的目录数. (默认 5个) 관리자 + Administrator 管理员 select 순위에 관리자를 포함합니다. + Administrators will be also ranked. 在排行显示管理员. 포함 + Include 显示 false 미포함 + Exclude 不显示 true 그룹 포함 + Include Group 包括组 text 출력할 회원 그룹명을 입력하세요. 예)준회원,정회원 + Please input name of group to include. ex) Associate, Regular Group 请输入要输出的会员组. 例)准会员,正会员 그룹 제외 + Exclude Group 组除外 text 제외할 회원 그룹명을 입력하세요. 예)관리그룹,정회원 - 请输入要不包括的用户组. 例)管理组,正会员 + Please input name of group to exclude. ex) Managing, Regular Group + 请输入要不包括的用户组. 例)管理组,正会员 diff --git a/widgets/rank_point/skins/sz_xe/skin.xml b/widgets/rank_point/skins/sz_xe/skin.xml index 76a954832..656290a40 100644 --- a/widgets/rank_point/skins/sz_xe/skin.xml +++ b/widgets/rank_point/skins/sz_xe/skin.xml @@ -1,14 +1,19 @@ Simulz 포인트 랭킹 스킨 + Simulz Point Ranking Skin Simulz 积分排行皮肤 Simulz + Simulz Simulz Simulz 포인트 랭킹 스킨입니다. - + + This is Simulz Point Ranking Skin. + + Simulz 积分排行皮肤. @@ -16,42 +21,52 @@ 기본 + Default 默认 회색 + Gray 灰色 연두 + Yellowish Green 淡绿 분홍 + Pink 粉红 보라 + Purple 淡青 밝은 파랑 + Bright Blue 浅蓝 청록 + Bluish Green 青绿 초록 + Green 草绿 노랑 + Yellow 黄色 파랑 + Blue 蓝色 diff --git a/widgets/rss_reader/conf/info.xml b/widgets/rss_reader/conf/info.xml index b5a7a0780..44cd91a4e 100644 --- a/widgets/rss_reader/conf/info.xml +++ b/widgets/rss_reader/conf/info.xml @@ -33,11 +33,11 @@ 페이지 수 页面数 - number of pages + Number of Pages text 기본 값 10 默认数 10 - default 10 + Default: 10 날짜 형식 @@ -46,7 +46,7 @@ text 기본 값 Y-m-d H:i:s 默认值 Y-m-d H:i:s - Default Y-m-d H:i:s + Default: Y-m-d H:i:s 본문 높이 @@ -55,7 +55,7 @@ text select 스킨에서 본문 높이 (기본값 200px) 在select皮肤文本高度 (默认值 200px) - + Height of select skin (default: 200px) diff --git a/widgets/rss_reader/skins/sz_select/skin.xml b/widgets/rss_reader/skins/sz_select/skin.xml index 89cd5c635..e031b2447 100644 --- a/widgets/rss_reader/skins/sz_select/skin.xml +++ b/widgets/rss_reader/skins/sz_select/skin.xml @@ -2,56 +2,71 @@ Simulz 스킨 (Select 메뉴) Simulz 皮肤 (Select 菜单) + Simulz Skin (Select menu) Simulz Simulz + Simulz Simulz 스킨입니다. Simulz 皮肤. + + + This is Simulz skin. 기본 默认 + Default 회색 灰色 + Gray 연두 淡绿 + Yellowish Green 분홍 粉红 + Pink 보라 淡青 + Purple 밝은 파랑 浅蓝 + Bright Blue 청록 青绿 + Bluish Green 초록 草绿 + Green 노랑 黄色 + Yellow 파랑 蓝色 + Blue diff --git a/widgets/rss_reader/skins/sz_xe/skin.xml b/widgets/rss_reader/skins/sz_xe/skin.xml index baad7e274..a77184fff 100644 --- a/widgets/rss_reader/skins/sz_xe/skin.xml +++ b/widgets/rss_reader/skins/sz_xe/skin.xml @@ -2,56 +2,71 @@ Simulz 스킨 (목록형) Simulz 皮肤(目录型) + Simulz Skin (List Style) Simulz Simulz + Simulz Simulz 스킨입니다. Simulz 皮肤. + + + This is Simulz skin. 기본 默认 + Default 회색 灰色 + Gray 연두 淡绿 + Yellowish Green 분홍 粉红 + Pink 보라 淡青 + Purple 밝은 파랑 浅蓝 + Bright Blue 청록 青绿 + Bluish Green 초록 草绿 + Green 노랑 黄色 + Yellow 파랑 蓝色 + Blue diff --git a/widgets/rss_reader/skins/xe_select/skin.xml b/widgets/rss_reader/skins/xe_select/skin.xml index 09aa87a88..b16401fdb 100644 --- a/widgets/rss_reader/skins/xe_select/skin.xml +++ b/widgets/rss_reader/skins/xe_select/skin.xml @@ -2,14 +2,19 @@ XE 최신글 스킨 (Select 메뉴) XE 最新主题皮肤 (Select 菜单) + XE Newest Article Skin (Select menu) Simulz Simulz + Simulz XE 공식 레이아웃에 적합한 최신글 스킨입니다. 适合XE 官方网站的主题列表. + + + This is a newest article skin that is suitable for XE official layout. From 6cd90d5645a6c94ec8387090094fd88717d6eaf1 Mon Sep 17 00:00:00 2001 From: risapapa Date: Thu, 6 Dec 2007 16:00:26 +0000 Subject: [PATCH 141/265] Corrected Japanese translation. git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3165 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- addons/google_analytics/conf/info.xml | 2 +- addons/referer/conf/info.xml | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/addons/google_analytics/conf/info.xml b/addons/google_analytics/conf/info.xml index edcfbcf0f..9d7e3f2f2 100644 --- a/addons/google_analytics/conf/info.xml +++ b/addons/google_analytics/conf/info.xml @@ -22,7 +22,7 @@ uacct uacct Google Analytics 코드의 _uacct 값을 입력해주세요. - Google Analytics コードの値を入力してください。 + Google Analytics コードの「uacct」値を入力してください。 请输入Google Analytics代码的_uacct值。 diff --git a/addons/referer/conf/info.xml b/addons/referer/conf/info.xml index e35408d53..712f55708 100644 --- a/addons/referer/conf/info.xml +++ b/addons/referer/conf/info.xml @@ -1,13 +1,18 @@ 리퍼러 수집기 + リファラー コレクター Referer Collector haneul + Haneul haneul Referer log를 수집합니다. + + リファラーログを収集します。 + Collect referer log and statistics. From 098bb606a60eb97c64f148f1633477b6e7ee15de Mon Sep 17 00:00:00 2001 From: mayoojin Date: Thu, 6 Dec 2007 16:54:29 +0000 Subject: [PATCH 142/265] git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3166 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- addons/blogapi/conf/info.xml | 12 +- addons/counter/conf/info.xml | 8 +- addons/google_analytics/conf/info.xml | 23 ++-- addons/member_extra_info/conf/info.xml | 18 ++- addons/member_extra_info/lang/ru.lang.php | 2 +- addons/openid_delegation_id/conf/info.xml | 16 ++- addons/point/conf/info.xml | 9 +- addons/point_level_icon/conf/info.xml | 10 +- addons/spamfilter/conf/info.xml | 11 +- common/lang/ru.lang.php | 88 +++++++------- modules/addon/conf/info.xml | 3 + modules/admin/conf/info.xml | 3 + modules/admin/lang/ru.lang.php | 70 ++++++------ modules/blog/conf/info.xml | 11 +- modules/blog/lang/ru.lang.php | 6 +- modules/board/conf/info.xml | 3 + modules/comment/conf/info.xml | 3 + modules/comment/lang/ru.lang.php | 4 +- modules/counter/conf/info.xml | 5 +- modules/counter/lang/ru.lang.php | 2 +- modules/document/conf/info.xml | 9 +- modules/document/lang/ru.lang.php | 12 +- modules/editor/conf/info.xml | 9 +- modules/editor/lang/ru.lang.php | 10 +- modules/file/conf/info.xml | 5 +- modules/guestbook/conf/info.xml | 5 +- modules/guestbook/lang/ru.lang.php | 8 +- modules/importer/conf/info.xml | 5 +- modules/install/conf/info.xml | 5 +- modules/install/lang/ru.lang.php | 28 ++--- modules/integration_search/conf/info.xml | 8 +- modules/integration_search/lang/ru.lang.php | 12 +- modules/krzip/conf/info.xml | 8 +- modules/krzip/lang/ru.lang.php | 2 +- modules/layout/conf/info.xml | 5 +- modules/layout/lang/ru.lang.php | 16 +-- modules/member/conf/info.xml | 3 + modules/member/lang/ru.lang.php | 120 ++++++++++---------- modules/menu/conf/info.xml | 3 + modules/message/conf/info.xml | 7 +- modules/module/conf/info.xml | 3 + modules/module/lang/ru.lang.php | 40 +++---- modules/opage/conf/info.xml | 11 +- modules/opage/lang/ru.lang.php | 6 +- modules/page/conf/info.xml | 3 + modules/point/conf/info.xml | 9 +- modules/point/lang/ru.lang.php | 32 +++--- modules/poll/conf/info.xml | 5 +- modules/poll/lang/ru.lang.php | 2 +- modules/referer/conf/info.xml | 3 + modules/referer/lang/ru.lang.php | 10 ++ modules/rss/conf/info.xml | 7 +- modules/spamfilter/conf/info.xml | 3 + modules/spamfilter/lang/ru.lang.php | 4 +- modules/springnote/conf/info.xml | 3 + modules/springnote/lang/ru.lang.php | 24 ++++ modules/tag/conf/info.xml | 9 +- modules/trackback/conf/info.xml | 11 +- modules/trackback/lang/ru.lang.php | 6 +- modules/ttimporter/conf/info.xml | 38 +++++++ modules/ttimporter/lang/ru.lang.php | 21 ++++ modules/widget/conf/info.xml | 9 +- modules/widget/lang/ru.lang.php | 24 ++-- 63 files changed, 565 insertions(+), 305 deletions(-) create mode 100644 modules/referer/lang/ru.lang.php create mode 100644 modules/springnote/lang/ru.lang.php create mode 100644 modules/ttimporter/conf/info.xml create mode 100644 modules/ttimporter/lang/ru.lang.php diff --git a/addons/blogapi/conf/info.xml b/addons/blogapi/conf/info.xml index 65006e489..8903dcf33 100644 --- a/addons/blogapi/conf/info.xml +++ b/addons/blogapi/conf/info.xml @@ -1,16 +1,18 @@ BlogAPI 애드온 - BlogAPIアドオン + BlogAPI BlogAPI Addon for BlogAPI Addon para BlogAPI + Аддон для BlogAPI 제로 Zero zero zero zero + zero metaWeblog를 지원하는 blogApi애드온입니다. 사용으로 설정하시면 각 모듈마다 RSD 태그를 노출합니다. @@ -18,7 +20,7 @@ 사용으로 하셔야 RSD태그 및 api가 동작을 합니다. - MetaWeblogをサポートするBlogAPI のアドオンです。「使用」をクリックして設定すると各モジュールごとRSDのアドレスを表示します。API のアドレスは「http://インストールURL/モジュール名/api」です。 「使用する」に設定しておけば RSDのアドレスが表示され、 API が動作します。 + MetaWeblogをサポートするBlogAPI アドオンです。「使用する」をクリックして設定すると各モジュールごとRSDのアドレスを表示します。API のアドレスは「http://インストールURL/モジュール名/api」です。 「使用する」に設定しておけば RSDのアドレスが表示され、 API が動作します。 支持metaWeblog的 blogApi插件。 @@ -38,5 +40,11 @@ La dirección de api es http://dirección de la instalación/nombre de módulo/api. Sólo si seleccionas la opción usar, funcionará la etiqueta RSD y api. + + Этот blogApi аддон поддерживает metaWeblog. + Включая это опицией использовать, позволяет RSD тегу быть доступным для каждого модуля. + URL для api - http://setup_path/module_name/api. + Только выбор опции использовать включает поведение RSD тега и api. + diff --git a/addons/counter/conf/info.xml b/addons/counter/conf/info.xml index bdd0014b8..36db97a18 100644 --- a/addons/counter/conf/info.xml +++ b/addons/counter/conf/info.xml @@ -1,16 +1,18 @@ 기본 카운터 애드온 - 接続カウンターアドオン + 接続カウンター 网站访问统计 Addon for basic counter Addon contador básico + Аддон для базового счетчика 제로 Zero zero zero zero + zero 제로보드XE의 기본 카운터 모듈을 이용하여 접속 정보를 기록합니다. 이 애드온을 켜셔야 접속 정보 수집이 됩니다. @@ -30,5 +32,9 @@ Este addon contador básico de Zeroboard XE permite llevar la información de acceso a la página web de los visitantes. Es necesario activar este addon para agregar la información de acceso. + + Этот аддон пишет в лог информацию о доступе к сайту, основанную на базовом модуле счетчика в Zeroboard XE. + Для сбора информации необходимо включить этот аддон. + diff --git a/addons/google_analytics/conf/info.xml b/addons/google_analytics/conf/info.xml index 9d7e3f2f2..261a0884c 100644 --- a/addons/google_analytics/conf/info.xml +++ b/addons/google_analytics/conf/info.xml @@ -1,29 +1,38 @@ Google Analytics - Google Analytics アドオン Google Analytics + Google Analytics + Google Analytics + Google Analytics 제로 - Zero Zero + Zero + Zero Google Analytics 코드를 사이트에 추가할 수 있습니다. - - Google Analytics コードをサイトに追加することができます。 - 可以添加Google Analytics代码。 + + Google Analytics + + + Google Analytics + uacct uacct + uacct + uacct Google Analytics 코드의 _uacct 값을 입력해주세요. - Google Analytics コードの「uacct」値を入力してください。 - 请输入Google Analytics代码的_uacct值。 + 请输入Google Analytics代码的_uacct值。 + Google Analytics _uacct + Google Analytics _uacct diff --git a/addons/member_extra_info/conf/info.xml b/addons/member_extra_info/conf/info.xml index 62dfc7bc1..0195a43ad 100644 --- a/addons/member_extra_info/conf/info.xml +++ b/addons/member_extra_info/conf/info.xml @@ -1,16 +1,18 @@ 사용자 추가 정보 및 커뮤니케이션 기능 활성화 - 会員情報・コミュニティ活性化機能 + 会員情報・コミュニティ 用户扩展信息 Addon for enabling facilities for providing additional information about users and communicating Addon para activar la función de la Información addcional del usuario y de la comunicación. + Аддон для предоставления дополнительной информации о пользователях и коммуникации 제로 Zero zero zero zero + zero 사용자의 정보중 이미지이름, 이미지마크, 서명등을 화면에 출력해주는 애드온입니다. 이런 정보들을 사용하지 않을 경우를 대비하여 별도의 애드온으로 빼어서 실행시간을 줄여줍니다. @@ -22,11 +24,11 @@ 5. MemberModel::getMemberMenu 호출시 친구 등록 메뉴를 추가합니다. - 会員情報のイメージ名、イメージマーク、署名などを画面に表示するアドオンです。このような情報を使用しない場合、アドオンを「未使用」に設定すれば、実行時間を少なくします。イメージ名、イメージマーク、署名などを表示させたい時は、このアドオンを「使用」に設定して下さい。 + 会員情報のイメージ名、イメージマーク、署名などを画面に表示するアドオンです。このような情報を使用しない場合、アドオンを「使用」に設定すれば、実行時間を少なくします。イメージ名、イメージマーク、署名などを表示させたい時は、このアドオンを「使用」に設定して下さい。 1. 出力の直前 <div class="member_会員番号">....</div> に定義された部分を探し、会員番号をチェックしてイメージ名、イメージマークがあるかを確認します。あった場合は内容を変更します 2. 出力の直前 <div class="document_番号">...</div>に定義された部分を探し、書込みの内容だと判断して、下段に署名を追加します - 3. 新しいメッセージが届いた時、ポップアップで表示します + 3. 新しいメッセージが来た場合ポップアップで表示します 4. MemberModel::getMemberMenu を呼出す時、相手が会員の場合はメッセージ送信の機能を追加します 5. MemberModel::getMemberMenu を呼出す時、友達登録メニュを追加します @@ -60,5 +62,15 @@ 4. Se activa la función "Enviar Mensajes" si la persona que envió la nota es usuario al comprobar en MemberModel::getMemberMenu. 5. Agrega el menú "Ägregar Amigo" al llamar MemberModel::getMemberMenu. + + Среди другой информации о пользователях, этот аддон показывает имя изображения, марку изображения и подпись. + В случае, если Вы не используете эту информацию, это стоит в стороне от базовой информации, так что время выполнения будет снижено. + Чтобы отображать имя изображения, марку изображения и подпись, пожалуйста, включите этот аддон. + 1. Прямо перед отображением информации пользователя, это создаст уникальный ключ члена из определения "&lt;div class="член_{уникальный ключ члена}"&gt;....&lt;/div&gt;" и заменит имя изображения и/или марку изображения, если они существуют. + 2. Прямо перед отображением, это должно найти определение "&lt;div class="документ_{уникальный ключ документа}"&gt;...&lt;/div&gt;" и вставить подпись внизу. + 3. Когда будет получено новое сообщение, оно всплывет. + 4. Это позволяет отправить сообщение, если назначение является членом, когда MemberModel::getMemberMenu вызывается. + 5. Это добавляет меню для регистрации как друга, когда MemberModel::getMemberMenu вызывается. + diff --git a/addons/member_extra_info/lang/ru.lang.php b/addons/member_extra_info/lang/ru.lang.php index 5601c132c..e181b5e69 100644 --- a/addons/member_extra_info/lang/ru.lang.php +++ b/addons/member_extra_info/lang/ru.lang.php @@ -5,5 +5,5 @@ * @brief Russian basic language pack for Zeroboard XE **/ - $lang->alert_new_message_arrived = 'У Вас есть новое сообщение. Хотите проверить сейчас?'; + $lang->alert_new_message_arrived = 'У Вас есть новые сообщения. Хотите проверить сейчас?'; ?> diff --git a/addons/openid_delegation_id/conf/info.xml b/addons/openid_delegation_id/conf/info.xml index 5b7295610..f639d6c8a 100644 --- a/addons/openid_delegation_id/conf/info.xml +++ b/addons/openid_delegation_id/conf/info.xml @@ -4,13 +4,15 @@ OpenID Addon for delegating domain name to OpenID Delegación ID para OpenID - OpenIDアドオン + OpenID + Аддон для делигирования доменного имени к OpenID 제로 zero zero zero Zero + Zero 본인의 도메인을 사용하여 오픈아이디로 활용할 수 있도록 합니다. 꼭 설정을 통해서 openid provider관련 값을 입력후 사용해주세요. @@ -30,6 +32,10 @@ 保有するドメインをオープンIDとして活用することができます。必ず設定で、OpenIDのプロバイダー関連の情報を入力してから使用してください。 + + Этот аддон позволяет Вам использовать Вашу доменное имя как OpenID. + Прежде, чем использовать, просто убедитесь, что установлены значения, имеющие отношение к провайдеру openid. + @@ -38,11 +44,13 @@ server Servidor server + server openid.server 값을 입력해 주세요. 请输入 openid.server 值。 Please input your openid.server value. Ingrese el valor del openid.server. openid.server の値を入力してください。 + Пожалуйста, введите Ваше значение openid сервера. delegate @@ -50,11 +58,13 @@ delegate delegado delegate + delegate openid.delegate값을 입력해주세요. 请输入 openid.delegate 值。 - Please input your openid.delegate value. + Пожалуйста, введите Ваше значение openid делегата. Ingresar el valor del openid.delegate openid.delegate の値を入力してください。 + Please input your openid.delegate value. xrds @@ -62,11 +72,13 @@ xrds xrds xrds + xrds X-XRDS-Location값을 입력해주세요. 请输入 X-XRDS-Location 值。 Please input your X-XRDS-Location value. Ingresar el valor de X-XRDS-Location X-XRDS-Location の値を入力してください。 + Пожалуйста, введите Ваше значение X-XRDS-Локации. diff --git a/addons/point/conf/info.xml b/addons/point/conf/info.xml index 28dc67ffe..27889b721 100644 --- a/addons/point/conf/info.xml +++ b/addons/point/conf/info.xml @@ -2,15 +2,17 @@ 포인트 활성화 애드온 积分插件 - ポイントシステムアドオン + ポイントシステム Addon for activating point Addon para activar los puntos + Аддон для активации поинтов 제로 Zero Zero zero zero + zero 포인트시스템 모듈에 설정된 내용을 바탕으로 글작성/삭제/댓글작성/삭제/파일업로드/삭제/다운로드등의 행동에 대해서 포인트를 기록합니다. @@ -18,7 +20,7 @@ 以积分系统模块中设置的内容为基础,对发表/删除新帖,发表/删除评论,上传/下载/删除/文件等动作记录为积分。 - ポイントシステムモジュールで設定された内容を基に、書き込みの作成・削除/コメントの作成・削除/ファイルのアップロード・削除/ダウンロードなどのユーザの活動に対してポイントに換算して記録します。 + ポイントシステムモジュールで設定された内容を基に、書き込み作成・削除/コメント作成・削除/ファイルアップロード・削除/ダウンロードなどのユーザの活動に対してポイントを記録します。 This addon records point on writing/deleting/adding comments/deleting comments/uploading/downloading following to point system module. @@ -26,5 +28,8 @@ Este addon registra los puntos de acuerdo a la acción de escribir/borrar/agregar comentarios/borrar comentarios/subir_archivo/bajar_archivo,etc., siguiendo el módulo de sistema de puntos. + + Этот аддон записыват поинты при написании/удалении/добавлении комментариев/удалении комментариев/закачки/скачки согласно модулю системы поинтов. + diff --git a/addons/point_level_icon/conf/info.xml b/addons/point_level_icon/conf/info.xml index 0c0281ca0..99e14e753 100644 --- a/addons/point_level_icon/conf/info.xml +++ b/addons/point_level_icon/conf/info.xml @@ -2,15 +2,17 @@ 포인트 레벨 아이콘 표시 애드온 积分级别图标 - ポイントレベルアイコン表示アドオン + ポイントレベルアイコン Addon for displaying level icon - Addon para mostar el nivel del ícono + Addon para mostar el nivel del ícono + Аддон для отображения иконки уровня 제로 Zero Zero zero zero + zero 포인트 시스템을 사용중일 경우 사용자 이름 앞에 레벨 아이콘을 표시하도록 합니다. 레벨 아이콘은 모듈 > 포인트시스템에서 선택 가능합니다. @@ -30,5 +32,9 @@ Este addon muestra el nivel del ícono delante del nombre del usuario cuando es usado el sistema de puntos. Tu puedes elegir los icono de cada nivel en el módulo > Sistema de Puntos. + + Этот аддон отображает иконку уровня напротив имени пользователя, когда используется система поинтов. + Вы можете выбрать иконку уровня на Модуле Системы Поинтов. + diff --git a/addons/spamfilter/conf/info.xml b/addons/spamfilter/conf/info.xml index bfc0c0901..6d311b275 100644 --- a/addons/spamfilter/conf/info.xml +++ b/addons/spamfilter/conf/info.xml @@ -4,13 +4,15 @@ 垃圾过滤 Addon for filtering spam Addon para filtrar los Spam - スパムフィルターアドオン + スパムフィルター + Аддон для фильтрации спама 제로 zero zero zero Zero + zero SpamFilter 모듈을 이용하여 글/코멘트/트랙백 등록 이전에 스팸 필터링 및 도배 방지를 합니다. 자세한 설정은 " 스팸필터 모듈" 에서 해주세요. @@ -27,8 +29,11 @@ Este addon filtra y previene de los documentos/ commentarios/ trackback no deseado antes de ser agregados. Para la configuración más detallada, debe hacerse en el " Módulo de Filtro de Spam". - - SpamFilterモジュールを利用して書き込み・コメント・トラックバックが登録される前にフィルタリングを行います。更に連続書き込みやロボットによる自動書き込みなどを防ぐことができます。詳細な設定は " スパムフィルターモジュール " で行ってください。 + SpamFilterモジュールを利用して書き込み・コメント・トラックバックが登録される前にフィルタリングを行います。更に連続書き込みやロボットによる自動書き込みなどを防ぐことができます。詳細な設定は " スパムフィルターモジュール " で行ってください。 + + + Этот аддон фильтрует спам и предотвращает беспорядок перед сохранением элементов, комментариев или трекбеков в базу данных посредством установки модуля Фильтра Спама. + Вы можете установить детали на странице "Модуля Спам Фильтра". diff --git a/common/lang/ru.lang.php b/common/lang/ru.lang.php index fe7732cdc..9d8819c3a 100644 --- a/common/lang/ru.lang.php +++ b/common/lang/ru.lang.php @@ -12,13 +12,13 @@ $lang->cmd_modify = 'Изменить'; $lang->cmd_edit = 'Редактировать'; $lang->cmd_view = 'Просмотреть'; - $lang->cmd_view_all = 'Просмотреть Все'; + $lang->cmd_view_all = 'Просмотреть все'; $lang->cmd_list = 'Список'; $lang->cmd_prev = 'Пред.'; $lang->cmd_next = 'След.'; - $lang->cmd_send_trackback = 'Отправить Трекбек'; + $lang->cmd_send_trackback = 'Отправить трекбек'; $lang->cmd_registration = $lang->cmd_submit = 'Принять'; - $lang->cmd_comment_registration = 'Добавить Комментарий'; + $lang->cmd_comment_registration = 'Добавить комментарий'; $lang->cmd_insert = 'Вставить'; $lang->cmd_save = 'Сохранить'; $lang->cmd_load = 'Загрузить'; @@ -29,45 +29,45 @@ $lang->cmd_vote = 'Рекомендовать'; $lang->cmd_vote_down = 'Критиковать'; $lang->cmd_declare = 'Обвинить'; - $lang->cmd_declared_list = 'Список Обвинений'; + $lang->cmd_declared_list = 'Список обвинений'; $lang->cmd_copy = 'Копировать'; $lang->cmd_move = 'Переместить'; $lang->cmd_move_up = 'Вверх'; $lang->cmd_move_down = 'Вниз'; - $lang->cmd_add_indent = 'Отступ Вправо'; - $lang->cmd_remove_indent = 'Отступ Влево'; + $lang->cmd_add_indent = 'Отступ вправо'; + $lang->cmd_remove_indent = 'Отступ влево'; $lang->cmd_management = 'Управление'; $lang->cmd_make = 'Создать'; $lang->cmd_select = 'Выделить'; - $lang->cmd_select_all = 'Выделить Все'; - $lang->cmd_unselect_all = 'Убрать Выделение Всех'; + $lang->cmd_select_all = 'Выделить все'; + $lang->cmd_unselect_all = 'Убрать выделение Всех'; $lang->cmd_reverse_all = 'Перевернуть'; - $lang->cmd_close_all = 'Закрыть Все'; - $lang->cmd_open_all = 'Открыть Все'; + $lang->cmd_close_all = 'Закрыть все'; + $lang->cmd_open_all = 'Открыть все'; $lang->cmd_reload = 'Перегрузить'; $lang->cmd_close = 'Закрыть'; $lang->cmd_open = 'Открыть'; - $lang->cmd_setup = 'Кунфигурировать'; - $lang->cmd_addition_setup = 'Дополнительная Настройка'; + $lang->cmd_setup = 'Конфигурация'; + $lang->cmd_addition_setup = 'Дополнительная настройка'; $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_scrap = 'В черновики'; $lang->cmd_preview = 'Предпросмотр'; $lang->cmd_reset = 'Сброс'; $lang->cmd_remake_cache = "Пере-создать файл кэша"; $lang->cmd_publish = "Опубликовать"; - $lang->enable = 'Включить'; - $lang->disable = 'Выключить'; + $lang->enable = 'Включено'; + $lang->disable = 'Выключено'; // Существенные слова $lang->no = 'No.'; $lang->notice = 'Уведомление'; $lang->secret = 'Секрет'; - $lang->category = 'Катигория'; + $lang->category = 'Категория'; $lang->document_srl = 'Док. No.'; $lang->user_id = 'Юзер ID'; $lang->author = 'Разработчик'; @@ -83,7 +83,7 @@ $lang->blog = 'Блог'; $lang->birthday = 'Дата рождения'; $lang->browser_title = 'Заголовок браузера'; - $lang->title = 'Предмет'; + $lang->title = 'Тема'; $lang->title_content = 'Тема+Содержание'; $lang->topic = 'Тема'; $lang->replies = 'Ответы'; @@ -93,9 +93,9 @@ $lang->description = 'Описание'; $lang->trackback = 'Трекбек'; $lang->tag = 'Тег'; - $lang->allow_comment = 'Позволить Комментарии'; - $lang->lock_comment = 'Заблокировать Комментарии'; - $lang->allow_trackback = 'Позволить Трекбек'; + $lang->allow_comment = 'Позволить комментарии'; + $lang->lock_comment = 'Заблокировать комментарии'; + $lang->allow_trackback = 'Позволить трекбек'; $lang->uploaded_file = 'Вложение'; $lang->grant = 'Права доступа'; $lang->target = 'Назначение'; @@ -113,36 +113,36 @@ $lang->module = 'Модуль'; $lang->skin = 'Тема'; $lang->colorset = 'Цветовой набор'; - $lang->extra_vars = 'Доп. Перем.'; + $lang->extra_vars = 'Доп. перем.'; $lang->document_url = 'Адрес статьи'; $lang->trackback_url = 'Адрес трекбек'; - $lang->blog_name = 'Название Блога'; + $lang->blog_name = 'Название блога'; $lang->excerpt = 'Цитата'; - $lang->document_count = 'Всего Статей'; - $lang->page_count = 'Кол-во Страниц'; - $lang->list_count = 'Кол-во Списков'; + $lang->document_count = 'Всего статей'; + $lang->page_count = 'Кол-во страниц'; + $lang->list_count = 'Кол-во списков'; $lang->readed_count = 'Хиты'; $lang->voted_count = 'Голоса'; $lang->member_count = 'Кол-во пользователей'; $lang->date = 'Дата'; - $lang->regdate = 'Дата Регистрации'; - $lang->last_update = 'Последнее Обновление'; - $lang->last_post = 'Последний Комментарий'; - $lang->signup_date = 'Дата Регистрации'; - $lang->last_login = 'Последний Вход'; - $lang->first_page = 'Первая Страница'; - $lang->last_page = 'Последняя Страница'; - $lang->search_target = 'Назначение Поиска'; - $lang->search_keyword = 'Ключевые Слова'; + $lang->regdate = 'Дата регистрации'; + $lang->last_update = 'Последнее обновление'; + $lang->last_post = 'Последний комментарий'; + $lang->signup_date = 'Дата регистрации'; + $lang->last_login = 'Последний вход'; + $lang->first_page = 'Первая страница'; + $lang->last_page = 'Последняя страница'; + $lang->search_target = 'Назначение поиска'; + $lang->search_keyword = 'Ключевые слова'; $lang->is_default = 'По умолчанию'; - $lang->no_documents = 'Нет Статей'; + $lang->no_documents = 'Нет статей'; - $lang->board_manager = 'Настройки Форума'; - $lang->member_manager = 'Настройки Пользователей'; - $lang->layout_manager = 'Настройки Лейаута'; + $lang->board_manager = 'Настройки форума'; + $lang->member_manager = 'Настройки пользователей'; + $lang->layout_manager = 'Настройки лейаута'; $lang->use = 'Использовать'; $lang->notuse = 'Не использовать'; @@ -203,7 +203,7 @@ $lang->confirm_reset = 'Вы подтверждаете сброс?'; $lang->confirm_leave = 'Вы подтверждаете уход?'; - $lang->column_type = 'Тип Колонки'; + $lang->column_type = 'Тип колонки'; $lang->column_type_list['text'] = 'one-line text'; $lang->column_type_list['homepage'] = 'url'; $lang->column_type_list['email_address'] = 'email'; @@ -214,11 +214,11 @@ $lang->column_type_list['kr_zip'] = 'zip code (Korean)'; $lang->column_type_list['date'] = 'date (yyyy/mm/dd)'; //$lang->column_type_list['jp_zip'] = 'zip code (Japanese)'; - $lang->column_name = 'Имя Колонки'; - $lang->column_title = 'Название Колонки'; - $lang->default_value = 'Стандартное Значение'; + $lang->column_name = 'Имя колонки'; + $lang->column_title = 'Название колонки'; + $lang->default_value = 'Стандартное значение'; $lang->is_active = 'Активно'; - $lang->is_required = 'Требуемое Поле'; + $lang->is_required = 'Требуемое поле'; // Alert-сообщения для Javascript используя XML filter $lang->filter->isnull = 'Пожалуйста, введите значение для %s'; diff --git a/modules/addon/conf/info.xml b/modules/addon/conf/info.xml index aa04249ac..27a6f2806 100644 --- a/modules/addon/conf/info.xml +++ b/modules/addon/conf/info.xml @@ -6,6 +6,7 @@ 插件 アドオン Additions + Аддоны 제로 zero @@ -13,11 +14,13 @@ zero Zero Zero + Zero 애드온을 등록하거나 사용/미사용을 설정하는 애드온 관리 모듈입니다. This module is for maintaining addons which can toggle use and disuse states. Este Módulo es para agregar Addons, como también el manejo de ellos. 登录插件或设置启用/禁用插件的管理模块。 アドオンの「登録、使用、未使用」などを設定するための管理モジュールです。 Ce module est pour les Additions de maintien qui peuvent basculer des états d'utilisation et de désuétude. + Этот модуль служит для управления аддонами, использование которых Вы можете включать и выключать. diff --git a/modules/admin/conf/info.xml b/modules/admin/conf/info.xml index d07417106..51667c631 100644 --- a/modules/admin/conf/info.xml +++ b/modules/admin/conf/info.xml @@ -5,16 +5,19 @@ Módulo del administrador 管理员模块 管理者用モジュール + Модуль администратора 제로 zero zero zero Zero + zero 각 모듈들의 기능을 나열하고 관리자용 레이아웃을 적용하여 관리 기능을 사용할 수 있도록 하는 모듈입니다. This module shows a list of features of each module, and enables you to use a quite few of managers by applying layout for administrator. Este módulo muestra una lista de características de cada módulo, en donde puede activar la función de la administracion aplicando el diseño del administrador. 列出各模块的功能并使用管理员布局,可以让其使用管理功能的模块。 各モジュールの機能を羅列し、管理者用のレイアウトを適用させ、管理機能が使用できるようにするモジュールです。 + Этот модуль показывает список возможностей каждого модуля, и позволяет Вам использовать несколько менеджеров, применяя лейаут для администратора. diff --git a/modules/admin/lang/ru.lang.php b/modules/admin/lang/ru.lang.php index dee41a5f0..11f27cbb9 100644 --- a/modules/admin/lang/ru.lang.php +++ b/modules/admin/lang/ru.lang.php @@ -5,40 +5,40 @@ * @brief Russian basic language pack for Zeroboard XE **/ - $lang->admin_info = 'Информация Администратора'; - $lang->admin_index = 'Индексная Страница Администратора'; + $lang->admin_info = 'Информация администратора'; + $lang->admin_index = 'Индексная страница администратора'; $lang->module_category_title = array( - 'service' => 'Служебные Модули', - 'manager' => 'Управляющие Модули', - 'utility' => 'Утилиратные Модули', - 'accessory' => 'Дополнительные Модули', - 'base' => 'Базовые Модули', + 'service' => 'Служебные модули', + 'manager' => 'Управляющие модули', + 'utility' => 'Утилиратные модули', + 'accessory' => 'Дополнительные модули', + 'base' => 'Базовые модули', ); - $lang->newest_news = "Последние Новости"; + $lang->newest_news = "Последние новости"; $lang->env_setup = "Настройка"; - $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 = "Новая версия XE доступна. Чтобы скачать последнюю версию, нажмите ссылку закачки."; - $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->module_name = "Имя модуля"; + $lang->addon_name = "Имя аддона"; $lang->version = "Версия"; $lang->author = "Разработчик"; - $lang->table_count = "Номер Таблицы"; - $lang->installed_path = "Путь Установки"; + $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 = 'Ярлыки модулей, аддонов, лейаутов, виджетов не могут быть удалены'; @@ -48,8 +48,8 @@ $lang->about_admin_page = "Страница администратора все еще в разработке,\nМы добавим важные доработки, принимая много хороших предложений на этапе Closebeta."; $lang->about_lang_env = "Чтобы применить выбранный язык для пользователей как страндартный, нажмите кнопку Сохранить [Save] после изменения."; - $lang->zeroboard_xe_user_links = 'Ссылки для Пользователей'; - $lang->zeroboard_xe_developer_links = 'Ссылки для Разработчиков'; + $lang->zeroboard_xe_user_links = 'Ссылки для пользователей'; + $lang->zeroboard_xe_developer_links = 'Ссылки для разработчиков'; $lang->xe_user_links = array( 'Официальный веб-сайт' => 'http://www.zeroboard.com', @@ -64,22 +64,22 @@ $lang->xe_developer_links = array( //'Manual' => 'http://www.zeroboard.com/wiki/manual', - "Форум Разработчиков" => 'http://spring.zeroboard.com', - 'Обсуждение Восросов' => 'http://trac.zeroboard.com', - 'SVN Репозиторий' => 'http://svn.zeroboard.com', + "Форум разработчиков" => 'http://spring.zeroboard.com', + 'Обсуждение вопсросов' => 'http://trac.zeroboard.com', + 'SVN репозиторий' => 'http://svn.zeroboard.com', 'Документация' => 'http://doc.zeroboard.com', - 'PDF Документация' => 'http://doc.zeroboard.com/zeroboard_xe.pdf', + 'PDF документация' => 'http://doc.zeroboard.com/zeroboard_xe.pdf', ); - $lang->zeroboard_xe_usefulness_module = 'Полезные Модули'; + $lang->zeroboard_xe_usefulness_module = 'Полезные модули'; $lang->xe_usefulness_modules = array( - 'dispEditorAdminIndex' => 'Менеждер Редактора', - 'dispDocumentAdminList' => 'Менеждер Статей', - 'dispCommentAdminList' => 'Менеждер Комментариев', - 'dispFileAdminList' => 'Менеждер Вложений', - 'dispPollAdminList' => 'Менеждер Голосований', - 'dispSpamfilterAdminConfig' => 'Менеждер Спам-фильтра', - 'dispCounterAdminIndex' => 'Лог Счетчика', + 'dispEditorAdminIndex' => 'Менеждер редактора', + 'dispDocumentAdminList' => 'Менеждер статей', + 'dispCommentAdminList' => 'Менеждер комментариев', + 'dispFileAdminList' => 'Менеждер вложений', + 'dispPollAdminList' => 'Менеждер голосований', + 'dispSpamfilterAdminConfig' => 'Менеждер спам-фильтра', + 'dispCounterAdminIndex' => 'Лог счетчика', ); diff --git a/modules/blog/conf/info.xml b/modules/blog/conf/info.xml index bf0196be8..96c5394f4 100644 --- a/modules/blog/conf/info.xml +++ b/modules/blog/conf/info.xml @@ -5,19 +5,23 @@ Blog Blog 博客 + Блог 제로 Zero zero zero zero + zero 블로그의 기능을 담당하는 모듈. 게시판과 비슷하지만 보여지는 view가 다르고 블로그에 적합한 method가 추가되었음. 레이아웃과 기본 메뉴를 직접 담당 - ブログの機能を担当するモジュールです。掲示板と似ているが、内容の表示が異なり、ブログに適切なメソッドが追加されています。 レイアウトと基本メニューを直接担当します。 + ブログの機能を担当するモジュール + 掲示板と似ているが、内容の表示が異なり、ブログに適切なメソッドが追加されている。 + レイアウトと基本メニューを直接担当します。 This module contains the blog functions. @@ -34,5 +38,10 @@ 虽然类似版面,但其显示模式不同,且还添加了适合博客的method。 内置布局和基本的菜单。 + + Этот модуль содержит функции блога. + Он похож на модуль BBS, но имеет другой вид и более подходящие методы для блога. + Этот модуль управляет лейвутом и базовым меню самостоятельно. + diff --git a/modules/blog/lang/ru.lang.php b/modules/blog/lang/ru.lang.php index 4a838361a..ee7395564 100644 --- a/modules/blog/lang/ru.lang.php +++ b/modules/blog/lang/ru.lang.php @@ -6,9 +6,9 @@ **/ // Слова, использованные в кнопке - $lang->cmd_blog_list = 'Список Блогов'; + $lang->cmd_blog_list = 'Список блогов'; $lang->cmd_module_config = 'Общие настройки блога'; - $lang->cmd_view_info = 'Иформация Блога'; + $lang->cmd_view_info = 'Иформация блога'; $lang->cmd_manage_menu = 'Управление меню'; $lang->cmd_make_child = 'Добавить дочернюю категорию'; $lang->cmd_enable_move_category = "Изменить позицию категории (Перетащите верхнее меню после выделения)"; @@ -20,7 +20,7 @@ $lang->parent_category_title = 'Родительская категория'; $lang->category_title = 'Категория'; $lang->expand = 'Расширить'; - $lang->category_group_srls = 'Доступные Группы'; + $lang->category_group_srls = 'Доступные группы'; $lang->search_result = 'Результат поиска'; // blah blah.. или чушь всякая... ;) diff --git a/modules/board/conf/info.xml b/modules/board/conf/info.xml index 5811f3374..9f0b60e18 100644 --- a/modules/board/conf/info.xml +++ b/modules/board/conf/info.xml @@ -5,16 +5,19 @@ Board Tablero 掲示板 + Форум 제로 zero zero zero Zero + zero 게시판의 기능을 담당하는 모듈. 게시판의 생성/추가 관리등의 관리자 기능도 포함합니다. 给用户提供相应版面功能,将包含版面的生成/添加及版面管理等管理员功能。 Module of the board''s function. Also includes administrator functions such as creating/managing boards. Módulo para la función del tablero. Incluye funciones de administración como crear/ agregar o el manejo de los tableros. 掲示板の機能を担うモジュールです。掲示板の生成・追加・管理などの管理者機能も含まれています。 + Модуль для функционирования форума. Также включает в себя функции администратора такие как создание/управление форумами. diff --git a/modules/comment/conf/info.xml b/modules/comment/conf/info.xml index 137a077b9..082db878a 100644 --- a/modules/comment/conf/info.xml +++ b/modules/comment/conf/info.xml @@ -5,16 +5,19 @@ 评论 Comment Commentarios + Комментарии 제로 Zero zero zero zero + zero 게시판이나 블로그등의 댓글을 관리하는 모듈입니다. 掲示板やブログなどのコメントを管理するモジュールです。 管理版面或博客评论的模块。 Module for managing board/blog's comments Es el módulo para manejar commentarios en blog o boletínes. + Модуль для управления комментариями форума/блога. diff --git a/modules/comment/lang/ru.lang.php b/modules/comment/lang/ru.lang.php index c2870faac..c9ca0a266 100644 --- a/modules/comment/lang/ru.lang.php +++ b/modules/comment/lang/ru.lang.php @@ -5,9 +5,9 @@ * @brief Russian basic language pack for Zeroboard XE **/ - $lang->cmd_comment_do = 'Вы бы...'; + $lang->cmd_comment_do = 'Действия'; - $lang->comment_list = 'Список Комментариев'; + $lang->comment_list = 'Список комментариев'; $lang->cmd_delete_checked_comment = 'Удалить выбранный объект'; $lang->msg_cart_is_null = 'Пожалуйста, выберите статью для удаления.'; diff --git a/modules/counter/conf/info.xml b/modules/counter/conf/info.xml index 78ba57618..af6ad4f23 100644 --- a/modules/counter/conf/info.xml +++ b/modules/counter/conf/info.xml @@ -5,16 +5,19 @@ Basic Counter Contador Básico 接続カウンター + Базовый счетчик 제로 zero - Zero + zero zero Zero + zero 기본 접속 통계 프로그램입니다. 默认访问统计程序。 Basic connection statistics program. Programa básico para la estadística de la conección. 接続統計のプログラムです。 + Базовая программа статистики подключений. diff --git a/modules/counter/lang/ru.lang.php b/modules/counter/lang/ru.lang.php index a512a5414..87146198d 100644 --- a/modules/counter/lang/ru.lang.php +++ b/modules/counter/lang/ru.lang.php @@ -14,7 +14,7 @@ 'year' => 'По годам', ); - $lang->total_counter = 'Общее Состояние'; + $lang->total_counter = 'Общее состояние'; $lang->selected_day_counter = 'Состояние на выбранный день'; $lang->unique_visitor = 'Посетителей'; diff --git a/modules/document/conf/info.xml b/modules/document/conf/info.xml index ce2d4bc6a..59905e54a 100644 --- a/modules/document/conf/info.xml +++ b/modules/document/conf/info.xml @@ -4,17 +4,20 @@ Document Documento 主题 - コンテンツ(ドキュメント) + コンテンツ + Документы 제로 - Zero + zero zero zero Zero + zero 게시판, 블로그등의 모듈에서 사용되는 문서를 관리하는 모듈입니다. Module for managing documents used in board, blog, etc. Módulo para manejar los documentos en blog y en los tableros. 管理版面,博客等处主题的模块。 - 掲示板、ブログなどのモジュールで使用されるコンテンツ(書き込み、ドキュメント)を管理するモジュールです。 + 掲示板、ブログなどのモジュルで使用されるドキュメント(書き込み)を管理するモジュルです。 + Модуль для управления документами в форуме, блоге и прочее. diff --git a/modules/document/lang/ru.lang.php b/modules/document/lang/ru.lang.php index 5667abd50..7aba32e10 100644 --- a/modules/document/lang/ru.lang.php +++ b/modules/document/lang/ru.lang.php @@ -5,22 +5,20 @@ * @brief Russian basic language pack for Zeroboard XE **/ - $lang->document_list = 'Список Документов'; - $lang->thumbnail_type = 'Тип Миниатюры'; + $lang->document_list = 'Список документов'; + $lang->thumbnail_type = 'Тип миниатюры'; $lang->thumbnail_crop = 'Обрезать'; $lang->thumbnail_ratio = 'Отношение'; $lang->cmd_delete_all_thumbnail = 'Удалить все миниарюры'; $lang->move_target_module = "Переместить в"; - $lang->title_bold = 'Жирное Название'; - $lang->title_color = 'Цвет Названия'; - - $lang->cmd_search_next = '계속 검색'; + $lang->title_bold = 'Жирное название'; + $lang->title_color = 'Цвет названия'; $lang->cmd_temp_save = 'Сохранить временно'; $lang->cmd_toggle_checked_document = 'Перевернуть выбранные объекты'; $lang->cmd_delete_checked_document = 'Удалить выбранные'; - $lang->cmd_document_do = 'Вы бы...'; + $lang->cmd_document_do = 'Действия'; $lang->msg_cart_is_null = 'Выберите статьи, которые Вы хотите удалить'; $lang->msg_category_not_moved = 'Невозможно переместить'; diff --git a/modules/editor/conf/info.xml b/modules/editor/conf/info.xml index 26b43d72d..8b926e992 100644 --- a/modules/editor/conf/info.xml +++ b/modules/editor/conf/info.xml @@ -1,20 +1,23 @@ 위지윅 에디터 - WYSIWYG Editor - Editor WYSIWYG + WYSIWYG Editor + Editor WYSIWYG 网页编辑器 エディター + WYSIWYG-редактор 제로 - Zero + zero zero zero Zero + zero 위지윅 에디터를 출력하거나 에디터 컴포넌트들을 관리/중계하는 모듈입니다. Module for displaying WYSIWYG editor and managing/relaying editor components. Módulo para mostrar en la pantalla el editor de WYSIWYG y para el manejo/relato de los componentes del editor. 显示网页编辑器或管理/传递编辑器组件的模块。 ウィジウィグエディター を出力したり、エディターのコンポネントを管理中継するモジュールです。 + Модуль для отображения WYSIWYG-редактора и управления/смены комментариев редактора. diff --git a/modules/editor/lang/ru.lang.php b/modules/editor/lang/ru.lang.php index cfa051a19..de2e07056 100644 --- a/modules/editor/lang/ru.lang.php +++ b/modules/editor/lang/ru.lang.php @@ -13,7 +13,7 @@ $lang->component_date = "Дата"; $lang->component_description = "Описание"; $lang->component_extra_vars = "Экстра перем."; - $lang->component_grant = "Настройки Прав Доступа"; + $lang->component_grant = "Настройки прав доступа"; $lang->about_component = "О компоненте"; $lang->about_component_grant = "Только выбранным группам позволено использование. (Каждый может использовать его, если режим выключен)"; @@ -23,14 +23,14 @@ $lang->msg_component_is_first_order = 'Выбранный компонент находится на первой позиции'; $lang->msg_component_is_last_order = 'Выбранный компонент находится на последней позиции'; $lang->msg_load_saved_doc = "Существует автоматически сохраненная статья. Хотите ли Вы ее восстановить?\nАвтоматически сохраненный черновик будет отменен после сохранения текущей статьи"; - $lang->msg_auto_saved = "Автоматически Сохранено"; + $lang->msg_auto_saved = "Автоматически сохранено"; $lang->cmd_disable = "Неавтивно"; $lang->cmd_enable = "Активно"; $lang->edit->fontname = 'Шрифт'; $lang->edit->fontsize = 'Размер'; - $lang->edit->use_paragraph = 'Функции Параграфа'; + $lang->edit->use_paragraph = 'Функции параграфа'; $lang->edit->fontlist = array( "Gulim", "Dodum", @@ -73,8 +73,8 @@ $lang->edit->upload = 'Вложение'; $lang->edit->upload_file = 'Вложить'; - $lang->edit->link_file = 'Вставить в Содержание'; - $lang->edit->delete_selected = 'Удалить Выбранное'; + $lang->edit->link_file = 'Вставить в содержание'; + $lang->edit->delete_selected = 'Удалить выбранное'; $lang->edit->icon_align_article = 'Занять весь параграф'; $lang->edit->icon_align_left = 'Выровнять по левому краю'; diff --git a/modules/file/conf/info.xml b/modules/file/conf/info.xml index e26937770..b69fa9b3d 100644 --- a/modules/file/conf/info.xml +++ b/modules/file/conf/info.xml @@ -5,16 +5,19 @@ Attachment Adjuntar archivos 添付ファイル + Вложения 제로 zero - Zero + zero zero Zero + zero 첨부 파일 관리하는 모듈입니다. 管理附件的模块。 Module for managing attachments. Módulo para manejar los archivos adjuntos. 添付ファイルを管理するモジュールです。 + Модуль для управления вложениями. diff --git a/modules/guestbook/conf/info.xml b/modules/guestbook/conf/info.xml index f91e77a06..0c5b3f87d 100644 --- a/modules/guestbook/conf/info.xml +++ b/modules/guestbook/conf/info.xml @@ -5,15 +5,18 @@ Guest Book Tablero de visitas 留言本 + Гостевая книга 제로 Zero zero - zero + zero + zero 모듈 제작을 위해 sample로 제작된 모듈입니다. モジュール作成のためのサンプルで作成されたモジュールです。 This is a sample module for creating modules. Este is un módulo de muestra para crear módulos. 留言本sample模块。 + Это модуль-пример для создания модулей. diff --git a/modules/guestbook/lang/ru.lang.php b/modules/guestbook/lang/ru.lang.php index 627922be0..3c27ab74c 100644 --- a/modules/guestbook/lang/ru.lang.php +++ b/modules/guestbook/lang/ru.lang.php @@ -5,12 +5,12 @@ * @brief Russian basic language pack for Zeroboard XE **/ - $lang->guestbook = "Гостевая Книга"; + $lang->guestbook = "Гостевая книга"; // Слова, использованные в кнопках - $lang->cmd_guestbook_list = 'Список Гостевых Книг'; - $lang->cmd_module_config = 'Общая Конфигурация Гостевых Книг'; - $lang->cmd_view_info = 'Информация Гостевой Книги'; + $lang->cmd_guestbook_list = 'Список гостевых книг'; + $lang->cmd_module_config = 'Общая конфигурация гостевых книг'; + $lang->cmd_view_info = 'Информация гостевой книги'; $lang->about_board = "Этот модуль служит для создания и управления гостевыми книгами.\nВы можете выбрать имя модуля из списка после создания для дополнительного конифигурирования.\nПожалуйста, будте осторожны с именем модуля форума, поскольку оно будет URL. (например : http://domain/zb/?mid=имя_модуля)"; ?> diff --git a/modules/importer/conf/info.xml b/modules/importer/conf/info.xml index 8dce940ae..d8b372a57 100644 --- a/modules/importer/conf/info.xml +++ b/modules/importer/conf/info.xml @@ -5,16 +5,19 @@ 数据导入 ZBデータ移転 Transferencia de los datos de ZeroBoard + Трансферинг данных Zeroboard 제로 - Zero + zero zero Zero Zero + zero XML파일을 이용하여 회원정보 또는 게시판등의 데이터를 입력합니다. Inputting member information or board's data using XML file. 利用XML文件导入会员信息或版面数据。 XMLファイルを用いて会員情報または掲示板などの情報を入力します。 Ingresa la información del usuario o los datos del tablero utilizando el archivo XML. + Запись информации пользователей или форума, используя XML-файл. diff --git a/modules/install/conf/info.xml b/modules/install/conf/info.xml index e1f5e008c..46dbe903b 100644 --- a/modules/install/conf/info.xml +++ b/modules/install/conf/info.xml @@ -5,16 +5,19 @@ 安装管理 インストール管理 Manajo de la Instalación + Управление установкой 제로 - Zero + zero zero Zero Zero + zero 설치 관리 모듈 Module for managing installation 安装管理模块。 インストール管理モジュール Módulo para el manejo de la instalación + Модуль для управления установкой diff --git a/modules/install/lang/ru.lang.php b/modules/install/lang/ru.lang.php index 37acc7f19..802379f1f 100644 --- a/modules/install/lang/ru.lang.php +++ b/modules/install/lang/ru.lang.php @@ -295,9 +295,9 @@ EndOfLicense; $lang->install_checklist_title = array( 'php_version' => 'Версия PHP', 'permission' => 'Права доступа', - 'xml' => 'XML Библиотека', - 'iconv' => 'ICONV Библиотека', - 'gd' => 'GD Библиотека', + 'xml' => 'XML библиотека', + 'iconv' => 'ICONV библиотека', + 'gd' => 'GD библиотека', 'session' => 'Session.auto_start настройка', ); @@ -310,16 +310,16 @@ EndOfLicense; 'gd' => 'GD Библиотека должна быть установлена для использования функции конвертироваия изображений', ); - $lang->install_checklist_xml = 'Установить XML Библиотеку'; - $lang->install_without_xml = 'XML Библиотека не установлена'; - $lang->install_checklist_gd = 'Установить GD Библиотеку'; - $lang->install_without_gd = 'GD Библиотека не установлена'; - $lang->install_checklist_gd = 'Установить GD Библиотеку'; - $lang->install_without_iconv = 'Iconv Библиотека не установлена'; + $lang->install_checklist_xml = 'Установить XML библиотеку'; + $lang->install_without_xml = 'XML библиотека не установлена'; + $lang->install_checklist_gd = 'Установить GD библиотеку'; + $lang->install_without_gd = 'GD библиотека не установлена'; + $lang->install_checklist_gd = 'Установить GD библиотеку'; + $lang->install_without_iconv = 'Iconv библиотека не установлена'; $lang->install_session_auto_start = 'Возможно возникнут проблемы из-за настройки PHP session.auto_start, установленной в 1'; $lang->install_permission_denied = 'Права доступа пути не установлены в 707'; - $lang->cmd_agree_license = 'Я согласен с данной Лицензией'; + $lang->cmd_agree_license = 'Я согласен с данной лицензией'; $lang->cmd_install_fix_checklist = 'Я удоволетворил требуемые условия'; $lang->cmd_install_next = 'Продолжить установку'; @@ -343,10 +343,10 @@ EndOfLicense; $lang->db_database_file = 'Файл базы данных'; $lang->db_table_prefix = 'Префикс таблиц'; - $lang->admin_title = 'Административная Информация'; + $lang->admin_title = 'Административная информация'; $lang->env_title = 'Конфигурация'; - $lang->use_optimizer = 'Включить Оптимизатор'; + $lang->use_optimizer = 'Включить оптимизатор'; $lang->about_optimizer = 'Если оптимизатор включен, пользователи могут быстро использовать этот сайт, поскольку несколько CSS / JS файлов собраны вместе и сжаты до передачи.
      Тем не менее, эта оптимизация может быть проблематичной согласно CSS или JS. Если Вы выключите ее, движок будет работать правильно, хотя и медленее.'; $lang->use_rewrite = 'Использовать модуль перезаписи (rewrite mod)'; $lang->about_rewrite = "Если сервер предлагает rewrite mod, длинные URL такие как http://blah/?document_srl=123 могут быть сокращены до http://blah/123"; @@ -355,8 +355,8 @@ EndOfLicense; $lang->about_database_file = 'Sqlite сохраняет данные в файл. Размещение базы данных должно быть недоступно с веб
      Файл базы данных должен иметь права доступа 707.'; - $lang->success_installed = 'Установка Завершена'; - $lang->success_updated = 'Обновление Завершено'; + $lang->success_installed = 'Установка завершена'; + $lang->success_updated = 'Обновление завершено'; $lang->msg_cannot_proc = 'Невозможно исполнить запрос, поскольку окружение установки не указано'; $lang->msg_already_installed = 'Zeroboard уже установлена'; diff --git a/modules/integration_search/conf/info.xml b/modules/integration_search/conf/info.xml index 011ab646d..0c321b861 100644 --- a/modules/integration_search/conf/info.xml +++ b/modules/integration_search/conf/info.xml @@ -5,12 +5,14 @@ 統合検索 Integration Search Búsqueda Integrada + Интегрируемый поиск 제로 zero Zero zero zero + zero 선택한 모듈들을 대상으로 통합검색을 지원합니다. 선택된 모듈의 글중 비밀글만 검색을 하지 않고 나머지는 모두 검색을 하기에 공개되지 않은 모듈은 대상에 포함하지 않도록 하셔야 합니다. @@ -24,11 +26,15 @@ It supports integration search for chosen modules. - All articles except secret articles will be searched, so you need to be careful not to include secret module to target . + All articles except secret articles will be searched, so you need to be careful not to include secret module to target. Soporta la búsqueda integrada de los módulos elegidos. Todo los documentos excepto los secretos serán buscados, y es necesario tener cuidado de no incluir módulo secreto como objetivo. + + Поддерживает интеграцию поиска в выбранные модули. + Все статьи, за исключением секретных, будут подлежать поиску, поэтому Вам нужно быть осторожным с тем, чтобы не включить модуль секретов в назначение. + diff --git a/modules/integration_search/lang/ru.lang.php b/modules/integration_search/lang/ru.lang.php index 26ec9acbb..dc177df98 100644 --- a/modules/integration_search/lang/ru.lang.php +++ b/modules/integration_search/lang/ru.lang.php @@ -5,9 +5,9 @@ * @brief Russian basic language pack for Zeroboard XE **/ - $lang->integration_search = "Интеграция Поиска"; + $lang->integration_search = "Интеграция поиска"; - $lang->sample_code = "Код Примера"; + $lang->sample_code = "Код примера"; $lang->about_target_module = "Только выбранные модули являются назначением. Пожалуйста, будте осторожны, устанавливая контроль"; $lang->about_sample_code = "Вы можете добавить интеграцию поиска на лейаут посредством добавления выше указанного кода"; $lang->msg_no_keyword = "Введите ключевое слово для поиска"; @@ -23,9 +23,9 @@ ); $lang->is_sort_option = array( - 'regdate' => 'Дата Регистрации', - 'comment_count' => 'Кол-во Комментариев', - 'readed_count' => 'Кол-во Хитов', - 'voted_count' => 'Кол-во Голосов', + 'regdate' => 'Дата регистрации', + 'comment_count' => 'Кол-во комментариев', + 'readed_count' => 'Кол-во хитов', + 'voted_count' => 'Кол-во голосов', ); ?> diff --git a/modules/krzip/conf/info.xml b/modules/krzip/conf/info.xml index 67b0378ff..dbc07b471 100644 --- a/modules/krzip/conf/info.xml +++ b/modules/krzip/conf/info.xml @@ -5,12 +5,14 @@ Código postal de Corea 韩国邮编 韓国郵便番号 + Корейский почтовый индекс 제로 - Zero + zero Zero zero Zero + zero 제로보드에서 운영하는 우편번호서버를 이용하여 우편번호 검색을 합니다. 우편번호 검색 서버는 설정을 통해 변경하실 수 있습니다. @@ -31,5 +33,9 @@ ゼロボードで運用している郵便番号サーバを利用して韓国の郵便番号を検索します。 郵便番号検索サーバは設定によって変更することができます。 + + Поиск индекса через сервер почтовый индексов, оперируемый zeroboard. + Вы можете изменить сервер почтовых индексов в настройках. + diff --git a/modules/krzip/lang/ru.lang.php b/modules/krzip/lang/ru.lang.php index db73c3d24..93e04ae60 100644 --- a/modules/krzip/lang/ru.lang.php +++ b/modules/krzip/lang/ru.lang.php @@ -6,7 +6,7 @@ **/ // нормальные слова - $lang->krzip = "Корейский Почтовый Индекс"; + $lang->krzip = "Корейский почтовый индекс"; $lang->krzip_server_hostname = "Имя сервера для проверки почтового индекса"; $lang->krzip_server_port = "Порт сервера для проверки почтового индекса"; $lang->krzip_server_query = "Путь на сервере для проверки почтового индекса"; diff --git a/modules/layout/conf/info.xml b/modules/layout/conf/info.xml index de17765ce..c512e8670 100644 --- a/modules/layout/conf/info.xml +++ b/modules/layout/conf/info.xml @@ -5,16 +5,19 @@ レイアウト Layout Diseño + Лейаут 제로 zero Zero zero zero + zero 레이아웃을 생성/관리하는 모듈입니다. 生成/管理布局的模块。 レイアウトを生成・管理するモジュールです。 - This module is for creating/managing. + This module is for creating/managing of layouts. Este módulo es para crear y manejar el diseño. + Этот модуль служит для создания/управления лейаутами. diff --git a/modules/layout/lang/ru.lang.php b/modules/layout/lang/ru.lang.php index 161e82f9f..20a59c2a7 100644 --- a/modules/layout/lang/ru.lang.php +++ b/modules/layout/lang/ru.lang.php @@ -5,18 +5,18 @@ * @brief Russian basic language pack for Zeroboard XE **/ - $lang->cmd_layout_management = 'Настройки Лейаута'; - $lang->cmd_layout_edit = 'Редактировать Лейаут'; + $lang->cmd_layout_management = 'Настройки лейаута'; + $lang->cmd_layout_edit = 'Редактировать лейаут'; - $lang->layout_name = 'Имя Лейаута'; - $lang->layout_maker = "Разработчик Лейаута"; + $lang->layout_name = 'Имя лейаута'; + $lang->layout_maker = "Разработчик лейаута"; $lang->layout_history = "Обновления"; - $lang->layout_info = "Информация Лейаута"; - $lang->layout_list = 'Список Лейаутов'; + $lang->layout_info = "Информация лейаута"; + $lang->layout_list = 'Список лейаутов'; $lang->menu_count = 'Меню'; - $lang->downloaded_list = 'Список Закачек'; + $lang->downloaded_list = 'Список закачек'; $lang->layout_preview_content = 'Содержимое отображается здесь'; - $lang->not_apply_menu = 'Применить Лейауты'; + $lang->not_apply_menu = 'Применить лейауты'; $lang->cmd_move_to_installed_list = "Просмотреть созданный список"; diff --git a/modules/member/conf/info.xml b/modules/member/conf/info.xml index ad650f5cc..2908e23c7 100644 --- a/modules/member/conf/info.xml +++ b/modules/member/conf/info.xml @@ -5,16 +5,19 @@ 会員 Member Usuario + Пользователи 제로 zero Zero zero zero + zero 회원 관리 및 회원 관련 설정등을 하는 모듈입니다. 对会员进行管理及相关设置的模块。 会員管理及び会員関連設定などを行うためのモジュールです。 This module is for managing or configuring members. Este módulo es para el manejo y la configuración de los usuarios. + Этот модуль служит для управления и конфигурирования пользователей. diff --git a/modules/member/lang/ru.lang.php b/modules/member/lang/ru.lang.php index a05f38f4a..fbb03e0e0 100644 --- a/modules/member/lang/ru.lang.php +++ b/modules/member/lang/ru.lang.php @@ -6,11 +6,11 @@ **/ $lang->member = 'Пользователь'; - $lang->member_default_info = 'Базовая Информация'; - $lang->member_extend_info = 'Дополнительная Информация'; - $lang->default_group_1 = "Общая Группа"; - $lang->default_group_2 = "Особая Группа"; - $lang->admin_group = "Администативная Группа"; + $lang->member_default_info = 'Базовая информация'; + $lang->member_extend_info = 'Дополнительная информация'; + $lang->default_group_1 = "Общая группа"; + $lang->default_group_2 = "Особая группа"; + $lang->admin_group = "Администативная группа"; $lang->remember_user_id = 'Сохранить ID'; $lang->already_logged = "Вы уже вошли"; $lang->denied_user_id = 'Извините. Этот ID запрещен.'; @@ -19,45 +19,45 @@ $lang->invalid_authorization = 'Не авторизировано'; $lang->invalid_user_id= "Указанный ID не существует"; $lang->invalid_password = 'Неверный пароль'; - $lang->allow_mailing = 'Присоединиться к Списку Рассылки'; - $lang->allow_message = 'Разрешить Прием Сообщений'; + $lang->allow_mailing = 'Присоединиться к списку рассылки'; + $lang->allow_message = 'Разрешить прием сообщений'; $lang->allow_message_type = array( - 'Y' => 'Принимать Все', - 'N' => 'Отклонять Все', - 'F' => 'Только Друзья', + 'Y' => 'Принимать все', + 'N' => 'Отклонять все', + 'F' => 'Только друзья', ); $lang->denied = 'Отказано'; - $lang->is_admin = 'Суперадминистративные Права'; - $lang->group = 'Присвоенная Группа'; - $lang->group_title = 'Имя Группы'; - $lang->group_srl = 'Номер Группы'; + $lang->is_admin = 'Суперадминистративные права'; + $lang->group = 'Присвоенная группа'; + $lang->group_title = 'Имя группы'; + $lang->group_srl = 'Номер группы'; $lang->signature = 'Подпись'; - $lang->profile_image = 'Изображение Профиля'; - $lang->profile_image_max_width = 'Макс. Ширина'; - $lang->profile_image_max_height = 'Макс. Высота'; - $lang->image_name = 'Имя Изображения'; - $lang->image_name_max_width = 'Макс. Ширина'; - $lang->image_name_max_height = 'Макс. Высота'; + $lang->profile_image = 'Изображение профиля'; + $lang->profile_image_max_width = 'Макс. ширина'; + $lang->profile_image_max_height = 'Макс. высота'; + $lang->image_name = 'Имя изображения'; + $lang->image_name_max_width = 'Макс. ширина'; + $lang->image_name_max_height = 'Макс. высота'; $lang->image_mark = 'Изображение-марка'; - $lang->image_mark_max_width = 'Макс. Ширина'; - $lang->image_mark_max_height = 'Макс. Высота'; - $lang->enable_openid = 'Включить Открытый ID (OpenID)'; - $lang->enable_join = 'Позволить Пользователям Регистрироваться'; - $lang->limit_day = 'Временный Лимит Даты'; - $lang->limit_date = 'Дата Лимита'; - $lang->redirect_url = 'URL после Регистрации'; - $lang->agreement = 'Пользовательское Соглашение Регистрации'; + $lang->image_mark_max_width = 'Макс. ширина'; + $lang->image_mark_max_height = 'Макс. высота'; + $lang->enable_openid = 'Включить открытый ID (OpenID)'; + $lang->enable_join = 'Позволить пользователям регистрироваться'; + $lang->limit_day = 'Временный лимит даты'; + $lang->limit_date = 'Дата лимита'; + $lang->redirect_url = 'URL после регистрации'; + $lang->agreement = 'Пользовательское соглашение о регистрации'; $lang->accept_agreement = 'Согласен'; $lang->sender = 'Отправитель'; $lang->receiver = 'Получатель'; - $lang->friend_group = 'Группа Друзей'; - $lang->default_friend_group = 'Неприсвоенная Группа'; - $lang->member_info = 'Пользовательская Информация'; - $lang->current_password = 'Текущий Пароль'; + $lang->friend_group = 'Группа друзей'; + $lang->default_friend_group = 'Неприсвоенная группа'; + $lang->member_info = 'Пользовательская информация'; + $lang->current_password = 'Текущий пароль'; $lang->openid = 'OpenID'; - $lang->webmaster_name = "Имя Веб-мастера"; - $lang->webmaster_email = "Email Веб-мастера"; + $lang->webmaster_name = "Имя веб-мастера"; + $lang->webmaster_email = "Email веб-мастера"; $lang->about_webmaster_name = "Пожалуйста, введите имя веб-мастера, которое будет использоваться для аутентификационных писем или другого адиминистрирования сайта. (по умолчанию : webmaster)"; $lang->about_webmaster_email = "Пожалуйста, введите email адрес веб-мастера."; @@ -67,46 +67,46 @@ 'user_name' => 'Имя', 'nick_name' => 'Ник', 'email_address' => 'Email', - 'regdate' => 'Дата Регистрации', - 'last_login' => 'Дата Последнего Входа', - 'extra_vars' => 'Экстра Перем.', + 'regdate' => 'Дата регистрации', + 'last_login' => 'Дата последнего входа', + 'extra_vars' => 'Экстра перем.', ); $lang->message_box = array( 'R' => 'Принятые', 'S' => 'Отправленные', - 'T' => 'Почтовый Ящик', + 'T' => 'Почтовый ящик', ); - $lang->readed_date = "Дата Прочтения"; + $lang->readed_date = "Дата прочтения"; $lang->cmd_login = 'Войти'; $lang->cmd_logout = 'Выйти'; $lang->cmd_signup = 'Регистрация'; - $lang->cmd_modify_member_info = 'Изменить Информацию Пользователя'; - $lang->cmd_modify_member_password = 'Изменить Пароль'; - $lang->cmd_view_member_info = 'Информация Пользователя'; + $lang->cmd_modify_member_info = 'Изменить информацию пользователя'; + $lang->cmd_modify_member_password = 'Изменить пароль'; + $lang->cmd_view_member_info = 'Информация пользователя'; $lang->cmd_leave = 'Покинуть'; - $lang->cmd_find_member_account = 'Найти Информацию Аккаунта'; + $lang->cmd_find_member_account = 'Найти информацию аккаунта'; - $lang->cmd_member_list = 'Список Пользователей'; - $lang->cmd_module_config = 'Стандартные Настройки'; - $lang->cmd_member_group = 'Увтавление Группами'; - $lang->cmd_send_mail = 'Отправить Почту'; - $lang->cmd_manage_id = 'Управление Запрещенными ID'; - $lang->cmd_manage_form = 'Управление Формой Регистрации'; - $lang->cmd_view_own_document = 'Просмотреть Написанные Статьи'; + $lang->cmd_member_list = 'Список пользователей'; + $lang->cmd_module_config = 'Стандартные настройки'; + $lang->cmd_member_group = 'Увтавление группами'; + $lang->cmd_send_mail = 'Отправить почту'; + $lang->cmd_manage_id = 'Управление запрещенными ID'; + $lang->cmd_manage_form = 'Управление формой регистрации'; + $lang->cmd_view_own_document = 'Просмотреть написанные статьи'; $lang->cmd_view_scrapped_document = 'Черновики'; - $lang->cmd_view_saved_document = 'Просмотреть Сохраненные Статьи'; - $lang->cmd_send_email = 'Отправить Почту'; - $lang->cmd_send_message = 'Отправить Сообщение'; + $lang->cmd_view_saved_document = 'Просмотреть сохраненные статьи'; + $lang->cmd_send_email = 'Отправить почту'; + $lang->cmd_send_message = 'Отправить сообщение'; $lang->cmd_reply_message = 'Ответить'; $lang->cmd_view_friend = 'Дзузья'; - $lang->cmd_add_friend = 'Сделать Другом'; - $lang->cmd_view_message_box = 'Ящик Сообщений'; + $lang->cmd_add_friend = 'Сделать другом'; + $lang->cmd_view_message_box = 'Ящик сообщений'; $lang->cmd_store = "Сохранить"; - $lang->cmd_add_friend_group = 'Добавить Группу Друзей'; - $lang->cmd_rename_friend_group = 'Изменить Имя Группы Друзей'; + $lang->cmd_add_friend_group = 'Добавить группу друзей'; + $lang->cmd_rename_friend_group = 'Изменить имя группы друзей'; $lang->msg_email_not_exists = "Email адрес не существует"; @@ -115,7 +115,7 @@ $lang->msg_cart_is_null = 'Пожалуйста, выберите назначение'; $lang->msg_checked_file_is_deleted = '%d вложенных файлов удалено'; - $lang->msg_find_account_title = 'Информация Аккаунта'; + $lang->msg_find_account_title = 'Информация аккаунта'; $lang->msg_find_account_info = 'Это требуемая информация аккаунта.'; $lang->msg_find_account_comment = 'Пароль будет изменен на указанный выше после нажатия по ссылке ниже.
      Пожалуйста, изменить пароль после входа.'; $lang->msg_auth_mail_sended = 'Аутентификационное почтовое сообщение было отправлено для %s. Пожалуйста, проверьте Вашу почту.'; @@ -125,8 +125,8 @@ $lang->msg_no_message = 'Нет сообщений'; $lang->message_received = 'Новое сообщение'; - $lang->msg_new_member = 'Добавить Пользователя'; - $lang->msg_update_member = 'Изменить Информацию Пользователя'; + $lang->msg_new_member = 'Добавить пользователя'; + $lang->msg_update_member = 'Изменить информацию пользователя'; $lang->msg_leave_member = 'Покинуть'; $lang->msg_group_is_null = 'Нет зарегистрированной группы'; $lang->msg_not_delete_default = 'Стандартные объекты не могут быть удалены'; diff --git a/modules/menu/conf/info.xml b/modules/menu/conf/info.xml index 7bfb204bd..518251ef4 100644 --- a/modules/menu/conf/info.xml +++ b/modules/menu/conf/info.xml @@ -5,16 +5,19 @@ メニュー Menu Menú + Меню 제로 zero Zero zero zero + zero 레이아웃, 모듈을 연결하는 메뉴를 생성/관리하는 모듈입니다. 此模块将生成并管理连接布局,模块的菜单。 レイアウト、モジュールを連動させるメニューを作成・管理するモジュールです。 This module is for creating/managering menues that linking layouts or modules. Este módulo es para crear/manejar los menús que que son conectados con los diseños o módulos. + Этот модуль служит создания/управления меню, которые соединяют лейауты и модули. diff --git a/modules/message/conf/info.xml b/modules/message/conf/info.xml index 7caaca89b..c23f52631 100644 --- a/modules/message/conf/info.xml +++ b/modules/message/conf/info.xml @@ -5,16 +5,19 @@ 错误信息 Display Errors Mostrar el error + Отображение ошибок 제로 Zero zero zero zero + zero 오류 및 각종 시스템 메세지 관리 모듈 エラー及びシステムメッセージ管理モジュール 管理错误信息及各种系统信息的模块。 - This module managers erros and system messages - Este módulo es para manejar los errores y mensajes del sistema + This module managers erros and system messages. + Este módulo es para manejar los errores y mensajes del sistema. + Этот модуль управляет ошибками и системными сообщениями. diff --git a/modules/module/conf/info.xml b/modules/module/conf/info.xml index ece95f6fa..9068a1001 100644 --- a/modules/module/conf/info.xml +++ b/modules/module/conf/info.xml @@ -5,16 +5,19 @@ モジュール Module Módulo + Модули 제로 zero Zero zero zero + zero 모듈 생성 및 관리하는 모듈입니다. 生成及管理模块的模块。 モジュールの生成、管理するモジュールです。 This module is for creating/managering the other modules. Este módulo is para crear y manejar los otros módulos. + Этот модуль служит для создания/управления другими модулями. diff --git a/modules/module/lang/ru.lang.php b/modules/module/lang/ru.lang.php index 3c9918e11..0d2355130 100644 --- a/modules/module/lang/ru.lang.php +++ b/modules/module/lang/ru.lang.php @@ -5,32 +5,32 @@ * @brief Russian basic language pack for Zeroboard XE **/ - $lang->module_list = "Список Модулей"; - $lang->module_index = "Список Модулей"; - $lang->module_category = "Категория Модуля"; + $lang->module_list = "Список модулей"; + $lang->module_index = "Список модулей"; + $lang->module_category = "Категория модуля"; $lang->module_info = "Информация"; - $lang->add_shortcut = "Добавить Ярлыки"; + $lang->add_shortcut = "Добавить ярлыки"; $lang->module_action = "Действия"; - $lang->module_maker = "Разработчик Модуля"; - $lang->module_history = "История Обновлений"; - $lang->category_title = "Название Категории"; - $lang->header_text = 'Верхний Колонтитул'; - $lang->footer_text = 'Нижний Колонтитул'; - $lang->use_category = 'Включить Категорию'; - $lang->category_title = 'Название Категории'; + $lang->module_maker = "Разработчик модуля"; + $lang->module_history = "История обновлений"; + $lang->category_title = "Название категории"; + $lang->header_text = 'Верхний колонтитул'; + $lang->footer_text = 'Нижний колонтитул'; + $lang->use_category = 'Включить категорию'; + $lang->category_title = 'Название категории'; $lang->checked_count = 'Число выбранных статей'; // translator's note: возможно "checked" следует перевести как "проверенных" - $lang->skin_default_info = 'Информация Стандартного Скина'; - $lang->skin_maker = 'Разработчик Скина'; - $lang->skin_maker_homepage = "Домашняя Страница Разработчика"; - $lang->module_copy = "Копировать Модуль"; + $lang->skin_default_info = 'Информация стандартного скина'; + $lang->skin_maker = 'Разработчик скина'; + $lang->skin_maker_homepage = "Домашняя страница разработчика"; + $lang->module_copy = "Копировать модуль"; - $lang->cmd_add_shortcut = "Добавить Ярлык"; + $lang->cmd_add_shortcut = "Добавить ярлык"; $lang->cmd_install = "Установить"; $lang->cmd_update = "Обновить"; - $lang->cmd_manage_category = 'Управление Категориями'; - $lang->cmd_manage_grant = 'Управление Правами Доступа'; - $lang->cmd_manage_skin = 'Управление Скинами'; - $lang->cmd_manage_document = 'Управление Статьями'; + $lang->cmd_manage_category = 'Управление категориями'; + $lang->cmd_manage_grant = 'Управление правами доступа'; + $lang->cmd_manage_skin = 'Управление скинами'; + $lang->cmd_manage_document = 'Управление статьями'; $lang->msg_new_module = "Создать новый модуль"; $lang->msg_update_module = "Изменить модуль"; diff --git a/modules/opage/conf/info.xml b/modules/opage/conf/info.xml index 214e0e916..7e8de2b8d 100644 --- a/modules/opage/conf/info.xml +++ b/modules/opage/conf/info.xml @@ -2,19 +2,22 @@ 외부 페이지 外部页面 - 外部ページ + 外でページ External Page Afuera Página + Внешние страницы 제로 zero Zero - Zero + zero zero + zero 외부페이지를 제로보드XE내부로 삽입시키는 모듈 可以把外部页面插入到 Zeroboard XE内部的模块。 - 外部ページをゼロボードXEに挿入するモジュールです。 - Module for inserting external pages into inside of Zeroboard XE + 외부페이지를 제로보드XE내부로 삽입시키는 모듈 + Module for inserting external pages into inside of Zeroboard XE. 외부페이지를 제로보드XE내부로 삽입시키는 모듈 + Модуль для вставки внешних страниц внутрь Zeroboard XE. diff --git a/modules/opage/lang/ru.lang.php b/modules/opage/lang/ru.lang.php index 59fa5cd63..7186cdbea 100644 --- a/modules/opage/lang/ru.lang.php +++ b/modules/opage/lang/ru.lang.php @@ -5,9 +5,9 @@ * @brief Russian basic language pack for Zeroboard XE **/ - $lang->opage = "Внешняя Страница"; - $lang->opage_path = "Расположение Внешнего Документа"; - $lang->opage_caching_interval = "Установить Время Кеширования"; + $lang->opage = "Внешняя страница"; + $lang->opage_path = "Расположение внешнего документа"; + $lang->opage_caching_interval = "Установить время кеширования"; $lang->about_opage = "Этот модуль позволяет использовать внешние HTML или PHP файлы в Zeroboard XE.
      Требует ввода абсолютного или относительного пути. Если URL начинается с 'http://', внешняя страница с другого сервера будет показана."; $lang->about_opage_path= "Пожалуйста, введите размещение внешнего документа.
      Абсолютный путь как '/path1/path2/sample.php', так и относительный как '../path2/sample.php' могут быть использованы.
      Если Вы введете путь как 'http://url/sample.php', результат будет сначала получен и затем показан.
      Это текущий абсолютный путь к Zeroboard XE.
      "; diff --git a/modules/page/conf/info.xml b/modules/page/conf/info.xml index e11c30387..af061ec1f 100644 --- a/modules/page/conf/info.xml +++ b/modules/page/conf/info.xml @@ -5,16 +5,19 @@ ページ Page Página + Страницы 제로 zero Zero zero zero + zero 페이지를 제작하여 컨텐츠로 연결할 수 있는 모듈 制作页面并能连接到内容区的模块。 ページを作成してコンテンツとしてリンクできるようにするためのモジュールです。 This module is for creating pages to link with contents. Este módulo is para crear página para enlazar con contenidos. + Этот модуль служит для создания страниц, чтобы связать их с содержимым. diff --git a/modules/point/conf/info.xml b/modules/point/conf/info.xml index d832ae89d..44c68f7c0 100644 --- a/modules/point/conf/info.xml +++ b/modules/point/conf/info.xml @@ -5,12 +5,14 @@ ポイントシステム Point System Sistema de Punto + Система поитов 제로 Zero Zero zero - zero + zero + zero 글작성/삭제/댓글작성/삭제시에 포인트를 부여할 수 있습니다. 포인트마다 레벨을 지정하여 사용자 이름 앞에 아이콘을 표시할 수도 있습니다. @@ -34,5 +36,10 @@ Usted también puede mostrar el ícono de punto delande del nombre del usuario seleccionando el nivel sobre cada puntos. Pero para activar esas funciones, Usted necesita activar addon relacionado a los puntos. + + Вы можете назначать поинты за написание/удаление/добавление комментариев/удаление комментариев. + Вы также можете отображать икнку поинтов напротив имени пользователя, установив уровени для поинтов. + Но чтобы включить эти функции, Вам надо активировать аддоны, относящиеся к поинтам. + diff --git a/modules/point/lang/ru.lang.php b/modules/point/lang/ru.lang.php index c3d8cb842..1cb952de1 100644 --- a/modules/point/lang/ru.lang.php +++ b/modules/point/lang/ru.lang.php @@ -11,37 +11,37 @@ $lang->about_point_module = "Вы можете распределять поинты за написание/добавление комментариев, закачку/скачку файлов.
      Модуль поинтов только конфигурирует настройки, а набор поинтов будет осуществлять, если только аддон поинтов будет активирован"; $lang->about_act_config = "Каждый модуль, такой как форум/блог, имеет имеет свои действия, такие как\"написание/удаление/добавление комментариев/удаление комментариев\".
      Вы можете просто добавить значения действий, чтобы связать ситему поинтов, за исключением форума/блога.
      Запятая(,) используется как разделитель значений."; - $lang->max_level = 'Макс. Уровень'; + $lang->max_level = 'Макс. уровень'; $lang->about_max_level = 'Вы можете установить максимальный уровень. Иконки уровней должны быть присвоены. (макс. значение равно 1000)'; - $lang->level_icon = 'Иконка Уровня'; + $lang->level_icon = 'Иконка уровня'; $lang->about_level_icon = 'Путь иконок уровней "./module/point/icons/[level].gif" и максимальный уровень может меняться с набором иконок. Поэтому будте осторожны'; - $lang->point_name = 'Имя Поинта'; + $lang->point_name = 'Имя поинта'; $lang->about_point_name = 'Вы можете дать имя или единицу измерения для поинта'; - $lang->level_point = 'Уровень Поинтов'; + $lang->level_point = 'Уровень поинтов'; $lang->about_level_point = 'Уровень будет изменен, когда поинты достигают каждого уровня поинтов или падают ниже его'; - $lang->disable_download = 'Запретить Скачивание'; + $lang->disable_download = 'Запретить скачивание'; $lang->about_disable_download = "Это запретит скачивание файлов, когда не хватает достаточного кол-ва поинтов. (За исключением файлов изображений)"; $lang->about_module_point = "Вы можете установть поинты для каждого модуля, а модули, не имеющие значения будут использовать значение по умолчанию для поинтов.
      Все поинты будут восстановлены при обратном действии."; $lang->point_signup = 'Присвоить'; - $lang->point_insert_document = 'При Написании'; - $lang->point_delete_document = 'При Удалении'; - $lang->point_insert_comment = 'При Добавлении Комментариев'; - $lang->point_delete_comment = 'При Удалении Комментариев'; - $lang->point_upload_file = 'При Закачке Файлов'; - $lang->point_delete_file = 'При Скачке Файлов'; - $lang->point_download_file = 'При Скачке Файлов (кроме изображений)'; + $lang->point_insert_document = 'При написании'; + $lang->point_delete_document = 'При удалении'; + $lang->point_insert_comment = 'При добавлении комментариев'; + $lang->point_delete_comment = 'При удалении комментариев'; + $lang->point_upload_file = 'При закачке файлов'; + $lang->point_delete_file = 'При скачке файлов'; + $lang->point_download_file = 'При скачке файлов (кроме изображений)'; - $lang->cmd_point_config = 'Настройки По Умолчанию'; - $lang->cmd_point_module_config = 'Настройки Модуля'; - $lang->cmd_point_act_config = 'Настройки Действий'; - $lang->cmd_point_member_list = 'Список Поинтов Пользователей'; + $lang->cmd_point_config = 'Настройки по умолчанию'; + $lang->cmd_point_module_config = 'Настройки модуля'; + $lang->cmd_point_act_config = 'Настройки действий'; + $lang->cmd_point_member_list = 'Список поинтов пользователей'; $lang->msg_cannot_download = "У Вас нет достаточного количества поитов, чтобы иметь разрешение скачивать файлы."; ?> diff --git a/modules/poll/conf/info.xml b/modules/poll/conf/info.xml index dd2109f2d..a6dac0f35 100644 --- a/modules/poll/conf/info.xml +++ b/modules/poll/conf/info.xml @@ -5,16 +5,19 @@ アンケート Poll Encuesta + Опрос 제로 zero Zero zero zero + zero 설문조사 관리 모듈 管理投票调查的模块。 アンケート管理モジュール This module is for managering polls. - Este módulo es para manejar las encuestas. + Este módulo es para manejar las encuestas. + Этот модуль служит для управления опросами. diff --git a/modules/poll/lang/ru.lang.php b/modules/poll/lang/ru.lang.php index 919a3df14..79beb3f3b 100644 --- a/modules/poll/lang/ru.lang.php +++ b/modules/poll/lang/ru.lang.php @@ -6,7 +6,7 @@ **/ $lang->poll = "Опрос"; - $lang->poll_stop_date = "Дата Истечения"; + $lang->poll_stop_date = "Дата истечения"; $lang->poll_join_count = "Участников"; $lang->poll_checkcount = "Число полей выбора"; diff --git a/modules/referer/conf/info.xml b/modules/referer/conf/info.xml index c0cb69fac..91303a5c1 100644 --- a/modules/referer/conf/info.xml +++ b/modules/referer/conf/info.xml @@ -2,10 +2,13 @@ 리퍼러 통계 Referer Statistics + Статистика рефералов haneul haneul + haneul 기본 리퍼러 통계 프로그램입니다. Basic referer statistics program. + Базовая программа статистики рефералов. diff --git a/modules/referer/lang/ru.lang.php b/modules/referer/lang/ru.lang.php new file mode 100644 index 000000000..16272e3d2 --- /dev/null +++ b/modules/referer/lang/ru.lang.php @@ -0,0 +1,10 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->referer = "Реферал"; + $lang->ranking = "Рейтинг"; +?> diff --git a/modules/rss/conf/info.xml b/modules/rss/conf/info.xml index 9644945e4..5709494f3 100644 --- a/modules/rss/conf/info.xml +++ b/modules/rss/conf/info.xml @@ -5,16 +5,19 @@ RSS RSS RSS + RSS 제로 zero Zero zero - zero + zero + zero RSS 출력을 담당하는 모듈 负责输出RSS的模块。 RSS出力を担うモジュールです。 This modules is for printing RSS. - Este módulo es para imprimir RSS. + Este módulo es para imprimir RSS. + Этот модуль служит для печати RSS. diff --git a/modules/spamfilter/conf/info.xml b/modules/spamfilter/conf/info.xml index 0980cc375..e1d21d469 100644 --- a/modules/spamfilter/conf/info.xml +++ b/modules/spamfilter/conf/info.xml @@ -5,16 +5,19 @@ Spam Filter Filtro de Spam スパムフィルター + Фильтр спама 제로 zero zero zero Zero + zero 제로보드 XE의 기본 스팸필터입니다. Zeroboard XE的基本垃圾过滤模块。 A default spam filter of Zeroboard XE. Filtro de Span predefinido de Zeroboard XE. ゼロボードXEのスパムフィルターです。 + Стандартный фильтр спама Zeroboard XE. diff --git a/modules/spamfilter/lang/ru.lang.php b/modules/spamfilter/lang/ru.lang.php index 0e7b5a979..7e9e9ddfd 100644 --- a/modules/spamfilter/lang/ru.lang.php +++ b/modules/spamfilter/lang/ru.lang.php @@ -6,8 +6,8 @@ **/ // действия - $lang->cmd_denied_ip = "Черный Список IP-адресов"; - $lang->cmd_denied_word = "Черный Список Слов"; + $lang->cmd_denied_ip = "Черный список IP-адресов"; + $lang->cmd_denied_word = "Черный список слов"; // главные слова $lang->spamfilter = "Фильтр спама"; diff --git a/modules/springnote/conf/info.xml b/modules/springnote/conf/info.xml index fb8712857..2a1df12a3 100644 --- a/modules/springnote/conf/info.xml +++ b/modules/springnote/conf/info.xml @@ -2,10 +2,13 @@ 스프링노트 연동 Springnote + Спрингноут 제로 Zero + Zero 스프링노트의 페이지를 제로보드XE에서 연동하여 출력하는 기능을 가지고 있는 모듈입니다. This modules links pages of Springnote with ZeroboardXE, and display them. + Этот модуль связывает страницы Springnote с ZeroboardXE, и отображает их. diff --git a/modules/springnote/lang/ru.lang.php b/modules/springnote/lang/ru.lang.php new file mode 100644 index 000000000..e475cfc07 --- /dev/null +++ b/modules/springnote/lang/ru.lang.php @@ -0,0 +1,24 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->springnote = "Спрингноут"; + $lang->springnote_openid = "Открытый ID"; + $lang->springnote_userkey = "Ключ юзера"; + $lang->springnote_pageid = "Номер страницы"; + + $lang->page_url = "Оригинальный URL"; + $lang->page_modified = "Последняя модификация"; + $lang->page_modifier = "Последний модификатор"; + + $lang->cmd_springnote_list = 'Список спрингноутов'; + $lang->cmd_view_info = 'Спрингноут инфо'; + + $lang->about_springnote = "Спрингноут (Springnote) - это Вики Служба (Wiki Service), которую предоставляет Openmaru.
      Springnote ZeroboardXE модуль отображает определенные спрингноут страницы как внутренние документы."; + $lang->about_springnote_openid = "Пожалуйста, введите Ваш OpenID, который создал Springnote."; + $lang->about_springnote_userkey = 'Ключ юзера нужен для того, чтобы включить Springnote модуль.
      Пожалуйста, введи сгенерированный Ключ Юзера после ввода Вашего OpenID на [Получить Ключ Юзера] .'; + $lang->about_springnote_pageid = 'Пожалуйста, введите pageid, если вы хотите отобразить определенную страницу сначала.'; +?> diff --git a/modules/tag/conf/info.xml b/modules/tag/conf/info.xml index e973f6570..d85c8778b 100644 --- a/modules/tag/conf/info.xml +++ b/modules/tag/conf/info.xml @@ -5,16 +5,19 @@ タグ Tag Etiqueta + Теги 제로 zero Zero - Zero + zero Zero + zero 꼬리표 관리 모듈 标签管理模块。 タグ管理用のモジュールです。 - Module for managing tags - Módulo para manejar etiquetas + Module for managing tags. + Módulo para manejar etiquetas. + Модуль для управления тегами. diff --git a/modules/trackback/conf/info.xml b/modules/trackback/conf/info.xml index f69768489..a909535c1 100644 --- a/modules/trackback/conf/info.xml +++ b/modules/trackback/conf/info.xml @@ -5,16 +5,19 @@ トラックバック Trackback Trackback + Трекбек 제로 zero Zero - Zero - Zero + zero + Zero + zero 엮인글 관리 모듈 管理引用模块。 トラックバック管理モジュール - Module for managing trackbacks - Módulo para el manejo de trackbacks + Module for managing trackbacks. + Módulo para el manejo de trackbacks. + Модуль для управления трекбеками. diff --git a/modules/trackback/lang/ru.lang.php b/modules/trackback/lang/ru.lang.php index 7007e6298..52dc9017f 100644 --- a/modules/trackback/lang/ru.lang.php +++ b/modules/trackback/lang/ru.lang.php @@ -11,11 +11,11 @@ $lang->msg_checked_trackback_is_deleted = '%d трекбеков удалено.'; $lang->search_target_list = array( - 'url' => 'URL Назначения', - 'blog_name' => 'Имя Сайта', + 'url' => 'URL назначения', + 'blog_name' => 'Имя сайта', 'title' => 'Заголовок', 'excerpt' => 'Выдержка', - 'regdate' => 'Дата Отправки', + 'regdate' => 'Дата отправки', 'ipaddress' => 'IP-адрес', ); diff --git a/modules/ttimporter/conf/info.xml b/modules/ttimporter/conf/info.xml new file mode 100644 index 000000000..1a6a3e464 --- /dev/null +++ b/modules/ttimporter/conf/info.xml @@ -0,0 +1,38 @@ + + + TatterTools 데이터 이전 + TatterTools 数据导入 + TTデータ移転 + Transfer data from TatterTools + Перенос данных из TatterTools + + 제로 + zero + Zero + zero + zero + + 태터툴즈의 백업파일을 제로보드XE에 입력을 하는 모듈입니다. + 첨부파일 포함하지 않은 백업파일이 필요합니다. + 첨부파일은 원주소에서 직접 다운로드를 하게 됩니다. + + + 导入TatterTools的备份文件到Zeroboard XE的模块。 + 需要不包含附件的备份文件。 + 附件将在原地址直接下载。 + + + TatterToolsのバックアップファイルをゼロボードXE用にデータの変換を行うモジュールです。添付ファイルを含まないバックアップファイルが必要です。添付ファイルは、元のアドレスからダウンロードします。 + + + Module for inputting TattertTools' backup file to ZeroboardXE. + Backup file without attachment is required. + Attachments will be downloaded from the original address. + + + Модуль для ввода данных бекап-файла из TattertTools в ZeroboardXE. + Требуется бекап-файл без вложений. + Вложения будут скачены с оригинального адреса. + + + diff --git a/modules/ttimporter/lang/ru.lang.php b/modules/ttimporter/lang/ru.lang.php new file mode 100644 index 000000000..1d9ae75b0 --- /dev/null +++ b/modules/ttimporter/lang/ru.lang.php @@ -0,0 +1,21 @@ + | translation by Maslennikov Evgeny aka X-[Vr]bL1s5 | e-mail: x-bliss[a]tut.by; ICQ: 225035467; + * @brief Russian basic language pack for Zeroboard XE + **/ + + $lang->ttimporter = "Имортировать данные Tetter Tools"; + $lang->about_tt_importer = "Вы можете ипортировать дынне Tetter Tools в любой модуль.\n Вложенный файл будет напрямую скачан через Веб, поэтому, пожалуйста, убедитесь в том, что оригинальный Tetter Tools работает."; + + $lang->target_module = "Модуль назначения"; + $lang->target_file = "XML файл назначения"; + $lang->target_url = "URL Блога"; + + $lang->cmd_continue = 'Продолжить'; + + $lang->msg_no_xml_file = 'Невозможно найти XML файл! Пожалуйста, проверьте URL.'; + $lang->msg_invalid_xml_file = 'Неверный тип XML файла!'; + $lang->msg_importing = 'Импортирование: %d (если будет задержка, пожалуйста, нажмите кнопку "Продолжить".)'; + $lang->msg_import_finished = 'Импортировано: %d (согласно состоянию, некоторые данные могут быть импортированы неверно.)'; +?> diff --git a/modules/widget/conf/info.xml b/modules/widget/conf/info.xml index da522c852..2c573be3a 100644 --- a/modules/widget/conf/info.xml +++ b/modules/widget/conf/info.xml @@ -5,16 +5,19 @@ ウィジェット Widget Widget + Виджеты 제로 zero Zero - Zero + zero Zero + zero 위젯 관리 모듈 控件管理模块。 ウィジェット管理モジュール - Module for managing widgets - Módulo para el manejo de widgets + Module for managing widgets. + Módulo para el manejo de widgets. + Модуль для управления виджетами. diff --git a/modules/widget/lang/ru.lang.php b/modules/widget/lang/ru.lang.php index 8f4f06f68..91a18a661 100644 --- a/modules/widget/lang/ru.lang.php +++ b/modules/widget/lang/ru.lang.php @@ -5,33 +5,33 @@ * @brief Russian basic language pack for Zeroboard XE **/ - $lang->cmd_generate_code = 'Генерировать Код'; + $lang->cmd_generate_code = 'Генерировать код'; - $lang->widget_name = 'Имя Виджета'; - $lang->widget_maker = 'Разработчик Виджета'; - $lang->widget_history = 'История Обновлений'; - $lang->widget_info = 'Информация Виджета'; + $lang->widget_name = 'Имя виджета'; + $lang->widget_maker = 'Разработчик виджета'; + $lang->widget_history = 'История обновлений'; + $lang->widget_info = 'Информация виджета'; $lang->widget_code = 'Код'; $lang->widget_cache = 'Кеш'; - $lang->widget_fix_width = 'Фиксированная Ширина'; + $lang->widget_fix_width = 'Фиксированная ширина'; $lang->widget_width = 'Ширина'; $lang->widget_position = 'Позиция'; - $lang->widget_position_none = 'Следующая Строка'; + $lang->widget_position_none = 'Следующая строка'; $lang->widget_position_left = 'Лево'; $lang->widget_position_right = 'Право'; $lang->widget_margin = 'Поля'; - $lang->widget_margin_top = 'Верхнее Поле'; - $lang->widget_margin_right = 'Правое Поле'; - $lang->widget_margin_bottom = 'Шижнее Поле'; - $lang->widget_margin_left= 'Левое Поле'; + $lang->widget_margin_top = 'Верхнее поле'; + $lang->widget_margin_right = 'Правое поле'; + $lang->widget_margin_bottom = 'Шижнее поле'; + $lang->widget_margin_left= 'Левое поле'; $lang->about_widget_fix_width = 'Пожалуйста, установите для фиксирования ширины.'; $lang->about_widget_width = 'Пожалуйста, установите ширину виджета.'; $lang->about_widget_position = 'Пожалуйста, выберите позицию виджета, если Вы хотите отобразить несколько виджетов в одной строке.'; $lang->about_widget_margin = "Вы можете установить поля виждета, т.е. его отступы со всех четырех сторон."; $lang->about_widget_cache = 'Кешированные данные будут использоваться на указанный срок.'; - $lang->generated_code = 'Сгенерированный Код'; + $lang->generated_code = 'Сгенерированный код'; $lang->msg_widget_is_not_exists = '%s виджет не существует.'; $lang->msg_widget_object_is_null = '%s объектов виджета не могут быть созданы.'; From cff79d0f6fa5fda7c349b42af24f7e586fe0bc29 Mon Sep 17 00:00:00 2001 From: mayoojin Date: Thu, 6 Dec 2007 18:44:42 +0000 Subject: [PATCH 143/265] git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3167 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/springnote/lang/ru.lang.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/springnote/lang/ru.lang.php b/modules/springnote/lang/ru.lang.php index e475cfc07..2712c473e 100644 --- a/modules/springnote/lang/ru.lang.php +++ b/modules/springnote/lang/ru.lang.php @@ -19,6 +19,6 @@ $lang->about_springnote = "Спрингноут (Springnote) - это Вики Служба (Wiki Service), которую предоставляет Openmaru.
      Springnote ZeroboardXE модуль отображает определенные спрингноут страницы как внутренние документы."; $lang->about_springnote_openid = "Пожалуйста, введите Ваш OpenID, который создал Springnote."; - $lang->about_springnote_userkey = 'Ключ юзера нужен для того, чтобы включить Springnote модуль.
      Пожалуйста, введи сгенерированный Ключ Юзера после ввода Вашего OpenID на [Получить Ключ Юзера] .'; + $lang->about_springnote_userkey = 'Ключ юзера нужен для того, чтобы включить Springnote модуль.
      Пожалуйста, введите сгенерированный Ключ Юзера после ввода Вашего OpenID на [Получить Ключ Юзера] .'; $lang->about_springnote_pageid = 'Пожалуйста, введите pageid, если вы хотите отобразить определенную страницу сначала.'; ?> From 030d7ab42085593a6e64c2b15ee06dc80a54e224 Mon Sep 17 00:00:00 2001 From: haneul Date: Fri, 7 Dec 2007 03:05:52 +0000 Subject: [PATCH 144/265] #306 refer: r3163 git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3168 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- widgets/tab_newest_document/tab_newest_document.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widgets/tab_newest_document/tab_newest_document.class.php b/widgets/tab_newest_document/tab_newest_document.class.php index eefd7595b..f31588ea8 100644 --- a/widgets/tab_newest_document/tab_newest_document.class.php +++ b/widgets/tab_newest_document/tab_newest_document.class.php @@ -88,7 +88,7 @@ $browser_title = $value->browser_title; $obj->module_srl = $module_srl; - $output = executeQuery("widgets.tab_newest_document.getNewestDocuments", $obj); + $output = executeQueryArray("widgets.tab_newest_document.getNewestDocuments", $obj); unset($data); if($output->data && count($output->data)) { From 5f40fa5d8ef489315d427936bb6b79c9da6133b8 Mon Sep 17 00:00:00 2001 From: zero Date: Fri, 7 Dec 2007 04:50:30 +0000 Subject: [PATCH 145/265] =?UTF-8?q?=EA=B4=80=EB=A6=AC=EC=9E=90=20=EB=AA=A8?= =?UTF-8?q?=EB=93=9C=EC=97=90=EC=84=9C=20=EB=8C=93=EA=B8=80=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=EC=8B=9C=20=EB=8B=B5=EA=B8=80=EC=9D=B4=20=EC=9E=88?= =?UTF-8?q?=EC=96=B4=EC=84=9C=20=EC=A7=80=EC=9B=8C=EC=A7=80=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8A=94=20=EA=B2=83=EC=9D=80=20=EB=AC=B4=EC=8B=9C?= =?UTF-8?q?=ED=95=98=EA=B3=A0=20=EB=8B=A4=EC=9D=8C=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=A7=84=ED=96=89=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3169 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/comment/comment.admin.controller.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/comment/comment.admin.controller.php b/modules/comment/comment.admin.controller.php index a1b227f4f..e4da7faef 100644 --- a/modules/comment/comment.admin.controller.php +++ b/modules/comment/comment.admin.controller.php @@ -27,16 +27,20 @@ $oCommentController = &getController('comment'); + $deleted_count = 0; + // 글삭제 for($i=0;$i<$comment_count;$i++) { $comment_srl = trim($comment_srl_list[$i]); if(!$comment_srl) continue; $output = $oCommentController->deleteComment($comment_srl, true); - if(!$output->toBool()) return $output; + if(!$output->toBool()) continue; + + $deleted_count ++; } - $this->setMessage( sprintf(Context::getLang('msg_checked_comment_is_deleted'), $comment_count) ); + $this->setMessage( sprintf(Context::getLang('msg_checked_comment_is_deleted'), $deleted_count) ); } /** From ba7a5b5be7a1c509dba14195477da3b43998350c Mon Sep 17 00:00:00 2001 From: haneul Date: Fri, 7 Dec 2007 04:52:14 +0000 Subject: [PATCH 146/265] =?UTF-8?q?tag=20=ED=95=98=EB=82=98=EB=A7=8C=20?= =?UTF-8?q?=EC=9E=88=EC=9D=84=20=EB=95=8C=20=EC=83=9D=EA=B8=B0=EB=8A=94=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3170 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/tag/tag.model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/tag/tag.model.php b/modules/tag/tag.model.php index 581f209b5..606058384 100644 --- a/modules/tag/tag.model.php +++ b/modules/tag/tag.model.php @@ -29,7 +29,7 @@ else $args->module_srl = $obj->module_srl; $args->list_count = $obj->list_count; - $output = executeQuery('tag.getTagList', $args); + $output = executeQueryArray('tag.getTagList', $args); if(!$output->toBool()) return $output; return $output; From 5f0f4cebd25e4be9a7699835cacc18bf11383258 Mon Sep 17 00:00:00 2001 From: risapapa Date: Fri, 7 Dec 2007 05:05:00 +0000 Subject: [PATCH 147/265] Added Japanese Translation. git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3171 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/springnote/conf/info.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/springnote/conf/info.xml b/modules/springnote/conf/info.xml index 2a1df12a3..bcbe50cc4 100644 --- a/modules/springnote/conf/info.xml +++ b/modules/springnote/conf/info.xml @@ -1,13 +1,16 @@ 스프링노트 연동 + SpringNote連動 Springnote Спрингноут 제로 + Zero Zero Zero 스프링노트의 페이지를 제로보드XE에서 연동하여 출력하는 기능을 가지고 있는 모듈입니다. + SpringNoteのページをゼロボードXEと連動させて出力する機能を持っているモジュールです。 This modules links pages of Springnote with ZeroboardXE, and display them. Этот модуль связывает страницы Springnote с ZeroboardXE, и отображает их. From 9b240e58d3798740e3cf9dbacefdb01766d4ed6c Mon Sep 17 00:00:00 2001 From: zero Date: Fri, 7 Dec 2007 05:10:38 +0000 Subject: [PATCH 148/265] =?UTF-8?q?cozy=5Fboard=20=EC=8A=A4=ED=82=A8?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EB=8D=94=20=EC=9D=B4=EC=83=81=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=97=AE?= =?UTF-8?q?=EC=9D=B8=EA=B8=80=20=EB=B0=9C=EC=86=A1=20form=EC=9D=84=20?= =?UTF-8?q?=EA=B8=80=EC=93=B0=EA=B8=B0=EC=97=90=EC=84=9C=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3172 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/board/skins/cozy_board/write_form.html | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/modules/board/skins/cozy_board/write_form.html b/modules/board/skins/cozy_board/write_form.html index 8689e278d..3240fbce7 100644 --- a/modules/board/skins/cozy_board/write_form.html +++ b/modules/board/skins/cozy_board/write_form.html @@ -84,20 +84,6 @@
      {$editor}
      -
      - - - -
      -
      From 87ab83e91fa3ed146f4df97840b2a9b572e1ed9d Mon Sep 17 00:00:00 2001 From: haneul Date: Fri, 7 Dec 2007 05:12:34 +0000 Subject: [PATCH 149/265] =?UTF-8?q?uploader=EC=AA=BD=EC=97=90=20prototype?= =?UTF-8?q?=20dependancy=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3173 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/editor/skins/xquared/editor.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/editor/skins/xquared/editor.html b/modules/editor/skins/xquared/editor.html index 833d7d85a..ad0c4f2e8 100644 --- a/modules/editor/skins/xquared/editor.html +++ b/modules/editor/skins/xquared/editor.html @@ -64,7 +64,7 @@ var zbxe_session_name = "{session_name()}"; var uploader_setting = { "allowed_filesize" : "{$file_config->allowed_filesize}", "allowed_filetypes" : "{$file_config->allowed_filetypes}", "allowed_filetypes_description" : "{$file_config->allowed_filetypes}" } - editor_upload_init("{$editor_sequence}", editorGetForm_xq($("xqEditor_{$editor_sequence}"))); + editor_upload_init("{$editor_sequence}", editorGetForm_xq(document.getElementById("xqEditor_{$editor_sequence}"))); //]]> From ad1ae7aecb1a9ac8f96dbe8a504703a0dc14aee7 Mon Sep 17 00:00:00 2001 From: risapapa Date: Fri, 7 Dec 2007 05:18:28 +0000 Subject: [PATCH 150/265] Added Japanese Translation. git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3174 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/springnote/lang/jp.lang.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 modules/springnote/lang/jp.lang.php diff --git a/modules/springnote/lang/jp.lang.php b/modules/springnote/lang/jp.lang.php new file mode 100644 index 000000000..071a395df --- /dev/null +++ b/modules/springnote/lang/jp.lang.php @@ -0,0 +1,24 @@ +springnote = "SpringNote"; + $lang->springnote_openid = "オープンID"; + $lang->springnote_userkey = "ユーザーKey"; + $lang->springnote_pageid = "ページ番号"; + + $lang->page_url = "元のURL"; + $lang->page_modified = "最終修正"; + $lang->page_modifier = "最終修正者"; + + $lang->cmd_springnote_list = 'SpringNote リスト'; + $lang->cmd_view_info = 'SpringNote 情報'; + + $lang->about_springnote = "スプリングノートは、「openmaru.com」から提供されるウィキサービスです。
      スプリングノート連動モジュールは、スプリングノートの特定のページを自分のコンテンツの閲覧することができるようにするモジュールです。"; + $lang->about_springnote_openid = "スプリングノートでページを作成したオープンIDを入力してください。"; + $lang->about_springnote_userkey = 'スプリングノートとの連動するためのユーザKeyを入力してください。
      [ユーザーキー受信]をクリックして入力して生成されるキーの値を入力してください。'; + $lang->about_springnote_pageid = '使用するスプリングノートの中の特定ページを出力したい場合、「pageid」の値を入力してください。'; +?> From 95e82678b01ee4ea35fd2fcac2f67de33cbc6431 Mon Sep 17 00:00:00 2001 From: risapapa Date: Fri, 7 Dec 2007 05:23:07 +0000 Subject: [PATCH 151/265] Added Japanese Translation. git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3175 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/springnote/skins/xe_official/skin.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/springnote/skins/xe_official/skin.xml b/modules/springnote/skins/xe_official/skin.xml index d3cc5e916..b855310b0 100644 --- a/modules/springnote/skins/xe_official/skin.xml +++ b/modules/springnote/skins/xe_official/skin.xml @@ -1,11 +1,14 @@ 스프링 노트 연동 기본 스킨 + SpringNote連動のデフォルトスキン Springnote Module Basic Skin 제로 + Zero Zero 스프링 노트 연동 모듈의 기본 스킨 + SpringNote連動のデフォルトスキン Default Skin of Springnote Module @@ -47,7 +50,7 @@ 版面标题 Title of Board 게시판의 제목을 적어주세요. - 掲示板タイトルを入力してください。 + 掲示板のタイトルを入力してください。 请输入版面标题(留空为不显示)。 Please input the title of board. From 41f7f41f8a8ff0845c5e24466feb25fbaeb715b2 Mon Sep 17 00:00:00 2001 From: risapapa Date: Fri, 7 Dec 2007 05:29:19 +0000 Subject: [PATCH 152/265] Added Japanese Translation. git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3176 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/referer/conf/info.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/referer/conf/info.xml b/modules/referer/conf/info.xml index 91303a5c1..22e9e0900 100644 --- a/modules/referer/conf/info.xml +++ b/modules/referer/conf/info.xml @@ -1,13 +1,16 @@ 리퍼러 통계 + リファラー統計 Referer Statistics Статистика рефералов haneul + Haneul haneul haneul 기본 리퍼러 통계 프로그램입니다. + デフォルトのリファラー統計プログラムです。 Basic referer statistics program. Базовая программа статистики рефералов. From a1a490fad5e5391ecb590830e4dc31a3a7dda0c8 Mon Sep 17 00:00:00 2001 From: zero Date: Fri, 7 Dec 2007 05:30:42 +0000 Subject: [PATCH 153/265] =?UTF-8?q?=EC=B5=9C=EA=B7=BC=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EC=9C=84=EC=A0=AF=EC=97=90=EC=84=9C=201=EA=B0=9C?= =?UTF-8?q?=EB=A7=8C=20=EC=B6=94=EC=B6=9C=EC=8B=9C=20=EC=B6=94=EC=B6=9C?= =?UTF-8?q?=EB=90=98=EC=A7=80=20=EC=95=8A=EB=8D=98=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3177 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- widgets/newest_images/newest_images.class.php | 3 +-- widgets/newest_images/skins/default/css/normal.css | 7 +++---- widgets/newest_images/skins/default/list.html | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/widgets/newest_images/newest_images.class.php b/widgets/newest_images/newest_images.class.php index c85bd4623..45189f3ed 100644 --- a/widgets/newest_images/newest_images.class.php +++ b/widgets/newest_images/newest_images.class.php @@ -70,8 +70,7 @@ $obj->isvalid = 'Y'; // 정해진 모듈에서 문서별 파일 목록을 구함 - $files_output = executeQuery("file.getOneFileInDocument", $obj); - + $files_output = executeQueryArray("file.getOneFileInDocument", $obj); $oDocumentModel = &getModel('document'); if(count($files_output->data)) { diff --git a/widgets/newest_images/skins/default/css/normal.css b/widgets/newest_images/skins/default/css/normal.css index 61791d942..996f3fcd8 100644 --- a/widgets/newest_images/skins/default/css/normal.css +++ b/widgets/newest_images/skins/default/css/normal.css @@ -4,14 +4,13 @@ .ni_box .title_box .more A { float:right; color:#AAAAAA; text-decoration:none; font-weight:bold; font-size:.75em; } .ni_box .thumbnail_box { width:100%; table-layout:fixed; } -.ni_box .thumbnail_box .thumbnail { margin:3px; padding:3px; border:1px solid #EFEFEF; text-align:center; } -.ni_box .thumbnail_box .thumbnail:hover { border:1px solid #888888; } -.ni_box .thumbnail_box .thumbnail img { border:none; } -.ni_box .thumbnail_box .thumbnail img:hover { border:none; } +.ni_box .thumbnail_box img.thumbnail { margin:3px; padding:3px; border:1px solid #EFEFEF; text-align:center; } +.ni_box .thumbnail_box img.thumbnail:hover { border:1px solid #888888; } .ni_box .thumbnail_box a { color:#444444; text-decoration:none; } .ni_box .thumbnail_box a:visited { color:#AAAAAA; text-decoration:none; } +.ni_box .thumbnail_box td div { text-align:center; } .ni_box .thumbnail_box td.bottomBorder { border-bottom:1px dashed #EEEEEE; padding-bottom:5px; } .ni_box .thumbnail_box div strong { font-weight:bold; font-size:0.75em; color:#CCCCCC; } .ni_box .thumbnail_box div.author { color:#AAAAAA; } diff --git a/widgets/newest_images/skins/default/list.html b/widgets/newest_images/skins/default/list.html index b77abd40b..b665c5ce7 100644 --- a/widgets/newest_images/skins/default/list.html +++ b/widgets/newest_images/skins/default/list.html @@ -30,7 +30,7 @@ [{$oDocument->getCommentCount()}]
      -
      {$oDocument->getNickName()}
      +
      {$oDocument->getNickName()}
      From 649f68e6ad9ac245094c5053f078192eea88379a Mon Sep 17 00:00:00 2001 From: risapapa Date: Fri, 7 Dec 2007 05:33:10 +0000 Subject: [PATCH 154/265] Added New Japanese Translation File. git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3178 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/referer/lang/jp.lang.php | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 modules/referer/lang/jp.lang.php diff --git a/modules/referer/lang/jp.lang.php b/modules/referer/lang/jp.lang.php new file mode 100644 index 000000000..92db4a788 --- /dev/null +++ b/modules/referer/lang/jp.lang.php @@ -0,0 +1,10 @@ + + * @brief 日本語言語パッケージ 翻訳:RisaPapa + */ + + $lang->referer = "レファラー"; + $lang->ranking = "順位"; +?> From 5a991347429409debf4fd0fddfa7acd466669e88 Mon Sep 17 00:00:00 2001 From: zero Date: Fri, 7 Dec 2007 05:35:49 +0000 Subject: [PATCH 155/265] =?UTF-8?q?=ED=86=B5=ED=95=A9=EA=B2=80=EC=83=89?= =?UTF-8?q?=EB=AA=A8=EB=93=88=EC=97=90=EC=84=9C=20=EA=B8=80=20=EC=A0=9C?= =?UTF-8?q?=EB=AA=A9=EC=97=90=20tag=EA=B0=80=20=EC=9E=88=EC=9D=84=20?= =?UTF-8?q?=EA=B2=BD=EC=9A=B0=20html=EC=9D=B4=20=EA=B9=A8=EC=96=B4?= =?UTF-8?q?=EC=A7=80=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3179 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/integration_search/skins/default/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/integration_search/skins/default/index.html b/modules/integration_search/skins/default/index.html index 6e54af24a..9574d2f7b 100644 --- a/modules/integration_search/skins/default/index.html +++ b/modules/integration_search/skins/default/index.html @@ -41,7 +41,7 @@
      -
      {$document->getTitleText()} [{$document->getCommentCount()}] | {$mid_list[$document->get('module_srl')]->browser_title}
      +
      {$document->getTitle()} [{$document->getCommentCount()}] | {$mid_list[$document->get('module_srl')]->browser_title}
      {$document->getSummary(140)}
      From 33094a04fea8a9f878c65cea8bbc297ee41770b9 Mon Sep 17 00:00:00 2001 From: risapapa Date: Fri, 7 Dec 2007 05:36:31 +0000 Subject: [PATCH 156/265] Added Japanese Translation. git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3180 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/point/lang/jp.lang.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/point/lang/jp.lang.php b/modules/point/lang/jp.lang.php index 629135761..238e7b601 100644 --- a/modules/point/lang/jp.lang.php +++ b/modules/point/lang/jp.lang.php @@ -26,10 +26,10 @@ $lang->disable_download = 'ダウンロード禁止'; $lang->about_disable_download = 'チェックするとポイントがない場合、ダウンロードを禁止します(イメージファイル除外)。'; - $lang->level_point_calc = '레벨별 포인트 계산'; - $lang->expression = '레벨 변수 i를 사용하여 자바스크립트 수식을 입력하세요. 예: Math.pow(i, 2) * 90'; - $lang->cmd_exp_calc = '계산'; - $lang->cmd_exp_reset = '초기화'; + $lang->level_point_calc = 'レベル別ポイント計算'; + $lang->expression = 'レベル変数iを使用してJavaスクリプト数式を入力してください(例: Math.pow(i, 2) * 90'); + $lang->cmd_exp_calc = '計算'; + $lang->cmd_exp_reset = '初期化'; $lang->about_module_point = 'モジュール別にポイントを指定することができますが、指定されていないモジュールでは、デフォルトポイントが使用されます。すべてのポイント数は、反対のアクションを行った際には原状復帰されます。'; From 34ae49f61ed91d8c4e4e5a88f83ad3a0bea25289 Mon Sep 17 00:00:00 2001 From: risapapa Date: Fri, 7 Dec 2007 05:46:32 +0000 Subject: [PATCH 157/265] Added Japanese Translation. git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3181 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/board/skins/xe_board/skin.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/board/skins/xe_board/skin.xml b/modules/board/skins/xe_board/skin.xml index fd7507ecb..bae69efba 100644 --- a/modules/board/skins/xe_board/skin.xml +++ b/modules/board/skins/xe_board/skin.xml @@ -65,6 +65,7 @@ 기본 형태 + デフォルトスタイル 默认样式 Default Form @@ -102,13 +103,13 @@ 정렬 방법 - 排序方式 ソート方法 + 排序方式 Sorting Type Tipo de ordenamiento 정렬대상을 내림차순 또는 올림차순으로 정렬할 수 있습니다. - 对其排序对象可进行升序/降序方式排序。 ソート方法を、降順、昇順にできます。 + 对其排序对象可进行升序/降序方式排序。 You can sort target articles by asending or desending order. Usted puede ordenar los documentos en orden acendente o en orden descendente. asc From 65962979f9f1e718f08ac9a661e9a68837f63917 Mon Sep 17 00:00:00 2001 From: risapapa Date: Fri, 7 Dec 2007 05:53:41 +0000 Subject: [PATCH 158/265] Added Japanese Translation. git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3182 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- widgets/DroArc_clock/skins/default/skin.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/widgets/DroArc_clock/skins/default/skin.xml b/widgets/DroArc_clock/skins/default/skin.xml index 32698e7b2..ff18e83b0 100644 --- a/widgets/DroArc_clock/skins/default/skin.xml +++ b/widgets/DroArc_clock/skins/default/skin.xml @@ -2,20 +2,23 @@ 플래시 디지털 시계 Flash数字时钟 + フラッシュデジタル時計 Flash Digital Clock 드로아크 DroArc + DroArc DroArc 플래시 디지털 시계를 출력합니다. 자체적인 오른쪽 마우스 메뉴를 사용가능합니다. 显示Flash数字时钟。 + フラッシュのデジタル時計を出力します。右クリックマウスのメニューが使用できます。 It displays flash digital clock. 일반 普通 - いっぱん + ノーマル Normal From df1abec77206c8c0c9f66ca29cf7ed5a1d158214 Mon Sep 17 00:00:00 2001 From: risapapa Date: Fri, 7 Dec 2007 06:17:43 +0000 Subject: [PATCH 159/265] Added Japanese Translation. git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3183 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- widgets/rank_count/conf/info.xml | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/widgets/rank_count/conf/info.xml b/widgets/rank_count/conf/info.xml index c1a2db1d5..e39b1c585 100644 --- a/widgets/rank_count/conf/info.xml +++ b/widgets/rank_count/conf/info.xml @@ -1,99 +1,122 @@ 글, 댓글 랭킹 출력 + 書き込み、コメント出力 Article, Comment Ranking 输出主题, 评论排行 Simulz + Simulz Simulz Simulz 글, 댓글 작성 순위를 출력합니다. - This widget displays articles and comments ranking. + 書き込み、コメントの作成順位を出力します。 输出主题, 内容排行. 제목 + タイトル 主题 text 위젯의 제목으로 출력됩니다. + ウィジェットのタイトルとして出力されます。 输出控件的主题. 목록수 + リスト数 目录数 text 출력될 목록의 수를 정하실 수 있습니다. (기본 5개) + 出力されるリスト数が設定できます(デフォルト5個)。 可以指定要输出的目录数. (默认 5个) 순위 대상 + 順位対象 排行对象 select 대상을 선택하세요. + 対象を選択してください。 请选择对象. 글 작성 + 書き込み作成 发表新帖 document 댓글 작성 + コメント作成 发表评论 comment 파일 첨부 + ファイル添付 上传附件 attach 추천 수 + 推薦数 推荐数 vote 조회 수 + 照合数 阅读数 read 관리자 + 管理者 管理员 select 순위에 관리자를 포함합니다. + 順位に管理者を含みます。 在排行包括管理员. 포함 + 含む 包括 false 미포함 + 含まない 不包括 true 그룹 포함 + グループを含む 包括组 text 출력할 회원 그룹명을 입력하세요. 예)준회원,정회원 + 出力する会員のグループ名を入力してください(例:準会員、正会員)。 请输入要显示的会员组. 例)准会员,正会员 그룹 제외 + グループ除外 组除外 text 제외할 회원 그룹명을 입력하세요. 예)관리그룹 + 除外する会員グループ名を入力してください(例:管理グループ)。 请输入将除外的会员组. 例)管理组 기간(일) + 期間(日) 期间(日期) text 설정 기간 내의 순위를 출력합니다. + 設定期間内の順位を出力します。 输出设置期间内的排行. From 76eb8ab367346058e7a309bb84ffc46d81f0e56a Mon Sep 17 00:00:00 2001 From: risapapa Date: Fri, 7 Dec 2007 06:30:27 +0000 Subject: [PATCH 160/265] Added Japanese Translation. git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3184 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- widgets/rank_count/skins/sz_xe/skin.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/widgets/rank_count/skins/sz_xe/skin.xml b/widgets/rank_count/skins/sz_xe/skin.xml index 93f4a5947..71ad3618f 100644 --- a/widgets/rank_count/skins/sz_xe/skin.xml +++ b/widgets/rank_count/skins/sz_xe/skin.xml @@ -1,14 +1,19 @@ Simulz 랭킹 스킨 + Simulzランキングスキン Simulz 排行皮肤 Simulz Ranking Skin Simulz + Simulz Simulz Simulz Simulz 랭킹 스킨입니다. + + + Simulzランキングスキンです。 Simulz 排行皮肤. @@ -20,51 +25,61 @@ 기본 + デフォルト 默认 Default 회색 + 灰色 Gray 연두 + 薄緑 淡绿 Yellowish Green 분홍 + 粉红 Pink 보라 + 淡青 Purple 밝은 파랑 + 浅蓝 Bright Blue 청록 + 青緑 青绿 Bluish Green 초록 + 草绿 Green 노랑 + 黄色 Yellow 파랑 + 蓝色 Blue From 43f2a35467875e3b21eb6374ec4984ebde11515f Mon Sep 17 00:00:00 2001 From: zero Date: Fri, 7 Dec 2007 06:35:36 +0000 Subject: [PATCH 161/265] =?UTF-8?q?#304=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=EC=8B=9C=20=EB=B2=84=ED=8A=BC=EB=93=A4?= =?UTF-8?q?=EC=9D=98=20=EC=9C=84=EC=B9=98=EB=A5=BC=20table=EC=9D=B4=20?= =?UTF-8?q?=EC=95=84=EB=8B=8C=20div=EB=A1=9C=20=EA=BE=B8=EB=A9=B0=EC=84=9C?= =?UTF-8?q?=20=EC=88=A8=EC=A7=80=20=EC=95=8A=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3185 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/page/tpl/page_content_modify.html | 40 +++++++++-------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/modules/page/tpl/page_content_modify.html b/modules/page/tpl/page_content_modify.html index fcf9c840c..733a2ce50 100644 --- a/modules/page/tpl/page_content_modify.html +++ b/modules/page/tpl/page_content_modify.html @@ -9,31 +9,21 @@ - - - - - - - - - -
      - - - - - - -
      - - - -
      +
      + + + + +
      +
      + + + +
      From cb60a769f20e62a0aa372477a433ae050112ec03 Mon Sep 17 00:00:00 2001 From: zero Date: Fri, 7 Dec 2007 06:41:49 +0000 Subject: [PATCH 162/265] =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EA=B8=80/=EB=8C=93?= =?UTF-8?q?=EA=B8=80=EC=97=90=EC=84=9C=20=EC=9D=B4=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=EB=AC=BC=EC=9D=84../=20=EC=9D=B4=20=EB=8C=93=EA=B8=80=EC=9D=84?= =?UTF-8?q?..=20=EC=9D=84=20=EC=A1=B0=EC=A0=88=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EC=9D=B8=EC=9E=90=EA=B0=92=EC=9D=98=20=EC=B6=9C=EB=A0=A5?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC=EB=A5=BC=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3186 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- modules/comment/comment.item.php | 33 +++++++++++++++++++++--------- modules/document/document.item.php | 33 +++++++++++++++++++++--------- 2 files changed, 46 insertions(+), 20 deletions(-) diff --git a/modules/comment/comment.item.php b/modules/comment/comment.item.php index ae837869b..49b3da73a 100644 --- a/modules/comment/comment.item.php +++ b/modules/comment/comment.item.php @@ -164,17 +164,30 @@ // url에 대해서 정규표현식으로 치환 $content = preg_replace('!([^>^"^\'^=])(http|https|ftp|mms):\/\/([^ ^<^"^\']*)!is','$1$2://$3',' '.$content); - if(!$add_comment_info) return $content; - $content = sprintf( - '
      %s
      %s
      ', - $this->comment_srl, $this->get('member_srl'), - $this->comment_srl, $this->get('member_srl'), - $content, - $this->comment_srl, Context::getLang('cmd_comment_do'), - $this->comment_srl, $this->get('member_srl'), - $this->comment_srl, $this->get('member_srl') - ); + // 추가 정보 출력을 하지 않는 경우 + if(!$add_comment_info) { + $content = sprintf( + '
      %s
      ', + $this->comment_srl, $this->get('member_srl'), + $this->comment_srl, $this->get('member_srl'), + $content, + $this->comment_srl, $this->get('member_srl'), + $this->comment_srl, $this->get('member_srl') + ); + // 추가 정보 출력을 하지 않는 경우 "이 댓글을.." 메뉴 추가 + } else { + $content = sprintf( + '
      %s
      %s
      ', + $this->comment_srl, $this->get('member_srl'), + $this->comment_srl, $this->get('member_srl'), + $content, + $this->comment_srl, Context::getLang('cmd_comment_do'), + $this->comment_srl, $this->get('member_srl'), + $this->comment_srl, $this->get('member_srl') + ); + } + return $content; } diff --git a/modules/document/document.item.php b/modules/document/document.item.php index afc16caed..8eb1880a9 100644 --- a/modules/document/document.item.php +++ b/modules/document/document.item.php @@ -209,22 +209,35 @@ $content = $this->get('content'); + // OL/LI 태그를 위한 치환 처리 $content = preg_replace('!<(ol|ul|blockquote)>!is','<\\1 style="margin-left:40px;">',$content); // url에 대해서 정규표현식으로 치환 $content = preg_replace('!([^>^"^\'^=])(http|https|ftp|mms):\/\/([^ ^<^"^\']*)!is','$1$2://$3',' '.$content); - if(!$add_document_info) return $content; - $content = sprintf( - '
      %s
      %s
      ', - $this->document_srl, $this->get('member_srl'), - $this->document_srl, $this->get('member_srl'), - $content, - $this->document_srl, Context::getLang('cmd_document_do'), - $this->document_srl, $this->get('member_srl'), - $this->document_srl, $this->get('member_srl') - ); + // 추가 정보 출력을 하지 않는 경우 + if(!$add_document_info) { + $content = sprintf( + '
      %s
      ', + $this->document_srl, $this->get('member_srl'), + $this->document_srl, $this->get('member_srl'), + $content, + $this->document_srl, $this->get('member_srl'), + $this->document_srl, $this->get('member_srl') + ); + // 추가 정보를 출력시 "이 게시물을..'이라는 메뉴 추가 + } else { + $content = sprintf( + '
      %s
      %s
      ', + $this->document_srl, $this->get('member_srl'), + $this->document_srl, $this->get('member_srl'), + $content, + $this->document_srl, Context::getLang('cmd_document_do'), + $this->document_srl, $this->get('member_srl'), + $this->document_srl, $this->get('member_srl') + ); + } return $content; } From 4d257fc37a9551cdf11b5f563691be433d82c8f6 Mon Sep 17 00:00:00 2001 From: zero Date: Fri, 7 Dec 2007 06:44:50 +0000 Subject: [PATCH 163/265] #305 git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3187 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- config/func.inc.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/func.inc.php b/config/func.inc.php index decb45b49..7e9e6c76e 100644 --- a/config/func.inc.php +++ b/config/func.inc.php @@ -408,6 +408,9 @@ // script code 제거 $content = preg_replace("!!is","",$content); + // meta 태그 제거 + $content = preg_replace("!!is","",$content); + return $content; } From f9ff0bbfcdefd120fb09642ec6f1b475acab74e5 Mon Sep 17 00:00:00 2001 From: risapapa Date: Fri, 7 Dec 2007 06:45:11 +0000 Subject: [PATCH 164/265] Added Japanese Translation. git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3188 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- widgets/rank_download/conf/info.xml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/widgets/rank_download/conf/info.xml b/widgets/rank_download/conf/info.xml index 5b28a3034..e12f31c75 100644 --- a/widgets/rank_download/conf/info.xml +++ b/widgets/rank_download/conf/info.xml @@ -1,57 +1,69 @@ 다운로드 랭킹 출력 + ダウンロードランキング出力 Download Ranking 输出下载排行 Simulz + Simulz Simulz Simulz 자료 내려받기 순위를 출력합니다. + ダウンロードの順位を出力します。 This widget displays download ranking. 输出下载文件顺位. 제목 + 제목 Title 主题 text 위젯의 제목으로 출력됩니다. + ウィジェットの題名として出力されます。 It will be displayed as widget's title. 输出控件的主题. 목록수 + リスト数 No. of List 目录数 text 출력될 목록의 수를 정하실 수 있습니다. (기본 5개) + 出力するリストの数を指定します(デフォルト5個)。 You may set number of list that will be displayed. (default 5) 可以指定将输出的目录数.(默认 5个) 파일 종류 + ファイルの種類 File Type 文件类型 select 순위에 포함할 파일 종류를 선택하세요. + 順位に含むファイルの種類を選択してください。 Please select file type to include. 请选择输出目录中要包涵的文件类型. 모두 + すべて All 全部 all 이미지 제외 + イメージ除外 Exclude Images 图片除外 noimage 이미지만 + イメージのみ Images Only 只输出图片类 image @@ -59,20 +71,24 @@ 내려 받기 + ダウンロード Download 显示下载链接 select 바로 내려 받는 링크를 보여줍니다. + 直接ダウンロードするリンクを表示します。 It shows direct download link. 显示直接下载链接 링크 보임 + リンク表示 Show Link 显示连接 Y 링크 숨김 + リンク非表示 Hide Link 隐藏链接 N @@ -80,10 +96,12 @@ 대상 모듈 + 対象モジュール Target Module 对象模块 mid_list 선택하신 모듈에 등록된 글을 대상으로 합니다. + 選択モジュールに登録された書き込みを対象とします。 Articles in selected module will be target. 被选中的模块将输出. From 784f2ff68c5e62895d48ee00851211f9f72d0303 Mon Sep 17 00:00:00 2001 From: risapapa Date: Fri, 7 Dec 2007 06:52:25 +0000 Subject: [PATCH 165/265] Added Japanese Translation. git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3189 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- widgets/rank_download/skins/sz_xe/skin.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/widgets/rank_download/skins/sz_xe/skin.xml b/widgets/rank_download/skins/sz_xe/skin.xml index 9423c0bb4..4f38ab630 100644 --- a/widgets/rank_download/skins/sz_xe/skin.xml +++ b/widgets/rank_download/skins/sz_xe/skin.xml @@ -1,14 +1,19 @@ Simulz 랭킹 스킨 + Simulzランキングスキン Simulz Ranking Skin Simulz 排行皮肤 Simulz + Simulz Simulz Simulz Simulz 랭킹 스킨입니다. + + + Simulzランキングスキンです。 This is Simulz Ranking Skin. @@ -20,51 +25,61 @@ 기본 + デフォルト Default 默认 회색 + Gray 灰色 연두 + 薄緑 Yellowish Green 淡绿 분홍 + Pink 粉红 보라 + Purple 淡青 밝은 파랑 + Bright Blue 浅蓝 청록 + 青緑 Bluish Green 青绿 초록 + Green 草绿 노랑 + Yellow 黄色 파랑 + Blue 蓝色 From 85a304e42e06f1fee36f53455fa335ce3f4db292 Mon Sep 17 00:00:00 2001 From: risapapa Date: Fri, 7 Dec 2007 07:01:09 +0000 Subject: [PATCH 166/265] Added Japanese Translation. git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3190 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- widgets/rank_point/conf/info.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/widgets/rank_point/conf/info.xml b/widgets/rank_point/conf/info.xml index a3fe5397d..32e8e25bb 100644 --- a/widgets/rank_point/conf/info.xml +++ b/widgets/rank_point/conf/info.xml @@ -1,51 +1,62 @@ 포인트 랭킹 출력 + ポイントランキング出力 Display Point Ranking 输出积分排行 Simulz + Simulz Simulz Simulz 회원의 포인트 순위를 출력합니다. + 会員ポイントの順位を出力します。 This widget displays members' point ranking. 输出会员积分排行. 제목 + タイトル Title 主题 text 위젯의 제목으로 출력됩니다. + ウィジェットのタイトルとして出力されます。 It will be displayed as widget's title. 输出控件的主题. 목록수 + リスト数 No. of List 目录数 text 출력될 목록의 수를 정하실 수 있습니다. (기본 5개) + 出力されるリスト数が設定できます(デフォルト5個)。 You may set number of list that will be displayed. (default 5) 可以指定要输出的目录数. (默认 5个) 관리자 + 管理者 Administrator 管理员 select 순위에 관리자를 포함합니다. + 順位に管理者を含みます。 Administrators will be also ranked. 在排行显示管理员. 포함 + 含む Include 显示 false 미포함 + 含まない Exclude 不显示 true @@ -53,19 +64,23 @@ 그룹 포함 + グループを含む Include Group 包括组 text 출력할 회원 그룹명을 입력하세요. 예)준회원,정회원 + 出力する会員のグループ名を入力してください(例:準会員、正会員)。 Please input name of group to include. ex) Associate, Regular Group 请输入要输出的会员组. 例)准会员,正会员 그룹 제외 + グループ除外 Exclude Group 组除外 text 제외할 회원 그룹명을 입력하세요. 예)관리그룹,정회원 + 除外する会員グループ名を入力してください(例:管理グループ、正会員)。 Please input name of group to exclude. ex) Managing, Regular Group 请输入要不包括的用户组. 例)管理组,正会员 From 7728d75d1fc1dff5e0758799a4ff1641e8514781 Mon Sep 17 00:00:00 2001 From: risapapa Date: Fri, 7 Dec 2007 07:05:18 +0000 Subject: [PATCH 167/265] Added Japanese Translation. git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3191 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- widgets/rank_point/skins/sz_xe/skin.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/widgets/rank_point/skins/sz_xe/skin.xml b/widgets/rank_point/skins/sz_xe/skin.xml index 656290a40..a45b66fb3 100644 --- a/widgets/rank_point/skins/sz_xe/skin.xml +++ b/widgets/rank_point/skins/sz_xe/skin.xml @@ -1,14 +1,19 @@ Simulz 포인트 랭킹 스킨 + Simulz ポイントランキングスキン Simulz Point Ranking Skin Simulz 积分排行皮肤 Simulz + Simulz Simulz Simulz Simulz 포인트 랭킹 스킨입니다. + + + Simulz ポイントランキングスキンです。 This is Simulz Point Ranking Skin. @@ -21,51 +26,61 @@ 기본 + デフォルト Default 默认 회색 + Gray 灰色 연두 + 薄緑 Yellowish Green 淡绿 분홍 + Pink 粉红 보라 + Purple 淡青 밝은 파랑 + Bright Blue 浅蓝 청록 + 青緑 Bluish Green 青绿 초록 + Green 草绿 노랑 + Yellow 黄色 파랑 + Blue 蓝色 From 5cb4cf3d23778299ec021f535416e5954bbc3a48 Mon Sep 17 00:00:00 2001 From: zero Date: Fri, 7 Dec 2007 07:05:41 +0000 Subject: [PATCH 168/265] =?UTF-8?q?=EC=8B=A0=EA=B3=A0=EB=90=9C=20=EA=B2=8C?= =?UTF-8?q?=EC=8B=9C=EA=B8=80/=EB=8C=93=EA=B8=80=EC=9D=84=20=EC=8B=A0?= =?UTF-8?q?=EA=B3=A0=20=EC=B7=A8=EC=86=8C=20=EC=8B=9C=ED=82=A4=EB=8A=94=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=EC=9E=90=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@3192 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- common/lang/en.lang.php | 1 + common/lang/es.lang.php | 1 + common/lang/fr.lang.php | 1 + common/lang/jp.lang.php | 1 + common/lang/ko.lang.php | 1 + common/lang/ru.lang.php | 1 + common/lang/zh-CN.lang.php | 1 + modules/comment/comment.admin.controller.php | 13 ++++++++++++ modules/comment/conf/module.xml | 2 +- modules/comment/tpl/declared_list.html | 4 ++++ modules/comment/tpl/js/comment_admin.js | 20 ++++++++++++++++++- modules/document/conf/module.xml | 1 + .../document/document.admin.controller.php | 13 ++++++++++++ modules/document/tpl/declared_list.html | 4 ++++ modules/document/tpl/js/document_admin.js | 18 +++++++++++++++++ 15 files changed, 80 insertions(+), 2 deletions(-) diff --git a/common/lang/en.lang.php b/common/lang/en.lang.php index 94744b6dd..d323b39f6 100644 --- a/common/lang/en.lang.php +++ b/common/lang/en.lang.php @@ -29,6 +29,7 @@ $lang->cmd_vote = 'Recommend'; $lang->cmd_vote_down = 'Criticize'; $lang->cmd_declare = 'Accuse'; + $lang->cmd_cancel_declare = 'Cancel Accuse'; $lang->cmd_declared_list = 'Accusations List'; $lang->cmd_copy = 'Copy'; $lang->cmd_move = 'Move'; diff --git a/common/lang/es.lang.php b/common/lang/es.lang.php index da9ec15fc..dc36eb62f 100644 --- a/common/lang/es.lang.php +++ b/common/lang/es.lang.php @@ -29,6 +29,7 @@ $lang->cmd_vote = 'Recomendar'; $lang->cmd_vote_down = '비추천'; $lang->cmd_declare = '신고'; + $lang->cmd_cancel_declare = '신고 취소'; $lang->cmd_declared_list = '신고 목록'; $lang->cmd_copy = 'Copia'; $lang->cmd_move = 'Mover'; diff --git a/common/lang/fr.lang.php b/common/lang/fr.lang.php index 2d6eed408..19fe1aa61 100644 --- a/common/lang/fr.lang.php +++ b/common/lang/fr.lang.php @@ -29,6 +29,7 @@ $lang->cmd_vote = 'Voter'; $lang->cmd_vote_down = '비추천'; $lang->cmd_declare = '신고'; + $lang->cmd_cancel_declare = '신고 취소'; $lang->cmd_declared_list = '신고 목록'; $lang->cmd_copy = 'Copie'; $lang->cmd_move = 'Deplacer'; diff --git a/common/lang/jp.lang.php b/common/lang/jp.lang.php index c07351db4..b2033307d 100644 --- a/common/lang/jp.lang.php +++ b/common/lang/jp.lang.php @@ -29,6 +29,7 @@ $lang->cmd_vote = '推薦'; $lang->cmd_vote_down = '非推薦'; $lang->cmd_declare = '通報'; + $lang->cmd_cancel_declare = '通報キャンセル'; $lang->cmd_declared_list = '通報リスト'; $lang->cmd_copy = 'コピー'; $lang->cmd_move = '移動'; diff --git a/common/lang/ko.lang.php b/common/lang/ko.lang.php index 3d603aa46..011c37ca8 100644 --- a/common/lang/ko.lang.php +++ b/common/lang/ko.lang.php @@ -29,6 +29,7 @@ $lang->cmd_vote = '추천'; $lang->cmd_vote_down = '비추천'; $lang->cmd_declare = '신고'; + $lang->cmd_cancel_declare = '신고 취소'; $lang->cmd_declared_list = '신고 목록'; $lang->cmd_copy = '복사'; $lang->cmd_move = '이동'; diff --git a/common/lang/ru.lang.php b/common/lang/ru.lang.php index 9d8819c3a..817668f0e 100644 --- a/common/lang/ru.lang.php +++ b/common/lang/ru.lang.php @@ -29,6 +29,7 @@ $lang->cmd_vote = 'Рекомендовать'; $lang->cmd_vote_down = 'Критиковать'; $lang->cmd_declare = 'Обвинить'; + $lang->cmd_cancel_declare = 'Отменить Обвинить'; $lang->cmd_declared_list = 'Список обвинений'; $lang->cmd_copy = 'Копировать'; $lang->cmd_move = 'Переместить'; diff --git a/common/lang/zh-CN.lang.php b/common/lang/zh-CN.lang.php index d4daff5b5..cf50dddac 100644 --- a/common/lang/zh-CN.lang.php +++ b/common/lang/zh-CN.lang.php @@ -29,6 +29,7 @@ $lang->cmd_vote = '推荐'; $lang->cmd_vote_down = '反对'; $lang->cmd_declare = '举报'; + $lang->cmd_cancel_declare = '举报取消'; $lang->cmd_declared_list = '举报目录'; $lang->cmd_copy = '复制'; $lang->cmd_move = '查看'; diff --git a/modules/comment/comment.admin.controller.php b/modules/comment/comment.admin.controller.php index e4da7faef..ad93f1868 100644 --- a/modules/comment/comment.admin.controller.php +++ b/modules/comment/comment.admin.controller.php @@ -43,6 +43,19 @@ $this->setMessage( sprintf(Context::getLang('msg_checked_comment_is_deleted'), $deleted_count) ); } + /** + * @brief 신고대상을 취소 시킴 + **/ + function procCommentAdminCancelDeclare() { + $comment_srl = trim(Context::get('comment_srl')); + + if($comment_srl) { + $args->comment_srl = $comment_srl; + $output = executeQuery('comment.deleteDeclaredComments', $args); + if(!$output->toBool()) return $output; + } + } + /** * @brief 특정 모듈의 모든 댓글 삭제 **/ diff --git a/modules/comment/conf/module.xml b/modules/comment/conf/module.xml index 5713edfa6..03fa6b95c 100644 --- a/modules/comment/conf/module.xml +++ b/modules/comment/conf/module.xml @@ -9,6 +9,6 @@ - + diff --git a/modules/comment/tpl/declared_list.html b/modules/comment/tpl/declared_list.html index 29058b6fe..14fb32c20 100644 --- a/modules/comment/tpl/declared_list.html +++ b/modules/comment/tpl/declared_list.html @@ -45,6 +45,9 @@
      +
      {$lang->cmd_select_all} {$lang->cmd_reverse_all} @@ -53,6 +56,7 @@ +
      + @@ -67,6 +70,7 @@ +